ios fixes
authorcaryclark <caryclark@google.com>
Fri, 11 Jul 2014 19:14:51 +0000 (12:14 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 11 Jul 2014 19:14:51 +0000 (12:14 -0700)
skia_ios.mm
Get the app's Documents directory and pass use it to set the resource path.
This is a quick hack which will be replaced by a new application that is
a tiny shim around a command line tool.

SkImageEncoder.h
SkForceLinking.cpp
SkImageDecoder_CG.cpp
Add support for FORCE_LINKING so iOS sees the PNG encoder and others.

SkFloatBits.cpp
SkPoint.cpp
Handle denormalized numbers that are floored by the iOS ARM processor.

SkImageDecoder_iOS.mm
Remove empty encoder factory.

SkTouchGesture.cpp
Return early on empty state on touch rather than aborting (crashing)

JpegTest.cpp
Hal via stackoverflow.com says partial jpegs can be gray as well.

skia_test.cpp
Remove crash handler call for now to avoid link failure.

OverwriteLine.h
Remove fancy line overwrite for iOS.

Resources.cpp
Add interface to set resource directory based on runtime query.

BUG=skia:2736 skia:2737 skia:2738
R=reed@google.com, halcanary@google.com, mtklein@google.com, tfarina@chromium.org

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/373383003

19 files changed:
experimental/iOSSampleApp/Shared/skia_ios.mm
experimental/iOSShell/iOSShell-Info.plist [new file with mode: 0644]
gyp/iOSShell.gyp [new file with mode: 0644]
gyp/most.gyp
include/core/SkImageEncoder.h
src/core/SkFloatBits.cpp
src/core/SkMathPriv.h
src/core/SkPoint.cpp
src/images/SkForceLinking.cpp
src/ports/SkImageDecoder_CG.cpp
src/utils/ios/SkImageDecoder_iOS.mm
src/views/SkTouchGesture.cpp
tests/JpegTest.cpp
tools/OverwriteLine.h
tools/Resources.cpp
tools/Resources.h
tools/flags/SkCommandLineFlags.h
tools/iOSShell.cpp [new file with mode: 0644]
tools/iOSShell.h [new file with mode: 0644]

index 65b3e8a034cc1c1ca9c97622091811bf3096eeb5..4fce1392d81fc692044b9dfadb4cb61ad6de83dd 100644 (file)
@@ -1,14 +1,19 @@
 #import <UIKit/UIKit.h>
 #include "SkApplication.h"
 
-extern void save_args(int argc, char *argv[]);
+extern bool set_cmd_line_args(int argc, char *argv[], const char* dir);
 
 int main(int argc, char *argv[]) {
     signal(SIGPIPE, SIG_IGN);
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     application_init();
-    save_args(argc, argv);
-    int retVal = UIApplicationMain(argc, argv, nil, nil);
+    // Identify the documents directory
+    NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+    NSString *docsDir = [dirPaths objectAtIndex:0];
+    const char *d = [docsDir UTF8String];
+
+    bool ranCommand = set_cmd_line_args(argc, argv, d);
+    int retVal = ranCommand ? 0 : UIApplicationMain(argc, argv, nil, nil);
     application_term();
     [pool release];
     return retVal;
diff --git a/experimental/iOSShell/iOSShell-Info.plist b/experimental/iOSShell/iOSShell-Info.plist
new file mode 100644 (file)
index 0000000..69b62ef
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleDisplayName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>com.google.iOSShell</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>NSMainNibFile</key>
+       <string>MainWindow_iPhone</string>
+       <key>NSMainNibFile~ipad</key>
+       <string>MainWindow_iPad</string>
+       <key>UISupportedInterfaceOrientations</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+       </array>
+       <key>UISupportedInterfaceOrientations~ipad</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationPortraitUpsideDown</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+</dict>
+</plist>
diff --git a/gyp/iOSShell.gyp b/gyp/iOSShell.gyp
new file mode 100644 (file)
index 0000000..ed648a3
--- /dev/null
@@ -0,0 +1,85 @@
+#
+{
+  'conditions' : [
+    [ 'skia_os == "ios"', {
+      'targets': [
+        {
+          'target_name': 'iOSShell',
+          'type': 'executable',
+          'mac_bundle' : 1,
+          'includes': [
+            'tests.gypi',
+               'pathops_unittest.gypi',
+          ],
+          'dependencies': [
+            'tools.gyp:crash_handler',
+            'views.gyp:views',
+            'xml.gyp:xml',
+          ],
+          'sources': [
+            '../tests/skia_test.cpp',
+            '../tools/iOSShell.cpp',
+            '../src/views/mac/SkEventNotifier.mm',
+            '../experimental/iOSSampleApp/SkiOSSampleApp-Base.xcconfig',
+            '../experimental/iOSSampleApp/SkiOSSampleApp-Debug.xcconfig',
+            '../experimental/iOSSampleApp/SkiOSSampleApp-Release.xcconfig',
+            '../experimental/iOSShell/iOSShell-Info.plist',
+            '../experimental/iOSSampleApp/Shared/SkUIRootViewController.mm',
+            '../experimental/iOSSampleApp/Shared/SkUIView.mm',
+            '../experimental/iOSSampleApp/Shared/skia_ios.mm',
+
+            # iPad
+            '../experimental/iOSSampleApp/iPad/AppDelegate_iPad.mm',
+            '../experimental/iOSSampleApp/iPad/SkUISplitViewController.mm',
+            '../experimental/iOSSampleApp/iPad/MainWindow_iPad.xib',
+
+            # iPhone
+            '../experimental/iOSSampleApp/iPhone/AppDelegate_iPhone.mm',
+            '../experimental/iOSSampleApp/iPhone/SkUINavigationController.mm',
+            '../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
+
+            '../src/views/ios/SkOSWindow_iOS.mm',
+            '../src/utils/ios/SkStream_NSData.mm',
+            '../src/utils/mac/SkCreateCGImageRef.cpp',
+          ],
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreText.framework',
+              '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/QuartzCore.framework',
+              '$(SDKROOT)/System/Library/Frameworks/OpenGLES.framework',
+              '$(SDKROOT)/System/Library/Frameworks/ImageIO.framework',
+              '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
+            ],
+          },
+          'include_dirs' : [
+            '../experimental/iOSSampleApp',
+            '../experimental/iOSSampleApp/iPad',
+            '../experimental/iOSSampleApp/iPhone',
+            '../experimental/iOSSampleApp/Shared',
+            '../include/utils/ios',
+            '../src/views/mac',
+          ],
+          'xcode_settings' : {
+            'INFOPLIST_FILE' : '../experimental/iOSShell/iOSShell-Info.plist',
+          },
+          'xcode_config_file': '../experimental/iOSSampleApp/SkiOSSampleApp-Base.xcconfig',
+          'mac_bundle_resources' : [
+            '../experimental/iOSSampleApp/iPad/MainWindow_iPad.xib',
+            '../experimental/iOSSampleApp/iPhone/MainWindow_iPhone.xib',
+          ],
+          'conditions' : [
+            [ 'skia_gpu == 1', {
+              'dependencies': [
+                'gputest.gyp:skgputest',
+              ],
+            }],
+          ],
+        },
+      ],
+    }],
+  ]
+}
index ba189316e9857d72eb366b49df53a9462a75e22a..4675add4ddeae47c78b12515d4622231da9fb6ad 100644 (file)
@@ -30,6 +30,7 @@
         }],
         ['skia_os == "ios"', {
           'dependencies!': [ 'SampleApp.gyp:SampleApp' ],
+          'dependencies': ['iOSShell.gyp:iOSShell' ],
         }],
         ['skia_os == "mac" or skia_os == "linux"', {
           'dependencies': [ 'nanomsg.gyp:*' ],
index 754d5bbbc3ad989c34fff0ceb3fcb8a650376e17..4d4d2a83c0f18a0bd31a8d42bd64d947703a8126 100644 (file)
@@ -100,6 +100,10 @@ DECLARE_ENCODER_CREATOR(PNGImageEncoder);
 DECLARE_ENCODER_CREATOR(KTXImageEncoder);
 DECLARE_ENCODER_CREATOR(WEBPImageEncoder);
 
+#ifdef SK_BUILD_FOR_IOS
+DECLARE_ENCODER_CREATOR(PNGImageEncoder_IOS);
+#endif
+
 // Typedef to make registering encoder callback easier
 // This has to be defined outside SkImageEncoder. :(
 typedef SkTRegistry<SkImageEncoder*(*)(SkImageEncoder::Type)> SkImageEncoder_EncodeReg;
index 39b51abf1dc8a9939c41e69463ee50a37b9b1956..6b35a75c88f72a30652c883eb598fda7cfb30a0c 100644 (file)
@@ -85,7 +85,16 @@ int32_t SkFloatBits_toIntFloor(int32_t packed) {
         value = SkApplySign(value, SkExtractSign(packed));
         exp = -exp;
         if (exp > 25) {   // underflow
+#ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED
+        // The iOS ARM processor discards small denormalized numbers to go faster.
+        // The comparision below empirically causes the result to agree with the
+        // tests in MathTest test_float_floor
+            if (exp > 149) {
+                return 0;
+            }
+#else
             exp = 25;
+#endif
         }
         // int add = 0;
         return value >> exp;
@@ -145,7 +154,17 @@ int32_t SkFloatBits_toIntCeil(int32_t packed) {
         value = SkApplySign(value, SkExtractSign(packed));
         exp = -exp;
         if (exp > 25) {   // underflow
+#ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED
+        // The iOS ARM processor discards small denormalized numbers to go faster.
+        // The comparision below empirically causes the result to agree with the
+        // tests in MathTest test_float_ceil
+            if (exp > 149) {
+                return 0;
+            }
+            return 0 < value;
+#else
             exp = 25;
+#endif
         }
         int add = (1 << exp) - 1;
         return (value + add) >> exp;
index f93ab610787b655cdcaf6a843613d50e3d82e5c7..e997045ea85318db4fe32b2643fc251dd83f4914 100644 (file)
 
 #include "SkMath.h"
 
+#ifdef SK_BUILD_FOR_IOS
+// The iOS ARM processor discards small denormalized numbers to go faster.
+// Algorithms that rely on denormalized numbers need alternative implementations.
+#define SK_DISCARD_DENORMALIZED_FOR_SPEED
+#endif
+
 /** Returns -1 if n < 0, else returns 0
  */
 #define SkExtractSign(n)    ((int32_t)(n) >> 31)
index 719ee54b225ae72e57ee6752ab22a107178adc66..8a6d0564af59b96d3e9842c02af373866b11bf02 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 
+#include "SkMathPriv.h"
 #include "SkPoint.h"
 
 void SkIPoint::rotateCW(SkIPoint* dst) const {
@@ -168,7 +169,17 @@ bool SkPoint::setLength(float x, float y, float length) {
         // divide by inf. and return (0,0) vector.
         double xx = x;
         double yy = y;
+    #ifdef SK_DISCARD_DENORMALIZED_FOR_SPEED
+        // The iOS ARM processor discards small denormalized numbers to go faster.
+        // Casting this to a float would cause the scale to go to zero. Keeping it
+        // as a double for the multiply keeps the scale non-zero.
+        double dscale = length / sqrt(xx * xx + yy * yy);
+        fX = x * dscale;
+        fY = y * dscale;
+        return true;
+    #else
         scale = (float)(length / sqrt(xx * xx + yy * yy));
+    #endif
     }
     fX = x * scale;
     fY = y * scale;
index 2c9a38979ac00e3d6a853abc1385a21f17c34bcd..442f0f77c0015bb31cd8482804784a75272b17b8 100644 (file)
@@ -28,6 +28,9 @@ int SkForceLinking(bool doNotPassTrue) {
 #endif
 #if !defined(SK_BUILD_FOR_MAC) && !defined(SK_BUILD_FOR_WIN) && !defined(SK_BUILD_FOR_IOS)
         CreatePNGImageDecoder();
+#endif
+#if defined(SK_BUILD_FOR_IOS)
+        CreatePNGImageEncoder_IOS();
 #endif
         return -1;
     }
index 7bebf394da5947dba78ea65b5cb01c95bf63d5bd..5b32502d8efa9ab0e6ca756f47cb7919fac624a8 100644 (file)
@@ -300,6 +300,17 @@ static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) {
 
 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory);
 
+#ifdef SK_BUILD_FOR_IOS
+class SkPNGImageEncoder_IOS : public SkImageEncoder_CG {
+public:
+    SkPNGImageEncoder_IOS()
+        : SkImageEncoder_CG(kPNG_Type) {
+    }
+};
+
+DEFINE_ENCODER_CREATOR(PNGImageEncoder_IOS);
+#endif
+
 struct FormatConversion {
     CFStringRef             fUTType;
     SkImageDecoder::Format  fFormat;
index 021fa253093590703f72081775cf2ca4731281f3..f3db65e03552f7b22b88709cd3e657769f77cc35 100755 (executable)
@@ -62,7 +62,4 @@ SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
     return NULL;
 }
 
-SkImageEncoder* SkImageEncoder::Create(Type t) {
-    return NULL;
-}
 
index 9b02417771e0f209e8e733a40e2d741640ca2620..e6a8eaeec66ab19c607818141b1bf5196c2c0423 100644 (file)
@@ -203,7 +203,9 @@ float SkTouchGesture::limitTotalZoom(float scale) const {
 void SkTouchGesture::touchMoved(void* owner, float x, float y) {
 //    GrPrintf("--- %d touchMoved %p %g %g\n", fTouches.count(), owner, x, y);
 
-    SkASSERT(kEmpty_State != fState);
+    if (kEmpty_State == fState) {
+        return;
+    }
 
     int index = this->findRec(owner);
     if (index < 0) {
index 2897883da3ad7db15092f979caee2f035924da8f..f8784a2d26cc3d428ea5394165c55aec3807a4a0 100644 (file)
@@ -437,8 +437,13 @@ DEF_TEST(Jpeg, reporter) {
     REPORTER_ASSERT(reporter, bm8888.getColor(27, 34) == 0xffffffff);
     REPORTER_ASSERT(reporter, bm8888.getColor(71, 18) == 0xff000000);
 
+#ifdef SK_BUILD_FOR_IOS  // the iOS jpeg decoder fills to gray
+    REPORTER_ASSERT(reporter, bm8888.getColor(127, 127) == 0xff808080
+            || bm8888.getColor(127, 127) == SK_ColorWHITE);
+#else
     // This is the fill color
     REPORTER_ASSERT(reporter, bm8888.getColor(127, 127) == SK_ColorWHITE);
+#endif
 
     #if JPEG_TEST_WRITE_TO_FILE_FOR_DEBUGGING
     // Check to see that the resulting bitmap is nice
index b76c223ba634031eb7978f3a54892964fa6189c1..e8f0504b1af57946e8dff49894ccc9afb92e641a 100644 (file)
@@ -5,6 +5,8 @@
 static const char* kSkOverwriteLine =
 #ifdef SK_BUILD_FOR_WIN32
 "\r                                                                               \r"
+#elif defined(SK_BUILD_FOR_IOS)
+"\r"
 #else
 "\r\033[K"
 #endif
index 756d14ad3acadf235bd5c2673168b5ab4e197919..0efd66b246caf2527bc98a1ff029804e6414555b 100644 (file)
@@ -15,3 +15,7 @@ DEFINE_string2(resourcePath, i, "resources", "Directory with test resources: ima
 SkString GetResourcePath(const char* resource) {
     return SkOSPath::SkPathJoin(FLAGS_resourcePath[0], resource);
 }
+
+void SetResourcePath(const char* resource) {
+    FLAGS_resourcePath.set(0, resource);
+}
index a10612b78d95c928e29bf5dbbd887c9145542ec5..485a11223158a00c5bc0fae5a93f4e2528dde7b5 100644 (file)
@@ -11,5 +11,6 @@
 #include "SkString.h"
 
 SkString GetResourcePath(const char* resource = "");
+void SetResourcePath(const char* );
 
 #endif  // Resources_DEFINED
index 370198b5a20d49825e5838637c4a8399f7b7383a..c6a783de3f4e9d8186dc0f81be78c7131e308c89 100644 (file)
@@ -137,6 +137,10 @@ public:
             return false;
         }
 
+        void set(int i, const char* str) {
+            fStrings[i].set(str);
+        }
+
     private:
         void reset() { fStrings.reset(); }
 
diff --git a/tools/iOSShell.cpp b/tools/iOSShell.cpp
new file mode 100644 (file)
index 0000000..bd70938
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "iOSShell.h"
+
+#include "Resources.h"
+#include "SkCanvas.h"
+#include "SkCommandLineFlags.h"
+#include "SkGraphics.h"
+#include "SkWindow.h"
+#include "sk_tool_utils.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* curr_view(SkWindow* wind) {
+    SkView::F2BIter iter(wind);
+    return iter.next();
+}
+
+ShellWindow::ShellWindow(void* hwnd, int argc, char** argv)
+    : INHERITED(hwnd) {
+    SkCommandLineFlags::Parse(argc, argv);
+}
+
+ShellWindow::~ShellWindow() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool ShellWindow::onDispatchClick(int x, int y, Click::State state,
+        void* owner, unsigned modi) {
+    int w = SkScalarRoundToInt(this->width());
+    int h = SkScalarRoundToInt(this->height());
+
+    // check for the resize-box
+    if (w - x < 16 && h - y < 16) {
+        return false;   // let the OS handle the click
+    } else {
+        return this->INHERITED::onDispatchClick(x, y, state, owner, modi);
+    }
+}
+
+void ShellWindow::onSizeChange() {
+    this->INHERITED::onSizeChange();
+
+    SkView::F2BIter iter(this);
+    SkView* view = iter.next();
+    view->setSize(this->width(), this->height());
+}
+
+void tool_main(int argc, char *argv[]);
+
+bool set_cmd_line_args(int argc, char *argv[], const char* resourceDir) {
+    for (int index = 0; index < argc; ++index) {
+        if (!strcmp("--test", argv[index])) {
+            SetResourcePath(resourceDir);
+            tool_main(argc - 1, argv);
+            return true;
+        }
+    }
+    return false;
+}
+
+// FIXME: this should be in a header
+SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv);
+SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
+    return new ShellWindow(hwnd, argc, argv);
+}
+
+// FIXME: this should be in a header
+void get_preferred_size(int* x, int* y, int* width, int* height);
+void get_preferred_size(int* x, int* y, int* width, int* height) {
+    *x = 10;
+    *y = 50;
+    *width = 640;
+    *height = 480;
+}
+
+// FIXME: this should be in a header
+void application_init();
+void application_init() {
+    SkGraphics::Init();
+    SkEvent::Init();
+}
+
+// FIXME: this should be in a header
+void application_term();
+void application_term() {
+    SkEvent::Term();
+    SkGraphics::Term();
+}
diff --git a/tools/iOSShell.h b/tools/iOSShell.h
new file mode 100644 (file)
index 0000000..7473e01
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Skia
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef iOSShell_DEFINED
+#define iOSShell_DEFINED
+
+#include "SkWindow.h"
+
+class SkCanvas;
+class SkEvent;
+class SkViewFactory;
+
+class ShellWindow : public SkOSWindow {
+public:
+    ShellWindow(void* hwnd, int argc, char** argv);
+    virtual ~ShellWindow();
+
+    virtual SkCanvas* createCanvas() SK_OVERRIDE {
+        SkCanvas* canvas = this->INHERITED::createCanvas();
+        return canvas;
+    }
+
+protected:
+    virtual void onSizeChange() SK_OVERRIDE;
+
+    virtual bool onDispatchClick(int x, int y, Click::State, void* owner,
+                                 unsigned modi) SK_OVERRIDE;
+
+private:
+    typedef SkOSWindow INHERITED;
+};
+
+#endif