├── Apps ├── StyleChecker │ ├── background.png │ ├── StyleCheckerAppDelegate.h │ ├── StyleCheckerViewController.h │ ├── main.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── StyleCheckerAppDelegate.m ├── Common │ ├── SVGUtil.h │ ├── SVGUtil.m │ ├── DirectoryContentsViewController.h │ └── DirectoryContentsViewController.m ├── DtdVerifier │ └── main.c ├── BatchRenderer │ └── main.m └── CommandLineRenderer │ └── main.m ├── AcceptanceTest ├── Golden │ └── Example │ │ └── circle.png ├── Info.plist └── AcceptanceTest.m ├── .gitignore ├── MetroSVG.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── AcceptanceTest.xcscheme │ ├── DTDVerifier.xcscheme │ ├── BatchRenderer.xcscheme │ ├── StyleChecker.xcscheme │ ├── CommandLineRenderer.xcscheme │ ├── MetroSVG-iOS.xcscheme │ └── MetroSVG-OS-X.xcscheme ├── TestData └── Example │ └── circle.svg ├── UnitTest-OS-X └── Info.plist ├── UnitTest-iOS └── Info.plist ├── MetroSVG ├── Public │ ├── MSCDebug.h │ ├── MSCStyleSheet.h │ └── MSCDocument.h ├── Internal │ ├── Constants.h │ ├── Macros.h │ ├── Debug.h │ ├── Constants.cc │ ├── BasicTypes.cc │ ├── Document.h │ ├── Debug.cc │ ├── TransformIterator.h │ ├── StyleSheet.h │ ├── StyleIterator.h │ ├── DocumentTest.mm │ ├── StringPiece.cc │ ├── SVGStandardColor.h │ ├── StyleIterator.cc │ ├── Gradient.h │ ├── StringPieceTest.mm │ ├── StringPiece.h │ ├── LoggingUtils.h │ ├── Gradient.cc │ ├── StyleIteratorTest.mm │ ├── BasicTypes.h │ ├── PathDataIterator.h │ ├── Utils.h │ ├── TransformIterator.cc │ ├── Document.cc │ ├── LoggingUtils.cc │ ├── StyleSheet.cc │ ├── BasicValueParsers.h │ ├── Utils.cc │ ├── StyleSheetTest.mm │ ├── SVGStandardColor.cc │ ├── Renderer.h │ └── PathDataIterator.cc ├── iOS │ ├── MSVGStyleSheet+Internal.h │ ├── MSVGStyleSheet.h │ ├── MSVGStyleSheet.mm │ ├── MSVGDocument.h │ └── MSVGDocument.mm ├── MetroSVG_Sources.mm ├── MetroSVG.h └── MetroSVG_Sources.cc ├── CONTRIBUTING ├── README.md ├── ProjectScripts └── copy_files.sh └── LICENSE /Apps/StyleChecker/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/metrosvg/HEAD/Apps/StyleChecker/background.png -------------------------------------------------------------------------------- /AcceptanceTest/Golden/Example/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/google/metrosvg/HEAD/AcceptanceTest/Golden/Example/circle.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | *.xcodeproj/project.xcworkspace/xcuserdata 4 | *.xcodeproj/xcuserdata 5 | TestData/UserData 6 | AcceptanceTest/Golden/UserData 7 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TestData/Example/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /UnitTest-OS-X/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /UnitTest-iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /AcceptanceTest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Apps/StyleChecker/StyleCheckerAppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface StyleCheckerAppDelegate : UIResponder 20 | 21 | @property (strong, nonatomic) UIWindow *window; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /MetroSVG/Public/MSCDebug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #if defined __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | void MSCSetCoreGraphicsCallLoggingEnabled(int enabled); 24 | 25 | #if defined __cplusplus 26 | } // extern "C" 27 | #endif 28 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | extern const CGFloat kPi; 25 | 26 | } // namespace internal 27 | } // namespace metrosvg 28 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) 20 | 21 | #define DISALLOW_COPY_AND_ASSIGN(class_name) \ 22 | class_name(const class_name &rhs); \ 23 | const class_name &operator=(const class_name &rhs); 24 | -------------------------------------------------------------------------------- /MetroSVG/iOS/MSVGStyleSheet+Internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "MetroSVG/iOS/MSVGStyleSheet.h" 18 | 19 | #include "MetroSVG/Public/MSCStyleSheet.h" 20 | 21 | @interface MSVGStyleSheet () 22 | 23 | @property(nonatomic, readonly) MSCStyleSheet *styleSheet; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "MetroSVG/Public/MSCDebug.h" 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | bool GetCoreGraphicsCallLoggingEnabled(); 25 | 26 | } // namespace internal 27 | } // namespace metrosvg 28 | -------------------------------------------------------------------------------- /Apps/StyleChecker/StyleCheckerViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @interface StyleCheckerViewController : UIViewController 20 | 21 | - (instancetype)initWithPath:(NSString *)path 22 | cssFiles:(NSArray *)cssFiles; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Constants.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/Constants.h" 18 | 19 | #include 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | const CGFloat kPi = static_cast(M_PI); 25 | 26 | } // namespace internal 27 | } // namespace metrosvg 28 | -------------------------------------------------------------------------------- /Apps/StyleChecker/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "StyleCheckerAppDelegate.h" 20 | 21 | int main(int argc, char *argv[]) { 22 | @autoreleasepool { 23 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([StyleCheckerAppDelegate class])); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MetroSVG/iOS/MSVGStyleSheet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | // MSVGStyleSheet represents a set of CSS rules. 20 | @interface MSVGStyleSheet : NSObject 21 | 22 | // Initializes the receiver with UTF-8-encoded CSS data. 23 | - (instancetype)initWithData:(NSData *)data; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Apps/Common/SVGUtil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | @interface SVGUtil : NSObject 21 | 22 | + (CGImageRef)imageWithSVGFile:(NSString *)file size:(CGSize)size; 23 | 24 | + (void)writeImage:(CGImageRef)image toPNGFile:(NSString *)file; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MetroSVG/MetroSVG_Sources.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | _Static_assert(TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR, 20 | "This file is for iOS."); 21 | 22 | #include "MetroSVG/MetroSVG_Sources.cc" 23 | #import "MetroSVG/iOS/MSVGDocument.mm" 24 | #import "MetroSVG/iOS/MSVGStyleSheet.mm" 25 | -------------------------------------------------------------------------------- /MetroSVG/Internal/BasicTypes.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/BasicTypes.h" 18 | 19 | #include "MetroSVG/Internal/Utils.h" 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | RgbColor::RgbColor(CGFloat red, CGFloat green, CGFloat blue) 25 | : red_(ClampToUnitRange(red)), 26 | green_(ClampToUnitRange(green)), 27 | blue_(ClampToUnitRange(blue)) {} 28 | 29 | } // namespace internal 30 | } // namespace metrosvg 31 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Document.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "MetroSVG/Public/MSCDocument.h" 20 | 21 | // Represents a partially parsed SVG document. 22 | struct MSCDocument { 23 | const char *data; 24 | size_t data_length; 25 | const char *url; 26 | 27 | // Value of the width and height attributes of the outmost svg element. 28 | CGSize size; 29 | // Value of the viewBox attribute of the outmost svg element. 30 | CGRect view_box; 31 | }; 32 | -------------------------------------------------------------------------------- /MetroSVG/iOS/MSVGStyleSheet.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "MetroSVG/iOS/MSVGStyleSheet+Internal.h" 18 | 19 | @implementation MSVGStyleSheet 20 | 21 | - (instancetype)initWithData:(NSData *)data { 22 | self = [super init]; 23 | if (self) { 24 | _styleSheet = 25 | MSCStyleSheetCreateWithData( 26 | reinterpret_cast(data.bytes), data.length); 27 | } 28 | return self; 29 | } 30 | 31 | - (void)dealloc { 32 | MSCStyleSheetDelete(_styleSheet); 33 | _styleSheet = NULL; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Debug.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/Debug.h" 18 | 19 | namespace metrosvg { 20 | namespace internal { 21 | 22 | namespace { 23 | bool g_coreGraphicsCallLoggingEnabled = false; 24 | } // namespace 25 | 26 | bool GetCoreGraphicsCallLoggingEnabled() { 27 | return g_coreGraphicsCallLoggingEnabled; 28 | } 29 | 30 | } // namespace internal 31 | } // namespace metrosvg 32 | 33 | void MSCSetCoreGraphicsCallLoggingEnabled(int enabled) { 34 | metrosvg::internal::g_coreGraphicsCallLoggingEnabled = (enabled != 0); 35 | } 36 | -------------------------------------------------------------------------------- /MetroSVG/MetroSVG.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // The umbrella header of MetroSVG. This file can be included by both C and 18 | // Objective-C code. 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include "MetroSVG/Public/MSCDebug.h" 25 | #include "MetroSVG/Public/MSCDocument.h" 26 | #include "MetroSVG/Public/MSCStyleSheet.h" 27 | 28 | #ifdef __OBJC__ 29 | #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 30 | 31 | #import "MetroSVG/iOS/MSVGDocument.h" 32 | #import "MetroSVG/iOS/MSVGStyleSheet.h" 33 | 34 | #endif // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 35 | #endif // __OBJC__ 36 | -------------------------------------------------------------------------------- /MetroSVG/Internal/TransformIterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | class StringPiece; 25 | 26 | class TransformIterator { 27 | public: 28 | explicit TransformIterator(StringPiece *s); 29 | 30 | bool Next(); 31 | const CGAffineTransform &transform() const { return transform_; } 32 | 33 | private: 34 | void ConsumeTransformDelimeters(StringPiece *s) const; 35 | 36 | StringPiece *s_; 37 | CGAffineTransform transform_; 38 | bool is_first; 39 | }; 40 | 41 | } // namespace internal 42 | } // namespace metrosvg 43 | -------------------------------------------------------------------------------- /MetroSVG/Public/MSCStyleSheet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #if defined __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | // MSCStyleSheet is an opaque type that represents a set of CSS rules. 24 | typedef struct MSCStyleSheet MSCStyleSheet; 25 | 26 | // Creates an MSCStyleSheet instance with UTF-8-encoded CSS data. The instance 27 | // must be deleted with MSCStyleSheetDelete when it is done. 28 | MSCStyleSheet *MSCStyleSheetCreateWithData(const char *data, size_t length); 29 | 30 | // Delets an MSCStyleSheet instance. 31 | void MSCStyleSheetDelete(MSCStyleSheet *style_sheet); 32 | 33 | #if defined __cplusplus 34 | } // extern "C" 35 | #endif 36 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleSheet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #include "MetroSVG/Public/MSCStylesheet.h" 23 | 24 | struct MSCStyleSheet { 25 | std::map>> entry; 26 | }; 27 | 28 | namespace metrosvg { 29 | namespace internal { 30 | 31 | // Caller should release the returned instance. 32 | MSCStyleSheet *ParseStyleSheetData(const char *data, 33 | size_t data_length); 34 | 35 | // Merge css content in source into dest. 36 | void MSCStyleSheetMerge(const MSCStyleSheet &source, 37 | MSCStyleSheet *dest); 38 | 39 | } // namespace internal 40 | } // namespace metrosvg 41 | -------------------------------------------------------------------------------- /MetroSVG/MetroSVG_Sources.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/BasicTypes.cc" 18 | #include "MetroSVG/Internal/BasicValueParsers.cc" 19 | #include "MetroSVG/Internal/Constants.cc" 20 | #include "MetroSVG/Internal/Debug.cc" 21 | #include "MetroSVG/Internal/Document.cc" 22 | #include "MetroSVG/Internal/Gradient.cc" 23 | #include "MetroSVG/Internal/LoggingUtils.cc" 24 | #include "MetroSVG/Internal/PathDataIterator.cc" 25 | #include "MetroSVG/Internal/Renderer.cc" 26 | #include "MetroSVG/Internal/StringPiece.cc" 27 | #include "MetroSVG/Internal/StyleIterator.cc" 28 | #include "MetroSVG/Internal/StyleSheet.cc" 29 | #include "MetroSVG/Internal/SVGStandardColor.cc" 30 | #include "MetroSVG/Internal/TransformIterator.cc" 31 | #include "MetroSVG/Internal/Utils.cc" 32 | -------------------------------------------------------------------------------- /Apps/StyleChecker/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleIterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include "MetroSVG/Internal/StringPiece.h" 22 | 23 | namespace metrosvg { 24 | namespace internal { 25 | 26 | class StyleIterator { 27 | public: 28 | StyleIterator(StringPiece *s, 29 | const std::unordered_set &supported_properties); 30 | 31 | // Sets property and value to the next style in supported_properties. 32 | bool Next(); 33 | const StringPiece &property() const { return property_; } 34 | const StringPiece &value() const { return value_; } 35 | 36 | private: 37 | StringPiece *s_; 38 | StringPiece property_; 39 | StringPiece value_; 40 | const std::unordered_set supported_properties_; 41 | }; 42 | 43 | } // namespace internal 44 | } // namespace metrosvg 45 | -------------------------------------------------------------------------------- /MetroSVG/Internal/DocumentTest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #import 20 | 21 | #include "MetroSVG/Internal/Document.h" 22 | 23 | @interface DocumentTest : XCTestCase 24 | @end 25 | 26 | @implementation DocumentTest 27 | 28 | - (void)testGetImageAspectRatio { 29 | std::string data = ""; 30 | MSCDocument *document = 31 | MSCDocumentCreateFromData(data.c_str(), data.size(), ""); 32 | XCTAssert(CGRectEqualToRect(MSCDocumentGetImageViewBox(document), 33 | CGRectMake(0, 0, 640, 480))); 34 | MSCDocumentDelete(document); 35 | } 36 | 37 | - (void)testGetImageAspectRatio_ImplicitDefault { 38 | // TODO: What to do when viewBox is not specified? 39 | } 40 | 41 | 42 | // TODO: Write more tests of SVGDocument* public functions. 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement] 6 | (https://cla.developers.google.com/about/google-individual) 7 | (CLA), which you can do online. The CLA is necessary mainly because you own the 8 | copyright to your changes, even after your contribution becomes part of our 9 | codebase, so we need your permission to use and distribute your code. We also 10 | need to be sure of various other things—for instance that you'll tell us if you 11 | know that your code infringes on other people's patents. You don't have to sign 12 | the CLA until after you've submitted your code for review and a member has 13 | approved it, but you must do it before we can put your code into our codebase. 14 | Before you start working on a larger contribution, you should get in touch with 15 | us first through the issue tracker with your idea so that we can help out and 16 | possibly guide you. Coordinating up front makes it much easier to avoid 17 | frustration later on. 18 | 19 | ### Code reviews 20 | All submissions, including submissions by project members, require review. We 21 | use Github pull requests for this purpose. 22 | 23 | ### The small print 24 | Contributions made by corporations are covered by a different agreement than 25 | the one above, the 26 | [Software Grant and Corporate Contributor License Agreement] 27 | (https://cla.developers.google.com/about/google-corporate). 28 | -------------------------------------------------------------------------------- /Apps/Common/SVGUtil.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "Apps/Common/SVGUtil.h" 18 | 19 | #import "MetroSVG/MetroSVG.h" 20 | 21 | @implementation SVGUtil 22 | 23 | + (CGImageRef)imageWithSVGFile:(NSString *)file size:(CGSize)size { 24 | NSData *svgData = [NSData dataWithContentsOfFile:file]; 25 | MSCDocument *document = MSCDocumentCreateFromData([svgData bytes], [svgData length], ""); 26 | CGImageRef image = MSCDocumentCreateCGImage(document, size, NULL); 27 | MSCDocumentDelete(document); 28 | return image; 29 | } 30 | 31 | + (void)writeImage:(CGImageRef)image toPNGFile:(NSString *)file { 32 | NSURL *url = [NSURL fileURLWithPath:file]; 33 | CGImageDestinationRef destination = 34 | CGImageDestinationCreateWithURL((__bridge CFURLRef)url, kUTTypePNG, 1, NULL); 35 | CGImageDestinationAddImage(destination, image, NULL); 36 | CGImageDestinationFinalize(destination); 37 | CFRelease(destination); 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StringPiece.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/StringPiece.h" 18 | 19 | #include 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | const std::string StringPiece::as_std_string() const { 25 | return std::string(begin_, length_); 26 | } 27 | 28 | void StringPiece::Advance(size_t n) { 29 | begin_ = begin_ + std::min(n, length_); 30 | length_ = length_ - std::min(n, length_); 31 | } 32 | 33 | size_t StringPiece::find(char c) const { 34 | const char *iter = std::find(begin_, end(), c); 35 | if (iter == end()) { 36 | return std::string::npos; 37 | } else { 38 | return iter - begin_; 39 | } 40 | } 41 | 42 | size_t StringPiece::find(const StringPiece &s) const { 43 | const char * pos = std::search(begin_, end(), s.begin_, s.end()); 44 | if (pos == end()) { 45 | return std::string::npos; 46 | } else { 47 | return pos - begin_; 48 | } 49 | } 50 | 51 | } // namespace internal 52 | } // namespace metrosvg 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #MetroSVG 2 | 3 | MetroSVG is a production-quality SVG renderer implementation for iOS 4 | and OS X. It is used in Google Maps for iOS. 5 | 6 | The library provides an Objective-C interface for iOS and a C 7 | interface for iOS and OS X. 8 | 9 | ##Usage 10 | #import "MetroSVG/MetroSVG.h" 11 | 12 | NSData *svgData = ...; 13 | MSVGDocument *svgDocument = [[MSVGDocument alloc] initWithData:svgData]; 14 | UIImage *svgImage = [svgDocument imageWithSize:svgDocument.size]; 15 | 16 | ##Supported Features 17 | MetroSVG is intended to cover the most common use cases of SVG in native iOS app development where designers create and export image assets using graphics tools such as Illustrator and Inkscape. Therefore, it is specialized for rendering of static images by design. Below is a list of SVG 1.1 features and their implementation status. 18 | 19 | 20 | Feature | Status 21 | --- | --- 22 | Paths and Basic Shapes | Feature complete. 23 | Coordinate Systems and Transformations | Feature complete. 24 | Gradients | Near feature complete. 25 | Fill and Stroke Properties | Near feature complete. 26 | Document Structure | Only <svg> and <g> are implemented. 27 | Styling (CSS) | An experimental implementation of class selector is available. 28 | Clipping, Masking, Patterns, Markers, Length Units | Not implemented. 29 | Text, Fonts, Filter Effects | Not implemented. Recommended to use other options. 30 | Color Profile, Linking, Interactivity, Scripting, Animation | Out of scope. 31 | 32 | ##Discussion Forum 33 | https://groups.google.com/forum/#!forum/metrosvg 34 | 35 | ##Disclaimer 36 | MetroSVG is not an official Google product. 37 | -------------------------------------------------------------------------------- /MetroSVG/Internal/SVGStandardColor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "MetroSVG/Internal/StringPiece.h" 20 | 21 | // If this symbol is externally set to 0, SVG color keyword support 22 | // will be omitted. Color keyword support causes the object code 23 | // size to increase by about 1100 bytes. 24 | #if !defined(SVG_COLOR_KEYWORD_SUPPORT) 25 | #define SVG_COLOR_KEYWORD_SUPPORT 1 26 | #endif // !defined(SVG_COLOR_KEYWORD_SUPPORT) 27 | 28 | #if SVG_COLOR_KEYWORD_SUPPORT 29 | 30 | namespace metrosvg { 31 | namespace internal { 32 | 33 | // This is a struct that can be statically initialized with the 34 | // definitions of the standard SVG colors. 35 | struct SvgStandardColorDefinition { 36 | const char *name; 37 | uint8_t red; 38 | uint8_t green; 39 | uint8_t blue; 40 | uint8_t alpha; 41 | }; 42 | const SvgStandardColorDefinition *FindSVGStandardColorOrNull( 43 | const StringPiece &token); 44 | 45 | } // namespace internal 46 | } // namespace metrosvg 47 | 48 | #endif // SVG_COLOR_KEYWORD_SUPPORT 49 | -------------------------------------------------------------------------------- /Apps/Common/DirectoryContentsViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | @protocol DirectoryContentsViewControllerDataSource; 20 | 21 | /** 22 | * DirectoryContentsViewController implements traversal of directory trees using 23 | * usual combination of table views and the navigation stack. When traversal 24 | * reaches a tree leave (non-directory files), it creates a view controller from 25 | * its data source that presents files in a way specific to the application. 26 | * 27 | * It can handle multiple parallel directory trees. 28 | */ 29 | @interface DirectoryContentsViewController : UITableViewController 30 | 31 | @property(nonatomic, weak) id dataSource; 32 | 33 | - (instancetype)initWithPaths:(NSArray *)paths title:(NSString *)title; 34 | 35 | @end 36 | 37 | @protocol DirectoryContentsViewControllerDataSource 38 | 39 | - (UIViewController *) 40 | directoryContentsController:(DirectoryContentsViewController *)directoryContentsController 41 | viewControllerWithFilePaths:(NSArray *)filePaths; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Apps/StyleChecker/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /MetroSVG/iOS/MSVGDocument.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | @class MSVGStyleSheet; 21 | 22 | // MSVGDocument represents an SVG document. 23 | @interface MSVGDocument : NSObject 24 | 25 | // The image's intrinsic size as defined by "width" and "height" attributes of 26 | // the outermost svg element. If these attributes are not specified, zero is 27 | // assumed. 28 | @property(nonatomic, readonly) CGSize size; 29 | 30 | // Value of "viewBox" attribute of the outermost svg element. Returns CGRectNull 31 | // if the attribute is not specified. 32 | @property(nonatomic, readonly) CGRect viewBox; 33 | 34 | // Initializes the receiver with UTF-8-encoded SVG data. The data will be 35 | // partially parsed to populate the receiver's properties. 36 | - (instancetype)initWithData:(NSData *)data; 37 | 38 | // Fully parses the data and renders it into a UIImage. The returned image 39 | // has the appropriate density for the screen scale. 40 | - (UIImage *)imageWithSize:(CGSize)size; 41 | 42 | // Same as -imageWithSize: but takes an optional style sheet argument. 43 | - (UIImage *)imageWithSize:(CGSize)size styleSheet:(MSVGStyleSheet *)styleSheet; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Apps/StyleChecker/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarTintParameters 32 | 33 | UINavigationBar 34 | 35 | Style 36 | UIBarStyleDefault 37 | Translucent 38 | 39 | 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /ProjectScripts/copy_files.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | # 3 | # Copyright 2015 Google Inc. All Rights Reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | ################################################################################ 18 | # 19 | 20 | #!/bin/bash 21 | # 22 | # This script copies the test data suite to an application-specific 23 | # location. 24 | # 25 | # ==== Usage ==== 26 | # 27 | # $ ./copy_files.sh [destination] 28 | # 29 | # The optional destinaiton is the directory that files will be copied 30 | # to. When it is not specified, the resource directory of an app's 31 | # main bundle is used, which is always a reasonable default for build 32 | # target types that create a bundle. 33 | 34 | if [[ $# -ge 1 ]]; then 35 | destination="$1" 36 | else 37 | destination="${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 38 | fi 39 | 40 | function install_files() { 41 | local source=$1 42 | local target=$2 43 | mkdir -p "$target" 44 | # Don't drop "/" after $source. rsync changes its behavior based on it. 45 | rsync -a --include="*/" --include="*.svg" --include="*.png" --exclude="*" "${source}/" "$target" 46 | } 47 | 48 | install_files \ 49 | "${SRCROOT}/TestData" \ 50 | "${destination}/TestData" 51 | 52 | install_files \ 53 | "${SRCROOT}/AcceptanceTest/Golden" \ 54 | "${destination}/Golden" 55 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleIterator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/StyleIterator.h" 18 | 19 | #include "MetroSVG/Internal/BasicValueParsers.h" 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | StyleIterator::StyleIterator( 25 | StringPiece *s, 26 | const std::unordered_set &supported_properties) 27 | : s_(s), 28 | supported_properties_(supported_properties) {} 29 | 30 | bool StyleIterator::Next() { 31 | ConsumeWhitespace(s_); 32 | if (s_->length() == 0) { 33 | return false; 34 | } 35 | size_t pos = s_->find(':'); 36 | if (pos == std::string::npos) { 37 | // TODO: throw exception 38 | return false; 39 | } 40 | property_ = TrimTrailingWhitespace(StringPiece(s_->begin(), pos)); 41 | s_->Advance(pos + 1); 42 | 43 | ConsumeWhitespace(s_); 44 | pos = s_->find(';'); 45 | if (pos == std::string::npos) { 46 | value_ = TrimTrailingWhitespace(*s_); 47 | s_->Advance(s_->length()); 48 | } else { 49 | value_ = TrimTrailingWhitespace(StringPiece(s_->begin(), pos)); 50 | s_->Advance(pos + 1); 51 | } 52 | 53 | if (supported_properties_.count(property_.as_std_string())) { 54 | return true; 55 | } 56 | return Next(); 57 | } 58 | 59 | } // namespace internal 60 | } // namespace metrosvg 61 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Gradient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "MetroSVG/Internal/BasicTypes.h" 25 | 26 | namespace metrosvg { 27 | namespace internal { 28 | 29 | struct Gradient; 30 | 31 | CGGradientRef CreateCGGradient(const Gradient &gradient); 32 | 33 | struct GradientStop { 34 | CGFloat offset; 35 | RgbColor color; 36 | CGFloat opacity; 37 | 38 | GradientStop(CGFloat offset_in, RgbColor color_in, CGFloat opacity_in) 39 | : offset(offset_in), color(color_in), opacity(opacity_in) {} 40 | }; 41 | 42 | struct Gradient { 43 | enum Type { 44 | kTypeLinear, 45 | kTypeRadial, 46 | }; 47 | 48 | enum Units { 49 | kUnitsObjectBoundingBox, 50 | kUnitsUserSpaceOnUse, 51 | }; 52 | 53 | struct Linear { 54 | Length x1, y1, x2, y2; 55 | }; 56 | 57 | struct Radial { 58 | Length fx, fy, cx, cy, r; 59 | }; 60 | 61 | Type type; 62 | std::string id; 63 | std::vector stops; 64 | std::vector transforms; 65 | Units units; 66 | 67 | union { 68 | Linear linear; 69 | Radial radial; 70 | }; 71 | 72 | Gradient(Type type_in, const StringMap &attributes); 73 | }; 74 | 75 | } // namespace internal 76 | } // namespace metrosvg 77 | -------------------------------------------------------------------------------- /Apps/DtdVerifier/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /** 18 | * DTDVerifier verifies an xml file with a given dtd. 19 | * 20 | * Usage: 21 | * $ DTDVerifier xml_file dtd_file 22 | */ 23 | 24 | #include 25 | 26 | int main(int argc, const char *argv[]) { 27 | int status = 0; 28 | xmlParserCtxtPtr parser_context = 0; 29 | xmlDocPtr doc = 0; 30 | xmlDtdPtr dtd = 0; 31 | xmlValidCtxtPtr valid_context = 0; 32 | 33 | do { 34 | if (argc < 3) { 35 | status = 2; 36 | fprintf(stderr, "Too few arguments.\n"); 37 | break; 38 | } 39 | 40 | parser_context = xmlNewParserCtxt(); 41 | doc = xmlCtxtReadFile(parser_context, argv[1], NULL, 0); 42 | if (!doc) { 43 | status = 3; 44 | fprintf(stderr, "Can't read xml.\n"); 45 | break; 46 | } 47 | 48 | dtd = xmlParseDTD(NULL, (const xmlChar *)argv[2]); 49 | if (!dtd) { 50 | status = 4; 51 | fprintf(stderr, "Can't read dtd.\n"); 52 | break; 53 | } 54 | 55 | valid_context = xmlNewValidCtxt(); 56 | status = xmlValidateDtd(valid_context, doc, dtd) ? 0 : 1; 57 | } while (0); 58 | 59 | if (parser_context) xmlFreeParserCtxt(parser_context); 60 | if (doc) xmlFreeDoc(doc); 61 | if (dtd) xmlFreeDtd(dtd); 62 | if (valid_context) xmlFreeValidCtxt(valid_context); 63 | 64 | return status; 65 | } 66 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StringPieceTest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #include "MetroSVG/Internal/StringPiece.h" 20 | 21 | using namespace metrosvg::internal; 22 | 23 | @interface StringPieceTest : XCTestCase 24 | @end 25 | 26 | @implementation StringPieceTest 27 | 28 | - (void)testEqualsOperator_Char { 29 | StringPiece lhs("abc"); 30 | XCTAssertTrue(lhs == "abc"); 31 | XCTAssertFalse(lhs == "ab"); 32 | XCTAssertFalse(lhs == "abcd"); 33 | XCTAssertFalse(lhs == "abe"); 34 | XCTAssertFalse(lhs == ""); 35 | XCTAssertFalse(lhs == NULL); 36 | } 37 | 38 | - (void)testFind_Char { 39 | StringPiece s("abcabc"); 40 | XCTAssertEqual(s.find('a'), size_t(0)); 41 | XCTAssertEqual(s.find('b'), size_t(1)); 42 | XCTAssertEqual(s.find('c'), size_t(2)); 43 | XCTAssertEqual(s.find('d'), std::string::npos); 44 | } 45 | 46 | - (void)testFind_Char_EmptyTarget { 47 | StringPiece s; 48 | XCTAssertEqual(s.find('a'), std::string::npos); 49 | } 50 | 51 | - (void)testFind_StdString { 52 | StringPiece s("abcdabcd"); 53 | XCTAssertEqual(s.find("ab"), size_t(0)); 54 | XCTAssertEqual(s.find("bc"), size_t(1)); 55 | XCTAssertEqual(s.find("cd"), size_t(2)); 56 | XCTAssertEqual(s.find("de"), std::string::npos); 57 | } 58 | 59 | - (void)testFind_StdString_EmptyTarget { 60 | StringPiece s; 61 | XCTAssertEqual(s.find("ab"), std::string::npos); 62 | } 63 | 64 | @end 65 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/AcceptanceTest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /MetroSVG/iOS/MSVGDocument.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "MetroSVG/iOS/MSVGDocument.h" 18 | 19 | #include "MetroSVG/Public/MSCDocument.h" 20 | #import "MetroSVG/iOS/MSVGStyleSheet+Internal.h" 21 | 22 | @implementation MSVGDocument { 23 | MSCDocument *_document; 24 | } 25 | 26 | - (instancetype)initWithData:(NSData *)data { 27 | self = [super init]; 28 | if (self) { 29 | _document = 30 | MSCDocumentCreateFromData(reinterpret_cast(data.bytes), 31 | data.length, 32 | ""); 33 | } 34 | return self; 35 | } 36 | 37 | - (void)dealloc { 38 | MSCDocumentDelete(_document); 39 | _document = NULL; 40 | } 41 | 42 | - (CGSize)size { 43 | return MSCDocumentGetImageSize(_document); 44 | } 45 | 46 | - (CGRect)viewBox { 47 | return MSCDocumentGetImageViewBox(_document); 48 | } 49 | 50 | - (UIImage *)imageWithSize:(CGSize)size { 51 | return [self imageWithSize:size styleSheet:NULL]; 52 | } 53 | 54 | - (UIImage *)imageWithSize:(CGSize)size 55 | styleSheet:(MSVGStyleSheet *)styleSheet { 56 | CGFloat scale = [UIScreen mainScreen].scale; 57 | CGSize canvasSize = CGSizeMake(size.width * scale, size.height * scale); 58 | CGImageRef cgImage = 59 | MSCDocumentCreateCGImage(_document, canvasSize, styleSheet.styleSheet); 60 | UIImage *uiImage = [UIImage imageWithCGImage:cgImage 61 | scale:[UIScreen mainScreen].scale 62 | orientation:UIImageOrientationUp]; 63 | CGImageRelease(cgImage); 64 | return uiImage; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Apps/StyleChecker/StyleCheckerAppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "StyleCheckerAppDelegate.h" 18 | 19 | #import "DirectoryContentsViewController.h" 20 | #import "StyleCheckerViewController.h" 21 | 22 | #include "MetroSVG/MetroSVG.h" 23 | 24 | @interface StyleCheckerAppDelegate () 25 | @end 26 | 27 | @implementation StyleCheckerAppDelegate 28 | 29 | - (BOOL)application:(UIApplication *)application 30 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 31 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 32 | self.window.backgroundColor = [UIColor whiteColor]; 33 | [self.window makeKeyAndVisible]; 34 | 35 | NSString *resourcesPath = [[NSBundle mainBundle] resourcePath]; 36 | NSString *testDataPath = [resourcesPath stringByAppendingPathComponent:@"TestData"]; 37 | DirectoryContentsViewController *rootDirectoryViewController = 38 | [[DirectoryContentsViewController alloc] initWithPaths:@[ testDataPath ] title:@"ROOT"]; 39 | rootDirectoryViewController.dataSource = self; 40 | UINavigationController *navigationController = 41 | [[UINavigationController alloc] initWithRootViewController:rootDirectoryViewController]; 42 | self.window.rootViewController = navigationController; 43 | 44 | return YES; 45 | } 46 | 47 | #pragma mark DirectoryContentsViewControllerDataSource 48 | 49 | - (UIViewController *) 50 | directoryContentsController:(DirectoryContentsViewController *)directoryContentsController 51 | viewControllerWithFilePaths:(NSArray *)filePaths { 52 | return [[StyleCheckerViewController alloc] initWithPath:filePaths[0] 53 | cssFiles:nil]; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /MetroSVG/Public/MSCDocument.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include "MetroSVG/Public/MSCStylesheet.h" 22 | 23 | #if defined __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | // MSCDocument is an opaque type that represents a single SVG document. 28 | typedef struct MSCDocument MSCDocument; 29 | 30 | // Creates an MSCDocument instance with UTF-8-encoded SVG data. The data will be 31 | // partially parsed to compute basic properties of the image. The returned 32 | // instance must be deleted with MSCDocumentDelete when it is done. 33 | // |url| can be NULL. 34 | MSCDocument *MSCDocumentCreateFromData(const char *data, 35 | size_t length, 36 | const char *url); 37 | 38 | // Deletes an MSCDocument instance. 39 | void MSCDocumentDelete(MSCDocument *document); 40 | 41 | // Fully parses data in a given MSCDocument and creates a CGImage from it. 42 | // The caller is responsible for releasing the returned object. 43 | // |style_sheet| can be NULL. 44 | CGImageRef MSCDocumentCreateCGImage(MSCDocument *document, 45 | CGSize canvas_size, 46 | const MSCStyleSheet *style_sheet); 47 | 48 | // Returns the image's intrinsic size as defined by "width" and "height" 49 | // attributes of the outermost svg element. If these attributes are not 50 | // specified, zero is assumed. 51 | CGSize MSCDocumentGetImageSize(const MSCDocument *document); 52 | 53 | // Returns value of "viewBox" attribute of the outermost svg element. Returns 54 | // CGRectNull if the attribute is not specified. 55 | CGRect MSCDocumentGetImageViewBox(const MSCDocument *document); 56 | 57 | #if defined __cplusplus 58 | } // extern "C" 59 | #endif 60 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StringPiece.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace metrosvg { 24 | namespace internal { 25 | 26 | class StringPiece { 27 | public: 28 | StringPiece() 29 | : begin_(NULL), length_(0) {} 30 | 31 | StringPiece(const char *s) 32 | : begin_(s), length_(s ? std::strlen(s) : 0) {} 33 | 34 | StringPiece(const std::string &s) 35 | : begin_(s.data()), length_(s.length()) {} 36 | 37 | StringPiece(const char *begin, size_t length) 38 | : begin_(begin), length_(length) {} 39 | 40 | StringPiece(const char *begin, const char *end) 41 | : begin_(begin), length_(end - begin) {} 42 | 43 | StringPiece(const StringPiece &rhs) 44 | : begin_(rhs.begin_), length_(rhs.length_) {} 45 | 46 | StringPiece &operator=(const StringPiece &rhs) { 47 | begin_ = rhs.begin_; 48 | length_ = rhs.length_; 49 | return *this; 50 | } 51 | 52 | bool operator==(const StringPiece &rhs) const { 53 | if (length() != rhs.length()) { 54 | return false; 55 | } 56 | for (size_t i = 0; i < length(); ++i) { 57 | if ((*this)[i] != rhs[i]) { 58 | return false; 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | bool operator==(const char *rhs) const { 65 | return (*this) == StringPiece(rhs); 66 | } 67 | 68 | char operator[](size_t n) const { return *(begin_ + n); } 69 | 70 | const char *begin() const { return begin_; } 71 | const char *end() const { return begin_ + length_; } 72 | size_t length() const { return length_; } 73 | 74 | const std::string as_std_string() const; 75 | 76 | size_t find(char c) const; 77 | size_t find(const StringPiece &s) const; 78 | 79 | void Advance(size_t n); 80 | 81 | private: 82 | const char *begin_; 83 | size_t length_; 84 | }; 85 | 86 | } // namespace internal 87 | } // namespace metrosvg 88 | -------------------------------------------------------------------------------- /Apps/BatchRenderer/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #import "Apps/Common/SVGUtil.h" 20 | 21 | static const CGSize kCanvasSize = {640, 640}; 22 | 23 | // Renders all files under |inputDir| with an extension of .svg 24 | // into the same relative path under |outputDir| as .png files. 25 | static void RenderSVGFiles(NSString *inputDir, NSString *outputDir) { 26 | NSFileManager *fileManager = [NSFileManager defaultManager]; 27 | NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:inputDir]; 28 | NSString *relPath; 29 | 30 | while (relPath = [enumerator nextObject]) { 31 | NSString *inputPath = [inputDir stringByAppendingPathComponent:relPath]; 32 | BOOL isDirectory; 33 | [fileManager fileExistsAtPath:inputPath isDirectory:&isDirectory]; 34 | if (isDirectory) { 35 | NSError *error; 36 | NSString *outputPath = [outputDir stringByAppendingPathComponent:relPath]; 37 | [fileManager createDirectoryAtPath:outputPath 38 | withIntermediateDirectories:YES 39 | attributes:nil 40 | error:&error]; 41 | } else if ([[relPath pathExtension] isEqualToString:@"svg"]) { 42 | NSString *relPathNoExtension = [relPath stringByDeletingPathExtension]; 43 | NSString *relPathPNG = [relPathNoExtension stringByAppendingPathExtension:@"png"]; 44 | NSString *outputPath = [outputDir stringByAppendingPathComponent:relPathPNG]; 45 | CGImageRef image = [SVGUtil imageWithSVGFile:inputPath 46 | size:kCanvasSize]; 47 | [SVGUtil writeImage:image toPNGFile:outputPath]; 48 | CGImageRelease(image); 49 | } 50 | } 51 | } 52 | 53 | int main(int argc, const char * argv[]) { 54 | @autoreleasepool { 55 | NSString *inputDir = @"/tmp/SVG/TestData"; 56 | NSString *outputDir = @"/tmp/SVG/Output"; 57 | RenderSVGFiles(inputDir, outputDir); 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /Apps/CommandLineRenderer/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | 19 | #include "MetroSVG/MetroSVG.h" 20 | 21 | int main(int argc, const char *argv[]) { 22 | int status = 0; 23 | MSCDocument *document = 0; 24 | CGImageRef image = 0; 25 | CGImageDestinationRef dest = 0; 26 | 27 | do { 28 | if (argc < 3) { 29 | status = 4; 30 | fprintf(stderr, "Too few arguments.\n"); 31 | break; 32 | } 33 | 34 | NSString *inputFile = [NSString stringWithCString:argv[1] 35 | encoding:NSUTF8StringEncoding]; 36 | NSData *data = [NSData dataWithContentsOfFile:inputFile]; 37 | if (!data) { 38 | status = 3; 39 | fprintf(stderr, "Can't read input.\n"); 40 | break; 41 | } 42 | 43 | document = MSCDocumentCreateFromData([data bytes], [data length], NULL); 44 | if (!document) { 45 | status = 1; 46 | fprintf(stderr, "Error in parsing SVG.\n"); 47 | break; 48 | } 49 | 50 | image = MSCDocumentCreateCGImage(document, MSCDocumentGetImageSize(document), NULL); 51 | if (!image) { 52 | status = 1; 53 | fprintf(stderr, "Error in parsing SVG.\n"); 54 | break; 55 | } 56 | 57 | NSString *outputFile = [NSString stringWithCString:argv[2] 58 | encoding:NSUTF8StringEncoding]; 59 | NSURL *outputURL = [NSURL fileURLWithPath:outputFile]; 60 | dest = CGImageDestinationCreateWithURL((__bridge CFURLRef)outputURL, 61 | kUTTypePNG, 62 | 1, 63 | NULL); 64 | CGImageDestinationAddImage(dest, image, NULL); 65 | if (!CGImageDestinationFinalize(dest)) { 66 | status = 2; 67 | fprintf(stderr, "Can't write output.\n"); 68 | break; 69 | } 70 | } while (0); 71 | 72 | if (document) MSCDocumentDelete(document); 73 | if (image) CGImageRelease(image); 74 | if (dest) CFRelease(dest); 75 | 76 | return status; 77 | } 78 | -------------------------------------------------------------------------------- /MetroSVG/Internal/LoggingUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace metrosvg { 26 | namespace internal { 27 | 28 | class LogArg; 29 | 30 | std::string FormatArgs(); 31 | std::string FormatArgs(const LogArg &arg1); 32 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2); 33 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 34 | const LogArg &arg3); 35 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 36 | const LogArg &arg3, const LogArg &arg4); 37 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 38 | const LogArg &arg3, const LogArg &arg4, 39 | const LogArg &arg5); 40 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 41 | const LogArg &arg3, const LogArg &arg4, 42 | const LogArg &arg5, const LogArg &arg6); 43 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 44 | const LogArg &arg3, const LogArg &arg4, 45 | const LogArg &arg5, const LogArg &arg6, 46 | const LogArg &arg7); 47 | 48 | template 49 | std::string FormatValue(T value) { 50 | std::stringstream ss; 51 | ss << value; 52 | return ss.str(); 53 | } 54 | 55 | template<> 56 | std::string FormatValue(std::nullptr_t value); 57 | 58 | template<> 59 | std::string FormatValue(CGAffineTransform value); 60 | 61 | template<> 62 | std::string FormatValue(CGAffineTransform *value); 63 | 64 | template<> 65 | std::string FormatValue(CGPoint value); 66 | 67 | template<> 68 | std::string FormatValue(CGRect value); 69 | 70 | template<> 71 | std::string FormatValue(CGLineCap value); 72 | 73 | template<> 74 | std::string FormatValue(CGLineJoin value); 75 | 76 | class LogArg { 77 | public: 78 | template 79 | LogArg(const T &value) 80 | : string_value_(FormatValue(value)) {} 81 | 82 | std::string string_value() const { 83 | return string_value_; 84 | } 85 | 86 | private: 87 | std::string string_value_; 88 | }; 89 | 90 | } // namespace internal 91 | } // namespace metrosvg 92 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Gradient.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/Gradient.h" 18 | 19 | #include "MetroSVG/Internal/StringPiece.h" 20 | #include "MetroSVG/Internal/TransformIterator.h" 21 | #include "MetroSVG/Internal/Utils.h" 22 | 23 | namespace metrosvg { 24 | namespace internal { 25 | 26 | Gradient::Gradient(Gradient::Type type_in, const StringMap &attributes) 27 | : type(type_in) { 28 | const std::string *id_value = FindValueOrNull(attributes, std::string("id")); 29 | if (id_value) { 30 | id = *id_value; 31 | } 32 | 33 | const std::string *gradient_transform_value = 34 | FindValueOrNull(attributes, std::string("gradientTransform")); 35 | if (gradient_transform_value) { 36 | StringPiece gradient_transform_value_sp(*gradient_transform_value); 37 | TransformIterator transform_iterator(&gradient_transform_value_sp); 38 | while (transform_iterator.Next()) { 39 | transforms.push_back(transform_iterator.transform()); 40 | } 41 | } 42 | 43 | const std::string *gradient_units_value = 44 | FindValueOrNull(attributes, std::string("gradientUnits")); 45 | if (gradient_units_value != nullptr && 46 | *gradient_units_value == "userSpaceOnUse") { 47 | units = kUnitsUserSpaceOnUse; 48 | } else { 49 | units = kUnitsObjectBoundingBox; 50 | } 51 | } 52 | 53 | CGGradientRef CreateCGGradient(const Gradient &gradient) { 54 | size_t stop_count = gradient.stops.size(); 55 | std::vector components(stop_count * 4); 56 | std::vector locations(stop_count); 57 | for (size_t i = 0; i < stop_count; ++i) { 58 | GradientStop stop = gradient.stops[i]; 59 | components[4 * i] = stop.color.red(); 60 | components[4 * i + 1] = stop.color.green(); 61 | components[4 * i + 2] = stop.color.blue(); 62 | components[4 * i + 3] = stop.opacity; 63 | locations[i] = stop.offset; 64 | } 65 | CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); 66 | CGGradientRef cg_gradient = 67 | CGGradientCreateWithColorComponents(color_space, 68 | components.data(), 69 | locations.data(), 70 | stop_count); 71 | CGColorSpaceRelease(color_space); 72 | return cg_gradient; 73 | } 74 | 75 | } // namespace internal 76 | } // namespace metrosvg 77 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleIteratorTest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #include "MetroSVG/Internal/StyleIterator.h" 20 | 21 | using namespace metrosvg::internal; 22 | 23 | @interface StyleIteratorTest : XCTestCase 24 | @end 25 | 26 | @implementation StyleIteratorTest 27 | 28 | - (void)test_Success_WithoutTrailingSemicolon { 29 | StyleIterator iter(new StringPiece("prop1:value1;prop2:value2"), 30 | { std::string("prop1"), std::string("prop2") }); 31 | XCTAssertTrue(iter.Next()); 32 | XCTAssertTrue(iter.property() == "prop1"); 33 | XCTAssertTrue(iter.value() == "value1", 34 | @"%s", iter.value().as_std_string().c_str()); 35 | 36 | XCTAssertTrue(iter.Next()); 37 | XCTAssertTrue(iter.property() == "prop2"); 38 | XCTAssertTrue(iter.value() == "value2", 39 | @"%s", iter.value().as_std_string().c_str()); 40 | 41 | XCTAssertFalse(iter.Next()); 42 | } 43 | 44 | - (void)test_Success_WithTrailingSemicolon { 45 | StyleIterator iter(new StringPiece("prop1:value1;prop2:value2;"), 46 | { std::string("prop1"), std::string("prop2") }); 47 | XCTAssertTrue(iter.Next()); 48 | XCTAssertTrue(iter.property() == "prop1"); 49 | XCTAssertTrue(iter.value() == "value1", @"%s", 50 | iter.value().as_std_string().c_str()); 51 | 52 | XCTAssertTrue(iter.Next()); 53 | XCTAssertTrue(iter.property() == "prop2"); 54 | XCTAssertTrue(iter.value() == "value2", @"%s", 55 | iter.value().as_std_string().c_str()); 56 | 57 | XCTAssertFalse(iter.Next()); 58 | } 59 | 60 | - (void)test_Success_Whitespace { 61 | StyleIterator iter(new StringPiece(" prop1 : value1 ; prop2 : value2 "), 62 | { std::string("prop1"), std::string("prop2") }); 63 | XCTAssertTrue(iter.Next()); 64 | XCTAssertTrue(iter.property() == "prop1", @"%s was not equal to %s", 65 | iter.property().as_std_string().c_str(), "prop1"); 66 | XCTAssertTrue(iter.value() == "value1", @"%s was not equal to %s", 67 | iter.value().as_std_string().c_str(), "value1"); 68 | 69 | XCTAssertTrue(iter.Next()); 70 | XCTAssertTrue(iter.property() == "prop2"); 71 | XCTAssertTrue(iter.value() == "value2", @"%s", 72 | iter.value().as_std_string().c_str()); 73 | 74 | XCTAssertFalse(iter.Next()); 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /MetroSVG/Internal/BasicTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | namespace metrosvg { 26 | namespace internal { 27 | 28 | typedef std::map StringMap; 29 | 30 | // RgbColor represents a color in the RGB color space. 31 | // Intensity of each color component takes a value from 0.0 to 1.0. 32 | class RgbColor { 33 | public: 34 | RgbColor() 35 | : red_(0), green_(0), blue_(0) {} 36 | 37 | RgbColor(CGFloat red, CGFloat green, CGFloat blue); 38 | 39 | CGFloat red() const { return red_; } 40 | void set_red(CGFloat red) { red_ = red; } 41 | 42 | CGFloat green() const { return green_; } 43 | void set_green(CGFloat green) { green_ = green; } 44 | 45 | CGFloat blue() const { return blue_; } 46 | void set_blue(CGFloat blue) { blue_ = blue; } 47 | 48 | private: 49 | CGFloat red_; 50 | CGFloat green_; 51 | CGFloat blue_; 52 | }; 53 | 54 | struct Length { 55 | enum Unit { 56 | kUnitNone = 0, 57 | 58 | kUnitCm, 59 | kUnitEm, 60 | kUnitEx, 61 | kUnitIn, 62 | kUnitMm, 63 | kUnitPc, 64 | kUnitPercent, 65 | kUnitPt, 66 | kUnitPx, 67 | }; 68 | 69 | CGFloat value; 70 | Unit unit; 71 | 72 | Length() 73 | : value(0), unit(kUnitNone) {} 74 | Length(CGFloat value_in, Unit unit_in) 75 | : value(value_in), unit(unit_in) {} 76 | }; 77 | 78 | struct LineDash { 79 | std::vector dash_values; 80 | CGFloat phase; 81 | 82 | LineDash() 83 | : phase(0) {} 84 | }; 85 | 86 | enum FillRule { 87 | kFillRuleNonZero, 88 | kFillRuleEvenOdd, 89 | }; 90 | 91 | // Parsed value of the preserveAspectRatio attribute. 92 | struct PreserveAspectRatio { 93 | bool defer; 94 | bool no_alignment; // true if alignment value is "none". 95 | 96 | enum Alignment { 97 | kMin, 98 | kMid, 99 | kMax, 100 | }; 101 | Alignment x_alignment; // must be kMid if no_alignment is true. 102 | Alignment y_alignment; // must be kMid if no_alignment is true. 103 | 104 | enum MeetOrSlice { 105 | kMeet, 106 | kSlice, 107 | }; 108 | MeetOrSlice meet_or_slice; 109 | 110 | static PreserveAspectRatio default_value() { 111 | PreserveAspectRatio aspect_ratio; 112 | aspect_ratio.defer = false; 113 | aspect_ratio.no_alignment = false; 114 | aspect_ratio.x_alignment = kMid; 115 | aspect_ratio.y_alignment = kMid; 116 | aspect_ratio.meet_or_slice = kMeet; 117 | return aspect_ratio; 118 | } 119 | }; 120 | 121 | } // namespace internal 122 | } // namespace metrosvg 123 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/DTDVerifier.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/BatchRenderer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/StyleChecker.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/CommandLineRenderer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/MetroSVG-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MetroSVG.xcodeproj/xcshareddata/xcschemes/MetroSVG-OS-X.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /MetroSVG/Internal/PathDataIterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | #include "MetroSVG/Internal/StringPiece.h" 22 | 23 | namespace metrosvg { 24 | namespace internal { 25 | 26 | class StringPiece; 27 | 28 | // PathCommandType represents the path commands defined by the SVG 29 | // specification. 30 | // 31 | // NOTE: The client of PathDataIterator doesn't need distinction between 32 | // some of these commands. Maybe consolidating these values will make the 33 | // class interface cleaner and consistent. 34 | enum PathCommandType { 35 | kPathCommandTypeMoveTo = 0, 36 | kPathCommandTypeLineTo = 1, 37 | kPathCommandTypeHorizontalLineTo = 2, 38 | kPathCommandTypeVerticalLineTo = 3, 39 | kPathCommandTypeCubicBezier = 4, 40 | kPathCommandTypeShorthandCubicBezier = 5, 41 | kPathCommandTypeQuadBezier = 6, 42 | kPathCommandTypeShorthandQuadBezier = 7, 43 | kPathCommandTypeEllipticalArc = 8, 44 | kPathCommandTypeClosePath = 9, 45 | }; 46 | 47 | enum PathDataFormat { 48 | kPathDataFormatPoints = 0, // polyline or polygon 49 | kPathDataFormatPath = 1, // path 50 | }; 51 | 52 | class PathDataIterator { 53 | public: 54 | // format defines whether is a path with full path commands, or a points 55 | // element with simply x,y pairs. 56 | // implicit_close means that an implicit ClosePath command should be appended 57 | // to the commands found in the data. 58 | PathDataIterator(const char *data, PathDataFormat format, 59 | bool implicit_close); 60 | 61 | bool Next(); 62 | 63 | PathCommandType command_type() const { return command_type_; } 64 | CGPoint point() const { return point_; } 65 | CGPoint control_point1() const { return control_point1_; } 66 | CGPoint control_point2() const { return control_point2_; } 67 | // Those four functions are for drawing arcs. 68 | CGFloat arc_radius_x() const { return arc_radius_x_; } 69 | CGFloat arc_radius_y() const { return arc_radius_y_; } 70 | bool large_arc() const { return large_arc_; } 71 | bool sweep() const { return sweep_; } 72 | CGFloat rotation() const { return rotation_; } 73 | 74 | private: 75 | StringPiece s_; 76 | bool implicit_close_, large_arc_, sweep_; 77 | PathDataFormat format_; 78 | PathCommandType command_type_; 79 | CGPoint point_, control_point1_, control_point2_; 80 | CGFloat arc_radius_x_; 81 | CGFloat arc_radius_y_; 82 | CGFloat rotation_; 83 | 84 | // For interpreting paths. 85 | bool is_first_command_; 86 | bool absolute_; // Always true for polygon/polyline. 87 | bool shown_close_path_; // Always true for polygon/polyline. 88 | CGPoint subpath_start_point_; 89 | // This has a valid value only when is_first_command_ is true. 90 | PathCommandType last_command_type_; 91 | 92 | bool ParseSingleCommandForPath(); 93 | bool ParseSingleCommandForPoints(); 94 | 95 | // The following routines assume the command character has already been 96 | // consumed from the StringPiece. 97 | 98 | // For ParseMoveAndLineCommand, command_type must be one of MoveTo, LineTo, 99 | // HorizontalLineTo, or VerticalLineTo. 100 | bool ParseMoveAndLineCommand(enum PathCommandType command_type); 101 | bool ParseCubicBezierCommand(); 102 | bool ParseShorthandCubicBezierCommand(); 103 | bool ParseQuadBezierCommand(); 104 | bool ParseShorthandQuadBezierCommand(); 105 | bool ParseEllipticalArcCommand(); 106 | }; 107 | 108 | } // namespace internal 109 | } // namespace metrosvg 110 | -------------------------------------------------------------------------------- /AcceptanceTest/AcceptanceTest.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | #import 19 | 20 | #import "Apps/Common/SVGUtil.h" 21 | #include "MetroSVG/MetroSVG.h" 22 | 23 | static const CGSize kCanvasSize = {640, 640}; 24 | 25 | NSString *FullFilePath(NSString *rootDir, NSString *baseName, NSString *extension) { 26 | NSString *dir = [rootDir stringByAppendingPathComponent:baseName]; 27 | NSString *file = [dir stringByAppendingPathExtension:extension]; 28 | return file; 29 | } 30 | 31 | @interface AcceptanceTest : XCTestCase 32 | @end 33 | 34 | @implementation AcceptanceTest { 35 | NSFileManager *_fileManager; 36 | NSString *_inputSVGDir; 37 | NSString *_actualPNGDir; 38 | NSString *_goldenPNGDir; 39 | } 40 | 41 | - (void)setUp { 42 | [super setUp]; 43 | _fileManager = [NSFileManager defaultManager]; 44 | NSString *resourceDir = [NSBundle bundleForClass:[self class]].resourcePath; 45 | _inputSVGDir = [resourceDir stringByAppendingPathComponent:@"TestData"]; 46 | _actualPNGDir = [resourceDir stringByAppendingPathComponent:@"Actual"]; 47 | _goldenPNGDir = [resourceDir stringByAppendingPathComponent:@"Golden"]; 48 | 49 | // Reset the test environment. 50 | [_fileManager removeItemAtPath:_actualPNGDir error:nil]; 51 | [_fileManager createDirectoryAtPath:_actualPNGDir 52 | withIntermediateDirectories:YES 53 | attributes:nil 54 | error:nil]; 55 | } 56 | 57 | - (void)test { 58 | NSDirectoryEnumerator *enumerator = [_fileManager enumeratorAtPath:_goldenPNGDir]; 59 | NSString *relPath; 60 | NSInteger numberOfVerifiedFiles = 0; 61 | while (relPath = [enumerator nextObject]) { 62 | NSString *goldenPNGFile = [_goldenPNGDir stringByAppendingPathComponent:relPath]; 63 | BOOL isDirectory; 64 | [_fileManager fileExistsAtPath:goldenPNGFile isDirectory:&isDirectory]; 65 | if (isDirectory) { 66 | [_fileManager createDirectoryAtPath:[_actualPNGDir stringByAppendingPathComponent:relPath] 67 | withIntermediateDirectories:YES 68 | attributes:nil 69 | error:nil]; 70 | } else { 71 | [self verifyDataWithBaseName:[relPath stringByDeletingPathExtension]]; 72 | numberOfVerifiedFiles += 1; 73 | } 74 | } 75 | XCTAssertNotEqual(numberOfVerifiedFiles, 0, 76 | @"No file was verified. There should be a bug in the project configurations or " 77 | @"the runtime environment."); 78 | } 79 | 80 | - (void)verifyDataWithBaseName:(NSString *)baseName { 81 | // First render the input svg file and save the result as png. 82 | NSString *inputSVGFile = FullFilePath(_inputSVGDir, baseName, @"svg"); 83 | if (![_fileManager fileExistsAtPath:inputSVGFile]) { 84 | XCTFail(@"%@: nput SVG file doesn't exist.", baseName); 85 | return; 86 | } 87 | CGImageRef actualImage = [SVGUtil imageWithSVGFile:inputSVGFile size:kCanvasSize]; 88 | NSString *actualPNGFile = FullFilePath(_actualPNGDir, baseName, @"png"); 89 | [SVGUtil writeImage:actualImage toPNGFile:actualPNGFile]; 90 | CGImageRelease(actualImage); 91 | 92 | // Then, compare the actual result with the golden. 93 | NSData *actualPNGData = [NSData dataWithContentsOfFile:actualPNGFile]; 94 | NSString *goldenPNGFile = FullFilePath(_goldenPNGDir, baseName, @"png"); 95 | NSData *goldenPNGData = [NSData dataWithContentsOfFile:goldenPNGFile]; 96 | XCTAssert([actualPNGData isEqualToData:goldenPNGData], 97 | @"Detected diff between %@ and %@", 98 | actualPNGFile, 99 | goldenPNGFile); 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "MetroSVG/Internal/BasicTypes.h" 25 | #include "MetroSVG/Internal/Constants.h" 26 | #include "MetroSVG/MetroSVG.h" 27 | 28 | namespace metrosvg { 29 | namespace internal { 30 | 31 | // This function makes it easier to use unique_ptr with a custom deleter. 32 | template 33 | std::unique_ptr MakeUniquePtr(T *t, Deleter deleter) { 34 | std::unique_ptr p(t, deleter); 35 | return p; 36 | } 37 | 38 | template 39 | const ValueType *FindValueOrNull(const std::map &map, 40 | const KeyType &key) { 41 | typename std::map::const_iterator iter = map.find(key); 42 | if (iter == map.end()) { 43 | return NULL; 44 | } else { 45 | return &(iter->second); 46 | } 47 | } 48 | 49 | // This function will look for the given key in the given map. 50 | // If it is present, it will attempt to parse the value of the 51 | // key as a floating-point number. 52 | // If the key is present and the parse is successful, it will 53 | // set the value pointed to by |out_float| and return true. 54 | // If the key is not present or if the value does not represent 55 | // a floating-point number, it will return false and the value 56 | // pointed to by |out_float| will be unchanged. 57 | bool FloatValueForKey(const StringMap &map, 58 | const std::string &key, 59 | CGFloat *out_float); 60 | 61 | bool LengthValueForKey(const StringMap &map, 62 | const std::string &key, 63 | Length *out_length); 64 | 65 | static inline CGFloat ToRadians(CGFloat degrees) { 66 | return degrees * kPi / 180.f; 67 | } 68 | 69 | static inline CGFloat ClampToUnitRange(CGFloat value) { 70 | return std::fmin(std::fmax(value, 0.f), 1.f); 71 | } 72 | 73 | // Converts representaion of an arc in start point, 74 | // end point and flags that is used by SVG to one by center, 75 | // Radius, start angle and end angle that is used by Core Graphics. 76 | // Angles are in radians. 77 | // Returns false in case of bad input. 78 | bool SvgArcToCgArc(CGPoint start_point, 79 | CGPoint end_point, 80 | bool large_arc, 81 | bool sweep, 82 | CGFloat *radius, 83 | CGPoint *center, 84 | CGFloat *start_angle, 85 | CGFloat *end_angle); 86 | 87 | // Test that angle a1 is close to angle a2. 88 | // When the difference between a1 and a2 is more than 2 * pi, 89 | // a1 is shifted to a point near a2 by multiples of 2 * pi. 90 | bool AreAnglesClose(CGFloat a1, CGFloat a2, CGFloat accuracy); 91 | 92 | // Returns an affine transform that maps a given rectangle to 93 | // a unit rectangle located at the origin ((0, 0), (1, 1)). 94 | CGAffineTransform CGAffineTransformToNormalizeRect(CGRect rect); 95 | 96 | // Returns a transform to establish a new coordinate system 97 | // as specified by |aspect_ratio| and |view_box| within the |target_viewport| 98 | // described by the current coordinate system. 99 | // NOTE: This method currently only supports view box and viewport 100 | // place at the origin. 101 | // TODO: Implement this missing feature. 102 | CGAffineTransform 103 | CGAffineTransformForPreserveAspectRatio(PreserveAspectRatio aspect_ratio, 104 | CGRect view_box, 105 | CGRect target_viewport); 106 | 107 | // Returns a unit-less length value measured in the user space evaluating 108 | // a given length value with a unit. Currently, only conversion from a 109 | // percentage, e.g., 65% -> 0.65, is supported. 110 | CGFloat EvaluateLength(Length length); 111 | 112 | } // namespace internal 113 | } // namespace metrosvg 114 | -------------------------------------------------------------------------------- /MetroSVG/Internal/TransformIterator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/TransformIterator.h" 18 | 19 | #include 20 | 21 | #include "MetroSVG/Internal/BasicValueParsers.h" 22 | #include "MetroSVG/Internal/Macros.h" 23 | #include "MetroSVG/Internal/StringPiece.h" 24 | #include "MetroSVG/Internal/Utils.h" 25 | 26 | namespace metrosvg { 27 | namespace internal { 28 | 29 | TransformIterator::TransformIterator(StringPiece *s) 30 | : s_(s), is_first(true) {} 31 | 32 | bool TransformIterator::Next() { 33 | StringPiece s_copy = *s_; 34 | ConsumeWhitespace(&s_copy); 35 | if (!is_first) { 36 | ConsumeTransformDelimeters(&s_copy); 37 | } 38 | if (s_copy.length() == 0) { 39 | return false; 40 | } 41 | if (ConsumeString(&s_copy, "matrix", true)) { 42 | CGFloat elements[6]; 43 | if (!ConsumeParenthesizedFloats(&s_copy, 6, elements)) { 44 | return false; 45 | } 46 | transform_ = CGAffineTransformMake(elements[0], elements[1], elements[2], 47 | elements[3], elements[4], elements[5]); 48 | } else if (ConsumeString(&s_copy, "translate", true)) { 49 | CGFloat elements[2]; 50 | if (ConsumeParenthesizedFloats(&s_copy, 2, elements)) { 51 | transform_ = CGAffineTransformMakeTranslation(elements[0], elements[1]); 52 | } else if (ConsumeParenthesizedFloats(&s_copy, 1, elements)) { 53 | transform_ = CGAffineTransformMakeTranslation(elements[0], 0.); 54 | } else { 55 | return false; 56 | } 57 | } else if (ConsumeString(&s_copy, "scale", true)) { 58 | CGFloat elements[2]; 59 | if (ConsumeParenthesizedFloats(&s_copy, 2, elements)) { 60 | transform_ = CGAffineTransformMakeScale(elements[0], elements[1]); 61 | } else if (ConsumeParenthesizedFloats(&s_copy, 1, elements)) { 62 | transform_ = CGAffineTransformMakeScale(elements[0], elements[0]); 63 | } else { 64 | return false; 65 | } 66 | } else if (ConsumeString(&s_copy, "rotate", true)) { 67 | CGFloat elements[3]; 68 | if (ConsumeParenthesizedFloats(&s_copy, 3, elements)) { 69 | CGAffineTransform translate = 70 | CGAffineTransformMakeTranslation(elements[1], elements[2]); 71 | CGAffineTransform rotate = 72 | CGAffineTransformMakeRotation(ToRadians(elements[0])); 73 | CGAffineTransform translate_back = 74 | CGAffineTransformMakeTranslation(-elements[1], -elements[2]); 75 | transform_ = 76 | CGAffineTransformConcat(translate, 77 | CGAffineTransformConcat(rotate, 78 | translate_back)); 79 | } else if (ConsumeParenthesizedFloats(&s_copy, 1, elements)) { 80 | transform_ = CGAffineTransformMakeRotation(ToRadians(elements[0])); 81 | } else { 82 | return false; 83 | } 84 | } else if (ConsumeString(&s_copy, "skewX", true)) { 85 | CGFloat skew_angle; 86 | if (!ConsumeParenthesizedFloats(&s_copy, 1, &skew_angle)) { 87 | return false; 88 | } 89 | CGFloat skew_angle_radians = ToRadians(skew_angle); 90 | transform_ = CGAffineTransformMake(1, 0, tan(skew_angle_radians), 1, 0, 0); 91 | } else if (ConsumeString(&s_copy, "skewY", true)) { 92 | CGFloat skew_angle; 93 | if (!ConsumeParenthesizedFloats(&s_copy, 1, &skew_angle)) { 94 | return false; 95 | } 96 | CGFloat skew_angle_radians = ToRadians(skew_angle); 97 | transform_ = CGAffineTransformMake(1, tan(skew_angle_radians), 0, 1, 0, 0); 98 | } else { 99 | return false; 100 | } 101 | s_->Advance(s_copy.begin() - s_->begin()); 102 | is_first = false; 103 | return true; 104 | } 105 | 106 | void TransformIterator::ConsumeTransformDelimeters(StringPiece *s) const { 107 | while (true) { 108 | ConsumeWhitespace(s); 109 | if (s->length() > 0 && (*s)[0] == ',') { 110 | s->Advance(1); 111 | } else { 112 | break; 113 | } 114 | } 115 | ConsumeWhitespace(s); 116 | } 117 | 118 | } // namespace internal 119 | } // namespace metrosvg 120 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Document.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/Document.h" 18 | 19 | #include "MetroSVG/Internal/BasicValueParsers.h" 20 | #include "MetroSVG/Internal/Renderer.h" 21 | #include "MetroSVG/Internal/StringPiece.h" 22 | #include "MetroSVG/Internal/Utils.h" 23 | 24 | namespace metrosvg { 25 | namespace internal { 26 | 27 | // Get size of the outmost svg element in given svg data. 28 | bool GetImageMetaDataFromSVGData(const char *data, 29 | size_t data_length, 30 | CGSize *image_size, 31 | CGRect *view_box) { 32 | // Defaults to 100% per spec but we don't support length units yet. 33 | // http://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute 34 | Length width(100.f, Length::kUnitNone); 35 | Length height(100.f, Length::kUnitNone); 36 | 37 | xmlTextReader *reader = 38 | xmlReaderForMemory(data, static_cast(data_length), NULL, NULL, 0); 39 | bool success = true; 40 | int last_xml_status; 41 | while ((last_xml_status = xmlTextReaderRead(reader)) > 0) { 42 | int node_type = xmlTextReaderNodeType(reader); 43 | StringPiece elem_name = 44 | reinterpret_cast(xmlTextReaderConstName(reader)); 45 | if (node_type == XML_READER_TYPE_ELEMENT && elem_name == "svg") { 46 | while (xmlTextReaderMoveToNextAttribute(reader)) { 47 | StringPiece attr_name = 48 | reinterpret_cast(xmlTextReaderConstName(reader)); 49 | StringPiece attr_value = 50 | reinterpret_cast(xmlTextReaderConstValue(reader)); 51 | if (attr_name == "width") { 52 | if (!ParseLength(attr_value, &width)) { 53 | success = false; 54 | } 55 | } else if (attr_name == "height") { 56 | if (!ParseLength(attr_value, &height)) { 57 | success = false; 58 | } 59 | } else if (attr_name == "viewBox") { 60 | CGFloat values[4] = {0, 0, 0, 0}; 61 | if (ParseFloats(attr_value, 4, values)) { 62 | *view_box = 63 | CGRectMake(values[0], values[1], values[2], values[3]); 64 | } 65 | } 66 | } 67 | break; 68 | } 69 | } 70 | xmlFreeTextReader(reader); 71 | 72 | if (last_xml_status < 0) { 73 | success = false; 74 | } 75 | 76 | if (success) { 77 | *image_size = CGSizeMake(width.value, height.value); 78 | return true; 79 | } else { 80 | return false; 81 | } 82 | } 83 | 84 | } // namespace internal 85 | } // namespace metrosvg 86 | 87 | using metrosvg::internal::GetImageMetaDataFromSVGData; 88 | using metrosvg::internal::Renderer; 89 | 90 | MSCDocument *MSCDocumentCreateFromData(const char *data, 91 | size_t length, 92 | const char *url) { 93 | CGSize size = CGSizeZero; 94 | CGRect view_box = CGRectNull; 95 | if (!GetImageMetaDataFromSVGData(data, length, &size, &view_box)) { 96 | return NULL; 97 | } 98 | 99 | MSCDocument *document = new MSCDocument; 100 | document->data = data; 101 | document->data_length = length; 102 | document->url = url; 103 | document->size = size; 104 | document->view_box = view_box; 105 | return document; 106 | } 107 | 108 | void MSCDocumentDelete(MSCDocument *document) { 109 | delete document; 110 | } 111 | 112 | CGImageRef MSCDocumentCreateCGImage(MSCDocument *document, 113 | CGSize canvas_size, 114 | const MSCStyleSheet *style_sheet) { 115 | Renderer renderer; 116 | return renderer.CreateCGImageFromMSCDocument(document, 117 | canvas_size, 118 | style_sheet); 119 | } 120 | 121 | CGSize MSCDocumentGetImageSize(const MSCDocument *document) { 122 | return document->size; 123 | } 124 | 125 | CGRect MSCDocumentGetImageViewBox(const MSCDocument *document) { 126 | return document->view_box; 127 | } 128 | -------------------------------------------------------------------------------- /MetroSVG/Internal/LoggingUtils.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/LoggingUtils.h" 18 | 19 | #include 20 | 21 | namespace metrosvg { 22 | namespace internal { 23 | 24 | std::string FormatArgs() { 25 | return ""; 26 | } 27 | 28 | std::string FormatArgs(const LogArg &arg1) { 29 | return arg1.string_value(); 30 | } 31 | 32 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2) { 33 | std::stringstream ss; 34 | ss << arg1.string_value() << ", " << arg2.string_value(); 35 | return ss.str(); 36 | } 37 | 38 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 39 | const LogArg &arg3) { 40 | std::stringstream ss; 41 | ss << arg1.string_value() << ", " << arg2.string_value() << ", " 42 | << arg3.string_value(); 43 | return ss.str(); 44 | } 45 | 46 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 47 | const LogArg &arg3, const LogArg &arg4) { 48 | std::stringstream ss; 49 | ss << arg1.string_value() << ", " << arg2.string_value() << ", " 50 | << arg3.string_value() << ", " << arg4.string_value(); 51 | return ss.str(); 52 | } 53 | 54 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 55 | const LogArg &arg3, const LogArg &arg4, 56 | const LogArg &arg5) { 57 | std::stringstream ss; 58 | ss << arg1.string_value() << ", " << arg2.string_value() << ", " 59 | << arg3.string_value() << ", " << arg4.string_value() << ", " 60 | << arg5.string_value(); 61 | return ss.str(); 62 | } 63 | 64 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 65 | const LogArg &arg3, const LogArg &arg4, 66 | const LogArg &arg5, const LogArg &arg6) { 67 | std::stringstream ss; 68 | ss << arg1.string_value() << ", " << arg2.string_value() << ", " 69 | << arg3.string_value() << ", " << arg4.string_value() << ", " 70 | << arg5.string_value() << ", " << arg6.string_value(); 71 | return ss.str(); 72 | } 73 | 74 | std::string FormatArgs(const LogArg &arg1, const LogArg &arg2, 75 | const LogArg &arg3, const LogArg &arg4, 76 | const LogArg &arg5, const LogArg &arg6, 77 | const LogArg &arg7) { 78 | std::stringstream ss; 79 | ss << arg1.string_value() << ", " << arg2.string_value() << ", " 80 | << arg3.string_value() << ", " << arg4.string_value() << ", " 81 | << arg5.string_value() << ", " << arg6.string_value() << ", " 82 | << arg7.string_value(); 83 | return ss.str(); 84 | } 85 | 86 | template<> 87 | std::string FormatValue(std::nullptr_t value) { 88 | return "NULL"; 89 | } 90 | 91 | template<> 92 | std::string FormatValue(const CGAffineTransform value) { 93 | std::stringstream ss; 94 | ss << "(" << value.a << ", " << value.b << ", " 95 | << value.c << ", " << value.d << ", " 96 | << value.tx << ", " << value.ty << ")"; 97 | return ss.str(); 98 | } 99 | 100 | template<> 101 | std::string FormatValue(CGAffineTransform *value) { 102 | return FormatValue(*value); 103 | } 104 | 105 | template<> 106 | std::string FormatValue(const CGPoint value) { 107 | std::stringstream ss; 108 | ss << "(" << value.x << ", " << value.y << ")"; 109 | return ss.str(); 110 | } 111 | 112 | template<> 113 | std::string FormatValue(const CGRect value) { 114 | std::stringstream ss; 115 | ss << "(" << value.origin.x << ", " << value.origin.y << ", " 116 | << value.size.width << ", " << value.size.height << ")"; 117 | return ss.str(); 118 | } 119 | 120 | template<> 121 | std::string FormatValue(CGLineCap value) { 122 | switch (value) { 123 | case kCGLineCapButt: 124 | return "kCGLineCapButt"; 125 | case kCGLineCapRound: 126 | return "kCGLineCapRound"; 127 | case kCGLineCapSquare: 128 | return "kCGLineCapSquare"; 129 | } 130 | } 131 | 132 | template<> 133 | std::string FormatValue(CGLineJoin value) { 134 | switch (value) { 135 | case kCGLineJoinMiter: 136 | return "kCGLineJoinMiter"; 137 | case kCGLineJoinRound: 138 | return "kCGLineJoinRound"; 139 | case kCGLineJoinBevel: 140 | return "kCGLineJoinBevel"; 141 | } 142 | } 143 | 144 | } // namespace internal 145 | } // namespace metrosvg 146 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleSheet.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/StyleSheet.h" 18 | 19 | #include "MetroSVG/Internal/StringPiece.h" 20 | #include "MetroSVG/Internal/StyleIterator.h" 21 | 22 | MSCStyleSheet *MSCStyleSheetCreateWithData(const char *data, 23 | size_t data_length) { 24 | return metrosvg::internal::ParseStyleSheetData(data, data_length); 25 | } 26 | 27 | void MSCStyleSheetDelete(MSCStyleSheet *style_sheet) { 28 | delete style_sheet; 29 | } 30 | 31 | namespace metrosvg { 32 | namespace internal { 33 | 34 | // ParserState is state for parsing CSS. 35 | // At OUTSIDE_CONTENTS, before reading selector name and after reading "}". 36 | // At BEFORE_VALUE, after reading selector name and before reading "{". 37 | // At FINDING_VALUE, reading values between "{" and "}". 38 | enum ParserState { 39 | OUTSIDE_CONTENTS, 40 | BEFORE_VALUE, 41 | FINDING_VALUE, 42 | }; 43 | 44 | MSCStyleSheet *ParseStyleSheetData(const char *data, 45 | size_t data_length) { 46 | ParserState state = OUTSIDE_CONTENTS; 47 | std::string selector_name; 48 | std::string selector_value; 49 | std::vector> selector_data; 50 | std::unordered_set supported_styles; 51 | supported_styles.insert("fill"); 52 | supported_styles.insert("stop-color"); 53 | supported_styles.insert("stroke"); 54 | supported_styles.insert("stroke-width"); 55 | std::unique_ptr style_sheet(new MSCStyleSheet); 56 | 57 | for (size_t i = 0; i < data_length; i++) { 58 | switch (state) { 59 | case OUTSIDE_CONTENTS: 60 | switch (data[i]) { 61 | case '.': 62 | while (('a' <= data[i + 1] && data[i + 1] <= 'z') || 63 | ('A' <= data[i + 1] && data[i + 1] <= 'Z') || 64 | ('0' <= data[i + 1] && data[i + 1] <= '9') || 65 | data[i + 1] == '-' || data[i + 1] == '_') { 66 | selector_name += data[(i++) + 1]; 67 | } 68 | state = BEFORE_VALUE; 69 | break; 70 | case '\n': 71 | case '\t': 72 | case ' ': 73 | break; 74 | default: 75 | return NULL; 76 | } 77 | break; 78 | case BEFORE_VALUE: 79 | switch (data[i]) { 80 | case '{': 81 | state = FINDING_VALUE; 82 | break; 83 | case ' ': 84 | break; 85 | default: 86 | return NULL; 87 | } 88 | break; 89 | case FINDING_VALUE: 90 | switch (data[i]) { 91 | case '}': { 92 | StringPiece sp = StringPiece(selector_value); 93 | StyleIterator style_iter(&sp, supported_styles); 94 | while (style_iter.Next()) { 95 | const std::string style_property = 96 | style_iter.property().as_std_string(); 97 | const std::string style_value = 98 | style_iter.value().as_std_string(); 99 | selector_data.push_back(std::pair(style_property, 101 | style_value)); 102 | } 103 | style_sheet->entry.insert(std::make_pair(selector_name, 104 | selector_data)); 105 | selector_data.clear(); 106 | selector_name = ""; 107 | selector_value = ""; 108 | state = OUTSIDE_CONTENTS; 109 | break; 110 | } 111 | case ' ': 112 | case '\n': 113 | break; 114 | default: 115 | selector_value += data[i]; 116 | break; 117 | } 118 | break; 119 | } 120 | } 121 | return style_sheet.release(); 122 | } 123 | 124 | void MSCStyleSheetMerge(const MSCStyleSheet &source, 125 | MSCStyleSheet *dest) { 126 | if (dest == NULL) { 127 | return; 128 | } 129 | for (auto source_item : source.entry) { 130 | auto dest_item = dest->entry.find(source_item.first); 131 | if (dest_item == dest->entry.end()) { 132 | dest->entry.insert(source_item); 133 | } else { 134 | dest_item->second.insert(dest_item->second.end(), 135 | source_item.second.begin(), 136 | source_item.second.end()); 137 | } 138 | } 139 | } 140 | 141 | } // namespace internal 142 | } // namespace metrosvg 143 | -------------------------------------------------------------------------------- /MetroSVG/Internal/BasicValueParsers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "MetroSVG/Internal/BasicTypes.h" 26 | #include "MetroSVG/Internal/StringPiece.h" 27 | // Must include this here to get default value of SVG_COLOR_KEYWORD_SUPPORT. 28 | #include "MetroSVG/Internal/SVGStandardColor.h" 29 | 30 | namespace metrosvg { 31 | namespace internal { 32 | 33 | // There are conventions for naming functions in this file. 34 | // 35 | // A function named "Consume" takes a string pointer. It returns 36 | // whether or not a token of the given type was found at the beginning of 37 | // the string. Except where noted, it ignores any whitespace found before 38 | // the token. If the token was found, it advances the string pointer past 39 | // the token and returns the parsed value of the token via an argument. 40 | // 41 | // A function named "Parse" takes a string by value. It returns 42 | // whether or not the string consists entirely of the given token. Except 43 | // where noted, it ignores any whitespace found before the token. If the 44 | // token was found, it returns the parsed value of the token via an argument. 45 | 46 | // Consumes a minus sign "-". 47 | bool ConsumeSign(StringPiece *s); 48 | 49 | // Consumes a non-negative decimal integer value, e.g., "0", "439". 50 | bool ConsumeDecimalInt(StringPiece *s, int *n); 51 | 52 | // Consumes a non-negative decimal integer value followed by a percent 53 | // symbol, e.g., "0%", "12%", "100%", "1249%". 54 | bool ConsumeDecimalIntPercent(StringPiece *s, int *n); 55 | 56 | // Consumes a hexadecimal integer of the given width, e.g, "1fd0", "deadbeaf". 57 | // If a zero or negative width is given, parses as many hex digits as 58 | // available. 59 | bool ConsumeHexInt(StringPiece *s, int width, int *n); 60 | 61 | // Consumes or parses a float value, e.g., "0.", "13.3", "-.2", "9.41-e3". 62 | bool ConsumeFloat(StringPiece *s, CGFloat *f); 63 | bool ParseFloat(StringPiece s, CGFloat *f); 64 | 65 | // Consumes or parses the given number of floats separated by commas, 66 | // e.g., "-0.5., 65.2". 67 | bool ConsumeFloats(StringPiece *s, int count, CGFloat *farray); 68 | bool ParseFloats(StringPiece s, int count, CGFloat *farray); 69 | 70 | // Parses the given number of floats surrounded by parentheses, 71 | // e.g., "(-0.5., 65.2)". 72 | bool ConsumeParenthesizedFloats(StringPiece *s, 73 | int count, 74 | CGFloat *farray); 75 | 76 | // Consumes or parses a float value followed by a length unit, 77 | // e.g., "5.6in", "-12px". 78 | bool ConsumeLength(StringPiece *s, Length *length); 79 | bool ParseLength(StringPiece s, Length *length); 80 | 81 | // Consumes or parses a list of lengths. 82 | bool ConsumeLengths(StringPiece *s, std::vector *lengths); 83 | bool ParseLengths(StringPiece s, std::vector *lengths); 84 | 85 | // PeekAlpha returns whether the first char in the string is an English 86 | // alphabetical character. It does not ignore whitespace. If the return 87 | // value is true, it will return that character via the argument. 88 | bool PeekAlpha(StringPiece s, char *c); 89 | 90 | // ConsumeAlpha returns the same value as PeekAlpha, but also advances 91 | // the string past the character if the return value is true. 92 | bool ConsumeAlpha(StringPiece *s, char *c); 93 | 94 | // Consumes a string value. It does not ignore whitespace. 95 | bool ConsumeString(StringPiece *s, const char *string, bool case_sensitive); 96 | 97 | // Consumes a single-digit flag value used by elliptical arcs. 98 | bool ConsumeFlag(StringPiece *s, bool *flag); 99 | 100 | // Consumes or parses a color value. Values allowed for color can be found on 101 | // http://www.w3.org/TR/SVG11/types.html#DataTypeColor 102 | bool ConsumeRgbColor(StringPiece *s, RgbColor *rgb); 103 | bool ParseRgbColor(StringPiece s, RgbColor *rgb); 104 | 105 | bool ConsumeWhitespace(StringPiece *s); 106 | StringPiece TrimTrailingWhitespace(const StringPiece &s); 107 | 108 | bool ConsumeIri(StringPiece *s, StringPiece *iri); 109 | bool ParseIri(StringPiece s, StringPiece *iri); 110 | 111 | // Consumes or parses a value of the preserveAspectRatio attribute. 112 | bool ConsumePreserveAspectRatio(StringPiece *s, 113 | PreserveAspectRatio *aspect_ratio); 114 | bool ParsePreserveAspectRatio(StringPiece s, 115 | PreserveAspectRatio *aspect_ratio); 116 | 117 | bool ConsumeNumberDelimiter(StringPiece *s); 118 | 119 | } // namespace internal 120 | } // namespace metrosvg 121 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Utils.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/Utils.h" 18 | 19 | #include 20 | 21 | #include "MetroSVG/Internal/BasicValueParsers.h" 22 | #include "MetroSVG/Internal/Constants.h" 23 | #include "MetroSVG/Internal/StringPiece.h" 24 | 25 | namespace metrosvg { 26 | namespace internal { 27 | 28 | bool FloatValueForKey(const StringMap &map, 29 | const std::string &key, 30 | CGFloat *out_float) { 31 | const std::string *value = FindValueOrNull(map, key); 32 | if (value) { 33 | return ParseFloat(StringPiece(*value), out_float); 34 | } 35 | return false; 36 | } 37 | 38 | bool LengthValueForKey(const StringMap &map, 39 | const std::string &key, 40 | Length *out_length) { 41 | const std::string *value = FindValueOrNull(map, key); 42 | if (value) { 43 | return ParseLength(StringPiece(*value), out_length); 44 | } 45 | return false; 46 | } 47 | 48 | bool SvgArcToCgArc(CGPoint start_point, 49 | CGPoint end_point, 50 | bool large_arc, 51 | bool sweep, 52 | CGFloat *radius, 53 | CGPoint *center, 54 | CGFloat *start_angle, 55 | CGFloat *end_angle) { 56 | if (CGPointEqualToPoint(start_point, end_point) || *radius <= 0) { 57 | return false; 58 | } 59 | CGFloat horizontal_length = 60 | std::sqrt(std::pow(start_point.x - end_point.x, 2.f) 61 | + std::pow(start_point.y - end_point.y, 2.f)); 62 | // If vertical_length has no solution, 63 | // the radius should be scaled up to the diameter. 64 | // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 65 | while (pow(*radius, 2) - pow(horizontal_length / 2, 2) < 0) { 66 | *radius = horizontal_length / 2; 67 | } 68 | CGFloat vertical_length = 69 | std::sqrt(std::pow(*radius, 2.f) - std::pow(horizontal_length / 2, 2.f)); 70 | if (large_arc != sweep) vertical_length = -vertical_length; 71 | center->x = (start_point.x + end_point.x) / 2 72 | +(end_point.y - start_point.y) * vertical_length / horizontal_length; 73 | center->y = (start_point.y + end_point.y) / 2 74 | - (end_point.x - start_point.x) * vertical_length / horizontal_length; 75 | *start_angle += atan2(-center->y + start_point.y, start_point.x - center->x); 76 | *end_angle += atan2(-center->y + end_point.y, end_point.x - center->x); 77 | 78 | return true; 79 | } 80 | 81 | bool AreAnglesClose(CGFloat a1, CGFloat a2, CGFloat accuracy) { 82 | int round_count = static_cast(std::round((a2 - a1) / (2 * kPi))); 83 | a1 += 2 * kPi * round_count; 84 | return (std::fabs(a1 - a2) < accuracy); 85 | } 86 | 87 | CGAffineTransform CGAffineTransformToNormalizeRect(CGRect rect) { 88 | CGAffineTransform transform = 89 | CGAffineTransformMakeTranslation(CGRectGetMinX(rect), 90 | CGRectGetMinY(rect)); 91 | transform = CGAffineTransformScale(transform, CGRectGetWidth(rect), 92 | CGRectGetHeight(rect)); 93 | return transform; 94 | } 95 | 96 | namespace { 97 | CGFloat OffsetForAlignment(PreserveAspectRatio::Alignment alignment, 98 | CGFloat viewport_dimention, 99 | CGFloat object_dimention) { 100 | switch (alignment) { 101 | case PreserveAspectRatio::kMin: 102 | return 0; 103 | case PreserveAspectRatio::kMid: 104 | return (viewport_dimention - object_dimention) / 2; 105 | case PreserveAspectRatio::kMax: 106 | return viewport_dimention - object_dimention; 107 | } 108 | } 109 | } // namespace 110 | 111 | CGAffineTransform 112 | CGAffineTransformForPreserveAspectRatio(PreserveAspectRatio aspect_ratio, 113 | CGRect view_box, 114 | CGRect target_viewport) { 115 | CGFloat x_scale = 116 | CGRectGetWidth(target_viewport) / CGRectGetWidth(view_box); 117 | CGFloat y_scale = 118 | CGRectGetHeight(target_viewport) / CGRectGetHeight(view_box); 119 | if (!aspect_ratio.no_alignment) { 120 | CGFloat scale = 121 | (aspect_ratio.meet_or_slice == PreserveAspectRatio::kMeet) ? 122 | std::fmin(x_scale, y_scale) : 123 | std::fmax(x_scale, y_scale); 124 | x_scale = scale; 125 | y_scale = scale; 126 | } 127 | 128 | CGFloat scaled_width = x_scale * CGRectGetWidth(view_box); 129 | CGFloat x_offset = OffsetForAlignment(aspect_ratio.x_alignment, 130 | CGRectGetWidth(target_viewport), 131 | scaled_width); 132 | CGFloat scaled_height = y_scale * CGRectGetHeight(view_box); 133 | CGFloat y_offset = OffsetForAlignment(aspect_ratio.y_alignment, 134 | CGRectGetHeight(target_viewport), 135 | scaled_height); 136 | 137 | CGAffineTransform transform = 138 | CGAffineTransformMakeTranslation(x_offset, y_offset); 139 | transform = CGAffineTransformScale(transform, x_scale, y_scale); 140 | return transform; 141 | } 142 | 143 | CGFloat EvaluateLength(Length length) { 144 | CGFloat scale = 1.f; 145 | if (length.unit == Length::kUnitPercent) { 146 | scale = 0.01f; 147 | } 148 | return length.value * scale; 149 | } 150 | 151 | } // namespace internal 152 | } // namespace metrosvg 153 | -------------------------------------------------------------------------------- /Apps/Common/DirectoryContentsViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import "DirectoryContentsViewController.h" 18 | 19 | #pragma mark - DirectoryContent 20 | 21 | @interface DirectoryContent : NSObject 22 | 23 | @property(nonatomic, strong, readonly) NSString *name; 24 | @property(nonatomic, assign, readonly) BOOL isDirectory; 25 | 26 | - (instancetype)initWithName:(NSString *)name isDirectory:(BOOL)isDirectory; 27 | 28 | + (NSArray *)directoryContentsInDirectoryAtPath:(NSString *)path; 29 | 30 | @end 31 | 32 | @implementation DirectoryContent 33 | 34 | - (instancetype)initWithName:(NSString *)name isDirectory:(BOOL)isDirectory { 35 | self = [super init]; 36 | if (self) { 37 | _name = name; 38 | _isDirectory = isDirectory; 39 | } 40 | return self; 41 | } 42 | 43 | - (BOOL)isEqual:(id)other { 44 | if (self == other) { 45 | return YES; 46 | } 47 | if (![other isKindOfClass:[self class]]) { 48 | return NO; 49 | } 50 | DirectoryContent *otherContent = (DirectoryContent *)other; 51 | return [_name isEqualToString:otherContent.name] && _isDirectory == otherContent.isDirectory; 52 | } 53 | 54 | - (NSUInteger)hash { 55 | NSUInteger hash = [_name hash]; 56 | hash = hash * 13 + (_isDirectory ? 7 : 0); 57 | return hash; 58 | } 59 | 60 | + (NSArray *)directoryContentsInDirectoryAtPath:(NSString *)path { 61 | NSFileManager *fileManager = [NSFileManager defaultManager]; 62 | NSArray *rawContents = [fileManager contentsOfDirectoryAtPath:path error:nil]; 63 | NSMutableArray *contents = [NSMutableArray array]; 64 | for (NSString *rawContent in rawContents) { 65 | if ([rawContent isEqualToString:@".DS_Store"]) { 66 | continue; 67 | } 68 | NSString *contentPath = [path stringByAppendingPathComponent:rawContent]; 69 | BOOL isDirectory; 70 | if ([fileManager fileExistsAtPath:contentPath isDirectory:&isDirectory]) { 71 | DirectoryContent *content = 72 | [[DirectoryContent alloc] initWithName:rawContent isDirectory:isDirectory]; 73 | [contents addObject:content]; 74 | } 75 | } 76 | return [contents copy]; 77 | } 78 | 79 | @end 80 | 81 | #pragma mark - DirectoryContentsViewController 82 | 83 | @implementation DirectoryContentsViewController { 84 | NSArray *_paths; // of NSString. 85 | NSArray *_commonContents; // of NSString. 86 | } 87 | 88 | - (instancetype)initWithPaths:(NSArray *)paths title:(NSString *)title { 89 | self = [super initWithStyle:UITableViewStylePlain]; 90 | if (self) { 91 | self.title = title; 92 | 93 | _paths = [paths copy]; 94 | 95 | NSMutableSet *commonContents; 96 | for (NSString *path in paths) { 97 | NSArray *contents = [DirectoryContent directoryContentsInDirectoryAtPath:path]; 98 | if (commonContents) { 99 | [commonContents intersectSet:[NSSet setWithArray:contents]]; 100 | } else { 101 | commonContents = [NSMutableSet setWithArray:contents]; 102 | } 103 | } 104 | _commonContents = 105 | [[commonContents allObjects] sortedArrayUsingComparator:^(DirectoryContent *c1, 106 | DirectoryContent *c2) { 107 | return [c1.name compare:c2.name]; 108 | }]; 109 | } 110 | return self; 111 | } 112 | 113 | #pragma mark UITableViewDataSource 114 | 115 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 116 | return 1; 117 | } 118 | 119 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 120 | return [_commonContents count]; 121 | } 122 | 123 | - (UITableViewCell *)tableView:(UITableView *)tableView 124 | cellForRowAtIndexPath:(NSIndexPath *)indexPath { 125 | static NSString *const kReuseIdentifier = @"DirectoryContentsViewController"; 126 | UITableViewCell *cell = 127 | [tableView dequeueReusableCellWithIdentifier:kReuseIdentifier]; 128 | if (!cell) { 129 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 130 | reuseIdentifier:kReuseIdentifier]; 131 | } 132 | DirectoryContent *content = _commonContents[indexPath.row]; 133 | NSString *icon = content.isDirectory ? @"\U0001F4C1" // directory icon. 134 | : @"\U0001F4C4"; // file icon. 135 | cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", icon, content.name]; 136 | return cell; 137 | } 138 | 139 | #pragma mark UITableViewDelegate 140 | 141 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 142 | DirectoryContent *content = _commonContents[indexPath.row]; 143 | 144 | NSMutableArray *newPaths = [NSMutableArray array]; 145 | for (NSString *p in _paths) { 146 | NSString *newPath = [p stringByAppendingPathComponent:content.name]; 147 | [newPaths addObject:newPath]; 148 | } 149 | if (content.isDirectory) { 150 | DirectoryContentsViewController *newController = 151 | [[DirectoryContentsViewController alloc] initWithPaths:newPaths title:content.name]; 152 | newController.dataSource = _dataSource; 153 | [self.navigationController pushViewController:newController animated:YES]; 154 | } else { 155 | UIViewController *viewController = 156 | [_dataSource directoryContentsController:self viewControllerWithFilePaths:newPaths]; 157 | if (viewController) { 158 | [self.navigationController pushViewController:viewController animated:YES]; 159 | } 160 | } 161 | } 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /MetroSVG/Internal/StyleSheetTest.mm: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | #include "MetroSVG/Internal/StyleSheet.h" 20 | #include "MetroSVG/Internal/Utils.h" 21 | 22 | #define SVGAssertCSSProperty(__pair, __name, __value) \ 23 | do {\ 24 | XCTAssertEqual(__pair.first, __name); \ 25 | XCTAssertEqual(__pair.second, __value); \ 26 | } while (0) 27 | 28 | using namespace metrosvg::internal; 29 | 30 | @interface StyleSheetTest : XCTestCase 31 | @end 32 | 33 | @implementation StyleSheetTest 34 | 35 | - (void)testParseStyleSheetData_OneProperty { 36 | const char *data = ".test1 { fill: red; }"; 37 | std::unique_ptr 38 | style_sheet(ParseStyleSheetData(data, strlen(data))); 39 | const std::vector> *value = 40 | FindValueOrNull(style_sheet->entry, std::string("test1")); 41 | XCTAssertTrue(value != NULL); 42 | XCTAssertEqual(value->size(), 1U); 43 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 44 | } 45 | 46 | - (void)testParseStyleSheetData_MultipleProperties { 47 | const char *data = ".test2{ fill:red; stroke:green; }"; 48 | std::unique_ptr 49 | style_sheet(ParseStyleSheetData(data, strlen(data))); 50 | const std::vector> *value = 51 | FindValueOrNull(style_sheet->entry, std::string("test2")); 52 | XCTAssertTrue(value != NULL); 53 | XCTAssertEqual(value->size(), 2U); 54 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 55 | SVGAssertCSSProperty((*value)[1], "stroke", "green"); 56 | } 57 | 58 | - (void)testParseStyleSheetData_MultipleSelectors { 59 | const char *data = ".test3 { fill: red; } .test4 { stroke:green; }"; 60 | std::unique_ptr 61 | style_sheet(ParseStyleSheetData(data, strlen(data))); 62 | const std::vector> *value = 63 | FindValueOrNull(style_sheet->entry, std::string("test3")); 64 | XCTAssertTrue(value != NULL); 65 | XCTAssertEqual(value->size(), 1U); 66 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 67 | value = FindValueOrNull(style_sheet->entry, std::string("test4")); 68 | XCTAssertEqual(value->size(), 1U); 69 | SVGAssertCSSProperty((*value)[0], "stroke", "green"); 70 | } 71 | 72 | - (void)testParseStyleSheetData_ErrorInvalidSelector1 { 73 | const char *data = ".te st5 { fill: red; }"; 74 | std::unique_ptr 75 | style_sheet(ParseStyleSheetData(data, strlen(data))); 76 | XCTAssertTrue(style_sheet == NULL); 77 | } 78 | 79 | - (void)testParseStyleSheetData_ErrorInvalidSelector2 { 80 | const char *data = "rect .test6 { fill: red; }"; 81 | std::unique_ptr 82 | style_sheet(ParseStyleSheetData(data, strlen(data))); 83 | XCTAssertTrue(style_sheet == NULL); 84 | } 85 | 86 | - (void)testSVGCSSMerge_SameSelector { 87 | const char *data_dest = ".test9 { fill:red; }"; 88 | std::unique_ptr 89 | dest(ParseStyleSheetData(data_dest, strlen(data_dest))); 90 | const char *data_source = ".test9 { fill:green; }"; 91 | std::unique_ptr 92 | source(ParseStyleSheetData(data_source, strlen(data_source))); 93 | MSCStyleSheetMerge(*source.get(), dest.get()); 94 | const std::vector> *value = 95 | FindValueOrNull(dest->entry, std::string("test9")); 96 | XCTAssertTrue(value != NULL); 97 | XCTAssertEqual(value->size(), 2U); 98 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 99 | SVGAssertCSSProperty((*value)[1], "fill", "green"); 100 | } 101 | 102 | - (void)testSVGCSSMerge_DifferentSelectors { 103 | const char *data_dest = ".test10 { fill:red; }"; 104 | std::unique_ptr 105 | desct(ParseStyleSheetData(data_dest, strlen(data_dest))); 106 | const char *data_source = ".test11 { fill:green; }"; 107 | std::unique_ptr 108 | source(ParseStyleSheetData(data_source, strlen(data_source))); 109 | MSCStyleSheetMerge(*source.get(), desct.get()); 110 | const std::vector> *value = 111 | FindValueOrNull(desct->entry, std::string("test10")); 112 | XCTAssertTrue(value != NULL); 113 | XCTAssertEqual(value->size(), 1U); 114 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 115 | value = FindValueOrNull(desct->entry, std::string("test11")); 116 | XCTAssertEqual(value->size(), 1U); 117 | SVGAssertCSSProperty((*value)[0], "fill", "green"); 118 | } 119 | 120 | - (void)testSVGCSSMerge_MultipleSourceSelectors { 121 | const char *data_dest = ".test12 { fill:red; }"; 122 | std::unique_ptr 123 | dest(ParseStyleSheetData(data_dest, strlen(data_dest))); 124 | const char *data_source = ".test13 { fill: red; } .test14 { stroke:green; }"; 125 | std::unique_ptr 126 | source(ParseStyleSheetData(data_source, strlen(data_source))); 127 | MSCStyleSheetMerge(*source.get(), dest.get()); 128 | const std::vector> *value = 129 | FindValueOrNull(dest->entry, std::string("test12")); 130 | XCTAssertTrue(value != NULL); 131 | XCTAssertEqual(value->size(), 1U); 132 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 133 | value = FindValueOrNull(dest->entry, std::string("test13")); 134 | XCTAssertEqual(value->size(), 1U); 135 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 136 | value = FindValueOrNull(dest->entry, std::string("test14")); 137 | XCTAssertEqual(value->size(), 1U); 138 | SVGAssertCSSProperty((*value)[0], "stroke", "green"); 139 | } 140 | 141 | - (void)testSVGCSSMerge_MultipleSourceProperties { 142 | const char *data_dest = ".test15 { fill:red; }"; 143 | std::unique_ptr 144 | dest(ParseStyleSheetData(data_dest, strlen(data_dest))); 145 | const char *data_source = ".test15 { fill: red; stroke:green; }"; 146 | std::unique_ptr 147 | source(ParseStyleSheetData(data_source, strlen(data_source))); 148 | MSCStyleSheetMerge(*source.get(), dest.get()); 149 | const std::vector> *value = 150 | FindValueOrNull(dest->entry, std::string("test15")); 151 | XCTAssertTrue(value != NULL); 152 | XCTAssertEqual(value->size(), 3U); 153 | SVGAssertCSSProperty((*value)[0], "fill", "red"); 154 | SVGAssertCSSProperty((*value)[1], "fill", "red"); 155 | SVGAssertCSSProperty((*value)[2], "stroke", "green"); 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /Apps/StyleChecker/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /MetroSVG/Internal/SVGStandardColor.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/SVGStandardColor.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "MetroSVG/Internal/BasicValueParsers.h" 24 | 25 | namespace metrosvg { 26 | namespace internal { 27 | 28 | #if SVG_COLOR_KEYWORD_SUPPORT 29 | 30 | // The standard SVG color definitions in alphabetical order, 31 | // for fast binary searching. 32 | // This table was generated by copy/pasting from the SVG spec: 33 | // http://www.w3.org/TR/SVG/types.html#ColorKeywords 34 | // and then passing it through this Python script plus the sort 35 | // command: 36 | // import fileinput 37 | // import re 38 | // import os 39 | // 40 | // color_line_re = re.compile( 41 | // """^\s*(\w+)\s*rgb\(\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\s*\)\s*$""", 42 | // re.IGNORECASE) 43 | // 44 | // for line in fileinput.input(): 45 | // line = line.strip() 46 | // m = color_line_re.match(line) 47 | // if not m: 48 | // continue 49 | // color_name = m.group(1) 50 | // red = int(m.group(2)) 51 | // green = int(m.group(3)) 52 | // blue = int(m.group(4)) 53 | // print """ { "%s", %d, %d, %d, 255, },""" % ( 54 | // color_name, red, green, blue) 55 | 56 | static const SvgStandardColorDefinition standardColorDefinitions[] = { 57 | { "aliceblue", 240, 248, 255, 255, }, 58 | { "antiquewhite", 250, 235, 215, 255, }, 59 | { "aqua", 0, 255, 255, 255, }, 60 | { "aquamarine", 127, 255, 212, 255, }, 61 | { "azure", 240, 255, 255, 255, }, 62 | { "beige", 245, 245, 220, 255, }, 63 | { "bisque", 255, 228, 196, 255, }, 64 | { "black", 0, 0, 0, 255, }, 65 | { "blanchedalmond", 255, 235, 205, 255, }, 66 | { "blue", 0, 0, 255, 255, }, 67 | { "blueviolet", 138, 43, 226, 255, }, 68 | { "brown", 165, 42, 42, 255, }, 69 | { "burlywood", 222, 184, 135, 255, }, 70 | { "cadetblue", 95, 158, 160, 255, }, 71 | { "chartreuse", 127, 255, 0, 255, }, 72 | { "chocolate", 210, 105, 30, 255, }, 73 | { "coral", 255, 127, 80, 255, }, 74 | { "cornflowerblue", 100, 149, 237, 255, }, 75 | { "cornsilk", 255, 248, 220, 255, }, 76 | { "crimson", 220, 20, 60, 255, }, 77 | { "cyan", 0, 255, 255, 255, }, 78 | { "darkblue", 0, 0, 139, 255, }, 79 | { "darkcyan", 0, 139, 139, 255, }, 80 | { "darkgoldenrod", 184, 134, 11, 255, }, 81 | { "darkgray", 169, 169, 169, 255, }, 82 | { "darkgreen", 0, 100, 0, 255, }, 83 | { "darkgrey", 169, 169, 169, 255, }, 84 | { "darkkhaki", 189, 183, 107, 255, }, 85 | { "darkmagenta", 139, 0, 139, 255, }, 86 | { "darkolivegreen", 85, 107, 47, 255, }, 87 | { "darkorange", 255, 140, 0, 255, }, 88 | { "darkorchid", 153, 50, 204, 255, }, 89 | { "darkred", 139, 0, 0, 255, }, 90 | { "darksalmon", 233, 150, 122, 255, }, 91 | { "darkseagreen", 143, 188, 143, 255, }, 92 | { "darkslateblue", 72, 61, 139, 255, }, 93 | { "darkslategray", 47, 79, 79, 255, }, 94 | { "darkslategrey", 47, 79, 79, 255, }, 95 | { "darkturquoise", 0, 206, 209, 255, }, 96 | { "darkviolet", 148, 0, 211, 255, }, 97 | { "deeppink", 255, 20, 147, 255, }, 98 | { "deepskyblue", 0, 191, 255, 255, }, 99 | { "dimgray", 105, 105, 105, 255, }, 100 | { "dimgrey", 105, 105, 105, 255, }, 101 | { "dodgerblue", 30, 144, 255, 255, }, 102 | { "firebrick", 178, 34, 34, 255, }, 103 | { "floralwhite", 255, 250, 240, 255, }, 104 | { "forestgreen", 34, 139, 34, 255, }, 105 | { "fuchsia", 255, 0, 255, 255, }, 106 | { "gainsboro", 220, 220, 220, 255, }, 107 | { "ghostwhite", 248, 248, 255, 255, }, 108 | { "gold", 255, 215, 0, 255, }, 109 | { "goldenrod", 218, 165, 32, 255, }, 110 | { "gray", 128, 128, 128, 255, }, 111 | { "green", 0, 128, 0, 255, }, 112 | { "greenyellow", 173, 255, 47, 255, }, 113 | { "grey", 128, 128, 128, 255, }, 114 | { "honeydew", 240, 255, 240, 255, }, 115 | { "hotpink", 255, 105, 180, 255, }, 116 | { "indianred", 205, 92, 92, 255, }, 117 | { "indigo", 75, 0, 130, 255, }, 118 | { "ivory", 255, 255, 240, 255, }, 119 | { "khaki", 240, 230, 140, 255, }, 120 | { "lavender", 230, 230, 250, 255, }, 121 | { "lavenderblush", 255, 240, 245, 255, }, 122 | { "lawngreen", 124, 252, 0, 255, }, 123 | { "lemonchiffon", 255, 250, 205, 255, }, 124 | { "lightblue", 173, 216, 230, 255, }, 125 | { "lightcoral", 240, 128, 128, 255, }, 126 | { "lightcyan", 224, 255, 255, 255, }, 127 | { "lightgoldenrodyellow", 250, 250, 210, 255, }, 128 | { "lightgray", 211, 211, 211, 255, }, 129 | { "lightgreen", 144, 238, 144, 255, }, 130 | { "lightgrey", 211, 211, 211, 255, }, 131 | { "lightpink", 255, 182, 193, 255, }, 132 | { "lightsalmon", 255, 160, 122, 255, }, 133 | { "lightseagreen", 32, 178, 170, 255, }, 134 | { "lightskyblue", 135, 206, 250, 255, }, 135 | { "lightslategray", 119, 136, 153, 255, }, 136 | { "lightslategrey", 119, 136, 153, 255, }, 137 | { "lightsteelblue", 176, 196, 222, 255, }, 138 | { "lightyellow", 255, 255, 224, 255, }, 139 | { "lime", 0, 255, 0, 255, }, 140 | { "limegreen", 50, 205, 50, 255, }, 141 | { "linen", 250, 240, 230, 255, }, 142 | { "magenta", 255, 0, 255, 255, }, 143 | { "maroon", 128, 0, 0, 255, }, 144 | { "mediumaquamarine", 102, 205, 170, 255, }, 145 | { "mediumblue", 0, 0, 205, 255, }, 146 | { "mediumorchid", 186, 85, 211, 255, }, 147 | { "mediumpurple", 147, 112, 219, 255, }, 148 | { "mediumseagreen", 60, 179, 113, 255, }, 149 | { "mediumslateblue", 123, 104, 238, 255, }, 150 | { "mediumspringgreen", 0, 250, 154, 255, }, 151 | { "mediumturquoise", 72, 209, 204, 255, }, 152 | { "mediumvioletred", 199, 21, 133, 255, }, 153 | { "midnightblue", 25, 25, 112, 255, }, 154 | { "mintcream", 245, 255, 250, 255, }, 155 | { "mistyrose", 255, 228, 225, 255, }, 156 | { "moccasin", 255, 228, 181, 255, }, 157 | { "navajowhite", 255, 222, 173, 255, }, 158 | { "navy", 0, 0, 128, 255, }, 159 | { "oldlace", 253, 245, 230, 255, }, 160 | { "olive", 128, 128, 0, 255, }, 161 | { "olivedrab", 107, 142, 35, 255, }, 162 | { "orange", 255, 165, 0, 255, }, 163 | { "orangered", 255, 69, 0, 255, }, 164 | { "orchid", 218, 112, 214, 255, }, 165 | { "palegoldenrod", 238, 232, 170, 255, }, 166 | { "palegreen", 152, 251, 152, 255, }, 167 | { "paleturquoise", 175, 238, 238, 255, }, 168 | { "palevioletred", 219, 112, 147, 255, }, 169 | { "papayawhip", 255, 239, 213, 255, }, 170 | { "peachpuff", 255, 218, 185, 255, }, 171 | { "peru", 205, 133, 63, 255, }, 172 | { "pink", 255, 192, 203, 255, }, 173 | { "plum", 221, 160, 221, 255, }, 174 | { "powderblue", 176, 224, 230, 255, }, 175 | { "purple", 128, 0, 128, 255, }, 176 | { "red", 255, 0, 0, 255, }, 177 | { "rosybrown", 188, 143, 143, 255, }, 178 | { "royalblue", 65, 105, 225, 255, }, 179 | { "saddlebrown", 139, 69, 19, 255, }, 180 | { "salmon", 250, 128, 114, 255, }, 181 | { "sandybrown", 244, 164, 96, 255, }, 182 | { "seagreen", 46, 139, 87, 255, }, 183 | { "seashell", 255, 245, 238, 255, }, 184 | { "sienna", 160, 82, 45, 255, }, 185 | { "silver", 192, 192, 192, 255, }, 186 | { "skyblue", 135, 206, 235, 255, }, 187 | { "slateblue", 106, 90, 205, 255, }, 188 | { "slategray", 112, 128, 144, 255, }, 189 | { "slategrey", 112, 128, 144, 255, }, 190 | { "snow", 255, 250, 250, 255, }, 191 | { "springgreen", 0, 255, 127, 255, }, 192 | { "steelblue", 70, 130, 180, 255, }, 193 | { "tan", 210, 180, 140, 255, }, 194 | { "teal", 0, 128, 128, 255, }, 195 | { "thistle", 216, 191, 216, 255, }, 196 | { "tomato", 255, 99, 71, 255, }, 197 | { "turquoise", 64, 224, 208, 255, }, 198 | { "violet", 238, 130, 238, 255, }, 199 | { "wheat", 245, 222, 179, 255, }, 200 | { "white", 255, 255, 255, 255, }, 201 | { "whitesmoke", 245, 245, 245, 255, }, 202 | { "yellow", 255, 255, 0, 255, }, 203 | { "yellowgreen", 154, 205, 50, 255, }, 204 | }; 205 | 206 | // Comparator function for an color definition and a StringPiece. 207 | // Compares the color's name to the StringPiece value. 208 | // Returns -1, 0, or 1 depending on whether the color definition 209 | // lexicographically sorts less than, equal to, or greater than 210 | // the StringPiece's value. 211 | static int CompareColorDefinitionToStringPiece( 212 | const SvgStandardColorDefinition &def, 213 | const StringPiece &sp) { 214 | const char *dp = def.name; 215 | const char *spp = sp.begin(); 216 | while (spp < sp.end()) { 217 | const char dc = *dp; 218 | // First n chars are equal but color name is shorter. 219 | if (dc == 0) { return -1; } 220 | const char sc = static_cast(tolower(*spp)); 221 | if (dc < sc) { return -1; } 222 | if (dc > sc) { return 1; } 223 | dp++; 224 | spp++; 225 | } 226 | // Character and lengths both equal. 227 | if (!*dp) { return 0; } 228 | // First n characters are equal but StringPiece is shorter. 229 | return 1; 230 | } 231 | 232 | // Returns the standard SVG color for the given string, 233 | // if it exists; otherwise NULL. 234 | // Implements binary search in the above static table. 235 | const SvgStandardColorDefinition *FindSVGStandardColorOrNull( 236 | const StringPiece &token) { 237 | int imin = 0; 238 | int imax = sizeof(standardColorDefinitions) 239 | / sizeof(SvgStandardColorDefinition); 240 | while (imax >= imin) { 241 | int imid = imin + (imax - imin) / 2; 242 | int comparison = CompareColorDefinitionToStringPiece( 243 | standardColorDefinitions[imid], token); 244 | if (comparison == 0) { 245 | return &standardColorDefinitions[imid]; 246 | } else if (comparison < 0) { 247 | imin = imid + 1; 248 | } else { 249 | imax = imid - 1; 250 | } 251 | } 252 | // key was not found 253 | return NULL; 254 | } 255 | 256 | #endif // SVG_COLOR_KEYWORD_SUPPORT 257 | 258 | } // namespace internal 259 | } // namespace metrosvg 260 | -------------------------------------------------------------------------------- /MetroSVG/Internal/Renderer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "MetroSVG/Internal/BasicTypes.h" 27 | #include "MetroSVG/MetroSVG.h" 28 | 29 | struct CGContext; 30 | 31 | namespace metrosvg { 32 | namespace internal { 33 | 34 | struct Gradient; 35 | class PathDataIterator; 36 | class StringPiece; 37 | 38 | class Renderer { 39 | public: 40 | Renderer(); 41 | ~Renderer(); 42 | CGImageRef CreateCGImageFromMSCDocument(MSCDocument *document, 43 | CGSize canvas_size, 44 | const MSCStyleSheet *style_sheet); 45 | 46 | private: 47 | typedef void (Renderer::*BeginElementHandler)(const StringMap &attributes, 48 | const StringMap &styles); 49 | typedef void (Renderer::*EndElementHandler)(); 50 | 51 | // As part of the explicit GraphicsState below, we keep whether to 52 | // paint or not, and whether to paint with a gradient, for each 53 | // possible paint operation (fill and stroke). 54 | struct PaintState { 55 | bool should_paint; 56 | RgbColor color; 57 | std::string iri; 58 | CGFloat opacity; 59 | 60 | explicit PaintState(bool paint_default, const RgbColor color_default) 61 | : should_paint(paint_default), 62 | color(color_default), 63 | iri(), 64 | opacity(1.0) {} 65 | 66 | void set_should_paint(bool new_should_paint) { 67 | should_paint = new_should_paint; 68 | if (!new_should_paint) { 69 | iri.clear(); 70 | } 71 | } 72 | 73 | void set_color(RgbColor new_color) { 74 | should_paint = true; 75 | color = new_color; 76 | iri.clear(); 77 | } 78 | 79 | void set_iri(const std::string &new_iri) { 80 | should_paint = true; 81 | iri = new_iri; 82 | } 83 | 84 | void ApplyOpacity(CGFloat additional_opacity) { 85 | opacity *= additional_opacity; 86 | } 87 | }; 88 | 89 | // Most paint state is maintained directly on the CoreGraphics 90 | // GState stack. However, we need to specifically know the value 91 | // of some items that cannot be read back out of the CGState, 92 | // so we maintain a local version of a few graphics state items. 93 | struct GraphicsState { 94 | PaintState fill; 95 | FillRule fill_rule; 96 | PaintState stroke; 97 | LineDash line_dash; 98 | // This tracks the value of the "display" attribute. 99 | bool display; 100 | // This tracks the value of the "visibility" attribute, 101 | // which inherits differently than "display". See 102 | // SVG 1.1 Section 11.5. 103 | bool visibility; 104 | 105 | // States related to gradients. 106 | RgbColor stop_color; 107 | CGFloat stop_opacity; 108 | 109 | // The default value of fill is black, but for stroke it's none. 110 | GraphicsState() 111 | : fill(true, RgbColor(0.0f, 0.0f, 0.0f)), 112 | fill_rule(kFillRuleNonZero), 113 | stroke(false, RgbColor(0.0f, 0.0f, 0.0f)), 114 | display(true), 115 | visibility(true), 116 | stop_color(0, 0, 0), 117 | stop_opacity(1) {} 118 | }; 119 | 120 | struct SVGElementDefinition { 121 | const char *name; 122 | BeginElementHandler begin_handler; 123 | EndElementHandler end_handler; 124 | }; 125 | 126 | struct State { 127 | SVGElementDefinition element_definition; 128 | int element_line_number; 129 | int element_column_number; 130 | GraphicsState graphics; 131 | bool defines_transparency_layer; 132 | std::string style_text_; 133 | std::string style_type_; 134 | 135 | State(SVGElementDefinition element, 136 | int line_number, 137 | int column_number, 138 | GraphicsState this_graphics) 139 | : element_definition(element), 140 | element_line_number(line_number), 141 | element_column_number(column_number), 142 | graphics(this_graphics), 143 | defines_transparency_layer(false) {} 144 | }; 145 | 146 | // Internal constants. 147 | static const SVGElementDefinition kSvgElementRoot; 148 | static const SVGElementDefinition kSvgElementUnknown; 149 | 150 | // Internal variables. 151 | const std::unordered_set supported_styles_; 152 | CGContext *context_; 153 | CGSize canvas_size_; 154 | CGFloat x_scale_; 155 | CGFloat y_scale_; 156 | xmlTextReader *reader_; 157 | std::vector state_stack_; 158 | std::unique_ptr pending_gradient_; 159 | std::map gradients_; 160 | GraphicsState graphics_; 161 | std::unique_ptr style_sheet_; 162 | 163 | // TODO: Make this a constant. 164 | std::vector svg_element_definitions_; 165 | 166 | void BeginElement(const char *name, 167 | const StringMap &attributes, 168 | const StringMap &styles); 169 | void EndElement(const char *name); 170 | 171 | void ProcessCircleElement(const StringMap &attributes, 172 | const StringMap &styles); 173 | void ProcessEllipseElement(const StringMap &attributes, 174 | const StringMap &styles); 175 | void ProcessGElement(const StringMap &attributes, 176 | const StringMap &styles); 177 | void ProcessLineElement(const StringMap &attributes, 178 | const StringMap &styles); 179 | 180 | void BeginLinearGradientElement(const StringMap &attributes, 181 | const StringMap &styles); 182 | void EndLinearGradientElement(); 183 | 184 | void ProcessPathElement(const StringMap &attributes, 185 | const StringMap &styles); 186 | void ProcessPolygonElement(const StringMap &attributes, 187 | const StringMap &styles); 188 | void ProcessPolylineElement(const StringMap &attributes, 189 | const StringMap &styles); 190 | 191 | void BeginRadialGradientElement(const StringMap &attributes, 192 | const StringMap &styles); 193 | void EndRadialGradientElement(); 194 | 195 | void ProcessRectElement(const StringMap &attributes, 196 | const StringMap &styles); 197 | void ProcessStopElement(const StringMap &attributes, 198 | const StringMap &styles); 199 | 200 | void BeginStyleElement(const StringMap &attributes, 201 | const StringMap &styles); 202 | void EndStyleElement(); 203 | 204 | void ProcessSvgElement(const StringMap &attributes, 205 | const StringMap &styles); 206 | 207 | // Attempts to process the given name and value that can be specified 208 | // as an attribute and a style. 209 | // 210 | // It returns whether the given name/value pair was a 211 | // known style (in which case it will have been processed). 212 | bool ProcessStyle(const std::string &name, 213 | const std::string &value); 214 | // This is a helper function to process the value of a fill 215 | // or stroke attribute. 216 | void ProcessFillOrStrokeValue(const std::string &value, bool is_fill); 217 | 218 | // Set the current fill or stroke color in the current context 219 | // based on the graphics state. 220 | void CallCGSetColor(bool is_fill); 221 | 222 | void ProcessDisplayValue(const std::string &value); 223 | void ProcessVisibilityValue(const std::string &value); 224 | void ProcessOpacityValue(const std::string &value); 225 | void ProcessFillRuleValue(const std::string &value); 226 | void ProcessDashArrayValue(const std::string &value); 227 | void ProcessDashOffsetValue(const std::string &value); 228 | 229 | // Returns true if all attributes and styles are processed successfully. 230 | // Returns false if there was an any error. 231 | bool ProcessCommonAttributes(StringMap *unprocessed_attributes, 232 | StringMap *unprocessed_styles); 233 | 234 | // Iterates through all the elements returned by the given 235 | // iterator and defines the result as the path in the current 236 | // graphics context. 237 | void ProcessPathData(PathDataIterator *iter); 238 | 239 | // Takes an path data iterator that points to an arc 240 | // and add the arc to a path. 241 | // If an error(Out-of-range etc) occured, 242 | // returns false without mutating the path. 243 | bool AddEllipticalArcToPath(const PathDataIterator &iter, 244 | CGMutablePathRef *path); 245 | 246 | // Called to handle a paintable element with a points= attribute 247 | // (either polygon or polyline). 248 | void PaintPolyElement(const StringMap &attributes, bool implicit_close); 249 | 250 | // This routine should be called to handle the painting of 251 | // any element based on previously set fill/stroke options. 252 | // The callback takes a context and should 253 | // set the path to be painted into the context. 254 | // The |is_fillable| parameter may be false to indicate that the 255 | // type of element being painted is not logically fillable 256 | // (line and polyline). 257 | void PaintElement(std::function define_path, 258 | bool is_fillable); 259 | 260 | // This routine is a helper which will draw the gradient referenced 261 | // by the given iri clipped by the current path. 262 | void DrawClippedGradient(const std::string &iri); 263 | 264 | // Helper functions. 265 | void InitializeCGContext(); 266 | SVGElementDefinition FindElementDefinition(const char *name); 267 | 268 | // Merge css into class variable style_sheet_, create an instance 269 | // if style_sheet_ is a nullptr. 270 | void MergeStyleSheet(const MSCStyleSheet &style_sheet); 271 | }; 272 | 273 | } // namespace internal 274 | } // namespace metrosvg 275 | -------------------------------------------------------------------------------- /MetroSVG/Internal/PathDataIterator.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "MetroSVG/Internal/PathDataIterator.h" 18 | 19 | #include 20 | 21 | #include "MetroSVG/Internal/BasicValueParsers.h" 22 | #include "MetroSVG/Internal/Macros.h" 23 | #include "MetroSVG/Internal/StringPiece.h" 24 | 25 | namespace metrosvg { 26 | namespace internal { 27 | 28 | PathDataIterator::PathDataIterator(const char *data, 29 | PathDataFormat format, 30 | bool implicit_close) 31 | : s_(data), 32 | implicit_close_(implicit_close), 33 | format_(format), 34 | is_first_command_(true), 35 | absolute_(format == kPathDataFormatPoints), 36 | shown_close_path_(false), 37 | last_command_type_(kPathCommandTypeClosePath) { 38 | point_ = CGPointMake(0.0, 0.0); 39 | } 40 | 41 | bool PathDataIterator::Next() { 42 | ConsumeWhitespace(&s_); 43 | if (s_.length() == 0) { 44 | if (implicit_close_ && !shown_close_path_) { 45 | command_type_ = kPathCommandTypeClosePath; 46 | shown_close_path_ = true; 47 | return true; 48 | } else { 49 | return false; 50 | } 51 | } 52 | 53 | bool success; 54 | if (format_ == kPathDataFormatPoints) { 55 | success = ParseSingleCommandForPoints(); 56 | } else { 57 | success = ParseSingleCommandForPath(); 58 | } 59 | if (success) { 60 | is_first_command_ = false; 61 | last_command_type_ = command_type_; 62 | } 63 | return success; 64 | } 65 | 66 | bool PathDataIterator::ParseSingleCommandForPath() { 67 | char command_char; 68 | // See whether we're starting a new command or repeating the previous command. 69 | if (PeekAlpha(s_, &command_char)) { 70 | // Consume the char we just peeked. 71 | if (!ConsumeAlpha(&s_, &command_char)) { 72 | return false; 73 | } 74 | char normalized_command_char = command_char; 75 | absolute_ = false; 76 | if ('A' <= command_char && command_char <= 'Z') { 77 | absolute_ = true; 78 | normalized_command_char = command_char - ('A' - 'a'); 79 | } 80 | switch (normalized_command_char) { 81 | case 'c': 82 | command_type_ = kPathCommandTypeCubicBezier; 83 | break; 84 | case 'h': 85 | command_type_ = kPathCommandTypeHorizontalLineTo; 86 | break; 87 | case 'l': 88 | command_type_ = kPathCommandTypeLineTo; 89 | break; 90 | case 'v': 91 | command_type_ = kPathCommandTypeVerticalLineTo; 92 | break; 93 | case 'm': 94 | command_type_ = kPathCommandTypeMoveTo; 95 | break; 96 | case 's': 97 | command_type_ = kPathCommandTypeShorthandCubicBezier; 98 | break; 99 | case 'q': 100 | command_type_ = kPathCommandTypeQuadBezier; 101 | break; 102 | case 't': 103 | command_type_ = kPathCommandTypeShorthandQuadBezier; 104 | break; 105 | case 'a': 106 | command_type_ = kPathCommandTypeEllipticalArc; 107 | break; 108 | case 'z': 109 | command_type_ = kPathCommandTypeClosePath; 110 | break; 111 | default: 112 | return false; 113 | } 114 | } else { 115 | if (is_first_command_ || (command_type_ == kPathCommandTypeClosePath)) { 116 | return false; 117 | } 118 | // All other command types can repeat their arguments, so reuse the last 119 | // command type. However, if the last type was MoveTo, it should morph into 120 | // a LineTo (see SVG 1.1 Section 8.3.2). 121 | if (command_type_ == kPathCommandTypeMoveTo) { 122 | command_type_ = kPathCommandTypeLineTo; 123 | } 124 | // Consume any comma between repeats. 125 | ConsumeNumberDelimiter(&s_); 126 | } 127 | switch (command_type_) { 128 | case kPathCommandTypeMoveTo: { 129 | bool success = ParseMoveAndLineCommand(command_type_); 130 | subpath_start_point_ = point_; 131 | return success; 132 | } 133 | case kPathCommandTypeLineTo: 134 | case kPathCommandTypeHorizontalLineTo: 135 | case kPathCommandTypeVerticalLineTo: 136 | return ParseMoveAndLineCommand(command_type_); 137 | case kPathCommandTypeCubicBezier: 138 | return ParseCubicBezierCommand(); 139 | case kPathCommandTypeShorthandCubicBezier: 140 | return ParseShorthandCubicBezierCommand(); 141 | case kPathCommandTypeQuadBezier: 142 | return ParseQuadBezierCommand(); 143 | case kPathCommandTypeShorthandQuadBezier: 144 | return ParseShorthandQuadBezierCommand(); 145 | case kPathCommandTypeEllipticalArc: 146 | return ParseEllipticalArcCommand(); 147 | case kPathCommandTypeClosePath: 148 | // The default start point of the next subpath is the same as 149 | // the current subpath. SVG (see SVG 1.1 Section 8.3.3) and 150 | // Core Graphics share this behivior. 151 | point_ = subpath_start_point_; 152 | return true; 153 | } 154 | } 155 | 156 | bool PathDataIterator::ParseSingleCommandForPoints() { 157 | if (is_first_command_) { 158 | command_type_ = kPathCommandTypeMoveTo; 159 | } else { 160 | command_type_ = kPathCommandTypeLineTo; 161 | // Consume any number delimiter between points. 162 | ConsumeNumberDelimiter(&s_); 163 | } 164 | return ParseMoveAndLineCommand(command_type_); 165 | } 166 | 167 | bool PathDataIterator::ParseMoveAndLineCommand( 168 | enum PathCommandType command_type) { 169 | bool change_x = false; 170 | bool change_y = false; 171 | CGFloat values[2] = {point_.x , point_.y}; 172 | switch (command_type) { 173 | case kPathCommandTypeHorizontalLineTo: 174 | if (!ConsumeFloat(&s_, values)) { 175 | return false; 176 | } 177 | change_x = true; 178 | break; 179 | case kPathCommandTypeLineTo: 180 | if (!ConsumeFloats(&s_, 2, values)) { 181 | return false; 182 | } 183 | change_x = true; 184 | change_y = true; 185 | break; 186 | case kPathCommandTypeMoveTo: 187 | if (!ConsumeFloats(&s_, 2, values)) { 188 | return false; 189 | } 190 | change_x = true; 191 | change_y = true; 192 | break; 193 | case kPathCommandTypeVerticalLineTo: 194 | if (!ConsumeFloat(&s_, values + 1)) { 195 | return false; 196 | } 197 | change_y = true; 198 | break; 199 | default: 200 | return false; 201 | } 202 | if (absolute_) { 203 | if (change_x) { 204 | point_ = CGPointMake(values[0], point_.y); 205 | } 206 | if (change_y) { 207 | point_ = CGPointMake(point_.x, values[1]); 208 | } 209 | } else { 210 | if (change_x) { 211 | point_ = CGPointMake(point_.x + values[0], point_.y); 212 | } 213 | if (change_y) { 214 | point_ = CGPointMake(point_.x, point_.y + values[1]); 215 | } 216 | } 217 | return true; 218 | } 219 | 220 | bool PathDataIterator::ParseCubicBezierCommand() { 221 | CGFloat values[6]; 222 | if (!ConsumeFloats(&s_, ARRAYSIZE(values), values)) { 223 | return false; 224 | } 225 | control_point1_ = CGPointMake(values[0] + (absolute_ ? 0 : point_.x), 226 | values[1] + (absolute_ ? 0 : point_.y)); 227 | control_point2_ = CGPointMake(values[2] + (absolute_ ? 0 : point_.x), 228 | values[3] + (absolute_ ? 0 : point_.y)); 229 | point_ = CGPointMake(values[4] + (absolute_ ? 0 : point_.x), 230 | values[5] + (absolute_ ? 0 : point_.y)); 231 | return true; 232 | } 233 | 234 | bool PathDataIterator::ParseShorthandCubicBezierCommand() { 235 | CGFloat values[4]; 236 | if (!ConsumeFloats(&s_, ARRAYSIZE(values), values)) { 237 | return false; 238 | } 239 | if (last_command_type_ == kPathCommandTypeCubicBezier || 240 | last_command_type_ == kPathCommandTypeShorthandCubicBezier) { 241 | control_point1_ = CGPointMake(point_.x + (point_.x - control_point2_.x), 242 | point_.y + (point_.y - control_point2_.y)); 243 | } else { 244 | control_point1_ = point_; 245 | } 246 | control_point2_ = CGPointMake(values[0] + (absolute_ ? 0 : point_.x), 247 | values[1] + (absolute_ ? 0 : point_.y)); 248 | point_ = CGPointMake(values[2] + (absolute_ ? 0 : point_.x), 249 | values[3] + (absolute_ ? 0 : point_.y)); 250 | return true; 251 | } 252 | 253 | bool PathDataIterator::ParseQuadBezierCommand() { 254 | CGFloat values[4]; 255 | if (!ConsumeFloats(&s_, ARRAYSIZE(values), values)) { 256 | return false; 257 | } 258 | control_point1_ = CGPointMake(values[0] + (absolute_ ? 0 : point_.x), 259 | values[1] + (absolute_ ? 0 : point_.y)); 260 | point_ = CGPointMake(values[2] + (absolute_ ? 0 : point_.x), 261 | values[3] + (absolute_ ? 0 : point_.y)); 262 | return true; 263 | } 264 | 265 | bool PathDataIterator::ParseShorthandQuadBezierCommand() { 266 | CGFloat values[2]; 267 | if (!ConsumeFloats(&s_, ARRAYSIZE(values), values)) { 268 | return false; 269 | } 270 | if (last_command_type_ == kPathCommandTypeQuadBezier || 271 | last_command_type_ == kPathCommandTypeShorthandQuadBezier) { 272 | control_point1_ = CGPointMake(point_.x + (point_.x - control_point1_.x), 273 | point_.y + (point_.y - control_point1_.y)); 274 | } else { 275 | control_point1_ = point_; 276 | } 277 | point_ = CGPointMake(values[0] + (absolute_ ? 0 : point_.x), 278 | values[1] + (absolute_ ? 0 : point_.y)); 279 | return true; 280 | } 281 | 282 | bool PathDataIterator::ParseEllipticalArcCommand() { 283 | CGFloat values[3]; 284 | if (!ConsumeFloats(&s_, ARRAYSIZE(values), values)) { 285 | return false; 286 | } 287 | // Take absolute values per spec. 288 | // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 289 | arc_radius_x_ = std::fabs(values[0]); 290 | arc_radius_y_ = std::fabs(values[1]); 291 | if (arc_radius_x_ == 0 || arc_radius_y_ == 0) { 292 | return false; 293 | } 294 | rotation_ = values[2]; 295 | 296 | ConsumeNumberDelimiter(&s_); 297 | if (!ConsumeFlag(&s_, &large_arc_)) { 298 | return false; 299 | } 300 | 301 | ConsumeNumberDelimiter(&s_); 302 | if (!ConsumeFlag(&s_, &sweep_)) { 303 | return false; 304 | } 305 | 306 | ConsumeNumberDelimiter(&s_); 307 | CGFloat point_coords[2]; 308 | if (!ConsumeFloats(&s_, ARRAYSIZE(point_coords), point_coords)) { 309 | return false; 310 | } 311 | point_ = CGPointMake(point_coords[0] + (absolute_ ? 0 : point_.x), 312 | point_coords[1] + (absolute_ ? 0 : point_.y)); 313 | return true; 314 | } 315 | 316 | } // namespace internal 317 | } // namespace metrosvg 318 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------