diff --git a/experimental/iOSSampleApp/Shared/skia_ios.mm b/experimental/iOSSampleApp/Shared/skia_ios.mm index 65b3e8a034..4fce1392d8 100644 --- a/experimental/iOSSampleApp/Shared/skia_ios.mm +++ b/experimental/iOSSampleApp/Shared/skia_ios.mm @@ -1,14 +1,19 @@ #import #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 index 0000000000..69b62efd1c --- /dev/null +++ b/experimental/iOSShell/iOSShell-Info.plist @@ -0,0 +1,43 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.google.iOSShell + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow_iPhone + NSMainNibFile~ipad + MainWindow_iPad + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/gyp/iOSShell.gyp b/gyp/iOSShell.gyp new file mode 100644 index 0000000000..ed648a38c4 --- /dev/null +++ b/gyp/iOSShell.gyp @@ -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', + ], + }], + ], + }, + ], + }], + ] +} diff --git a/gyp/most.gyp b/gyp/most.gyp index ba189316e9..4675add4dd 100644 --- a/gyp/most.gyp +++ b/gyp/most.gyp @@ -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:*' ], diff --git a/include/core/SkImageEncoder.h b/include/core/SkImageEncoder.h index 754d5bbbc3..4d4d2a83c0 100644 --- a/include/core/SkImageEncoder.h +++ b/include/core/SkImageEncoder.h @@ -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_EncodeReg; diff --git a/src/core/SkFloatBits.cpp b/src/core/SkFloatBits.cpp index 39b51abf1d..6b35a75c88 100644 --- a/src/core/SkFloatBits.cpp +++ b/src/core/SkFloatBits.cpp @@ -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; diff --git a/src/core/SkMathPriv.h b/src/core/SkMathPriv.h index f93ab61078..e997045ea8 100644 --- a/src/core/SkMathPriv.h +++ b/src/core/SkMathPriv.h @@ -10,6 +10,12 @@ #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) diff --git a/src/core/SkPoint.cpp b/src/core/SkPoint.cpp index 719ee54b22..8a6d0564af 100644 --- a/src/core/SkPoint.cpp +++ b/src/core/SkPoint.cpp @@ -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; diff --git a/src/images/SkForceLinking.cpp b/src/images/SkForceLinking.cpp index 2c9a38979a..442f0f77c0 100644 --- a/src/images/SkForceLinking.cpp +++ b/src/images/SkForceLinking.cpp @@ -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; } diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp index 7bebf394da..5b32502d8e 100644 --- a/src/ports/SkImageDecoder_CG.cpp +++ b/src/ports/SkImageDecoder_CG.cpp @@ -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; diff --git a/src/utils/ios/SkImageDecoder_iOS.mm b/src/utils/ios/SkImageDecoder_iOS.mm index 021fa25309..f3db65e035 100755 --- a/src/utils/ios/SkImageDecoder_iOS.mm +++ b/src/utils/ios/SkImageDecoder_iOS.mm @@ -62,7 +62,4 @@ SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { return NULL; } -SkImageEncoder* SkImageEncoder::Create(Type t) { - return NULL; -} diff --git a/src/views/SkTouchGesture.cpp b/src/views/SkTouchGesture.cpp index 9b02417771..e6a8eaeec6 100644 --- a/src/views/SkTouchGesture.cpp +++ b/src/views/SkTouchGesture.cpp @@ -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) { diff --git a/tests/JpegTest.cpp b/tests/JpegTest.cpp index 2897883da3..f8784a2d26 100644 --- a/tests/JpegTest.cpp +++ b/tests/JpegTest.cpp @@ -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 diff --git a/tools/OverwriteLine.h b/tools/OverwriteLine.h index b76c223ba6..e8f0504b1a 100644 --- a/tools/OverwriteLine.h +++ b/tools/OverwriteLine.h @@ -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 diff --git a/tools/Resources.cpp b/tools/Resources.cpp index 756d14ad3a..0efd66b246 100644 --- a/tools/Resources.cpp +++ b/tools/Resources.cpp @@ -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); +} diff --git a/tools/Resources.h b/tools/Resources.h index a10612b78d..485a112231 100644 --- a/tools/Resources.h +++ b/tools/Resources.h @@ -11,5 +11,6 @@ #include "SkString.h" SkString GetResourcePath(const char* resource = ""); +void SetResourcePath(const char* ); #endif // Resources_DEFINED diff --git a/tools/flags/SkCommandLineFlags.h b/tools/flags/SkCommandLineFlags.h index 370198b5a2..c6a783de3f 100644 --- a/tools/flags/SkCommandLineFlags.h +++ b/tools/flags/SkCommandLineFlags.h @@ -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 index 0000000000..bd709386ec --- /dev/null +++ b/tools/iOSShell.cpp @@ -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 index 0000000000..7473e0187c --- /dev/null +++ b/tools/iOSShell.h @@ -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