Jelajahi Sumber

Skia integration - preprocessing of shape geometry

Viktor Chlumský 4 tahun lalu
induk
melakukan
9d22335ea0
100 mengubah file dengan 21611 tambahan dan 57 penghapusan
  1. 1 0
      .gitattributes
  2. 11 9
      .gitignore
  3. 19 0
      CHANGELOG.md
  4. 8 1
      CMakeLists.txt
  5. TEMPAT SAMPAH
      Msdfgen.aps
  6. TEMPAT SAMPAH
      Msdfgen.rc
  7. 38 36
      Msdfgen.vcxproj
  8. 6 0
      Msdfgen.vcxproj.filters
  9. 2 1
      README.md
  10. 89 0
      ext/resolve-shape-geometry.cpp
  11. 15 0
      ext/resolve-shape-geometry.h
  12. 67 7
      main.cpp
  13. 4 1
      msdfgen-ext.h
  14. 2 2
      msdfgen.h
  15. 29 0
      skia/LICENSE
  16. 40 0
      skia/include/android/SkAndroidFrameworkUtils.h
  17. 154 0
      skia/include/android/SkAnimatedImage.h
  18. 29 0
      skia/include/android/SkBRDAllocator.h
  19. 92 0
      skia/include/android/SkBitmapRegionDecoder.h
  20. 42 0
      skia/include/atlastext/SkAtlasTextContext.h
  21. 35 0
      skia/include/atlastext/SkAtlasTextFont.h
  22. 72 0
      skia/include/atlastext/SkAtlasTextRenderer.h
  23. 100 0
      skia/include/atlastext/SkAtlasTextTarget.h
  24. 159 0
      skia/include/c/sk_canvas.h
  25. 25 0
      skia/include/c/sk_colorspace.h
  26. 70 0
      skia/include/c/sk_data.h
  27. 71 0
      skia/include/c/sk_image.h
  28. 62 0
      skia/include/c/sk_imageinfo.h
  29. 47 0
      skia/include/c/sk_maskfilter.h
  30. 49 0
      skia/include/c/sk_matrix.h
  31. 145 0
      skia/include/c/sk_paint.h
  32. 84 0
      skia/include/c/sk_path.h
  33. 70 0
      skia/include/c/sk_picture.h
  34. 143 0
      skia/include/c/sk_shader.h
  35. 73 0
      skia/include/c/sk_surface.h
  36. 256 0
      skia/include/c/sk_types.h
  37. 287 0
      skia/include/codec/SkAndroidCodec.h
  38. 921 0
      skia/include/codec/SkCodec.h
  39. 43 0
      skia/include/codec/SkCodecAnimation.h
  40. 23 0
      skia/include/codec/SkEncodedOrigin.h
  41. 130 0
      skia/include/config/SkUserConfig.h
  42. 50 0
      skia/include/core/SkAnnotation.h
  43. 31 0
      skia/include/core/SkBBHFactory.h
  44. 1195 0
      skia/include/core/SkBitmap.h
  45. 75 0
      skia/include/core/SkBlendMode.h
  46. 22 0
      skia/include/core/SkBlurTypes.h
  47. 2779 0
      skia/include/core/SkCanvas.h
  48. 93 0
      skia/include/core/SkCanvasVirtualEnforcer.h
  49. 33 0
      skia/include/core/SkClipOp.h
  50. 389 0
      skia/include/core/SkColor.h
  51. 196 0
      skia/include/core/SkColorFilter.h
  52. 163 0
      skia/include/core/SkColorPriv.h
  53. 237 0
      skia/include/core/SkColorSpace.h
  54. 20 0
      skia/include/core/SkColorSpaceXformCanvas.h
  55. 30 0
      skia/include/core/SkCoverageMode.h
  56. 182 0
      skia/include/core/SkData.h
  57. 119 0
      skia/include/core/SkDataTable.h
  58. 165 0
      skia/include/core/SkDeferredDisplayListRecorder.h
  59. 139 0
      skia/include/core/SkDeque.h
  60. 91 0
      skia/include/core/SkDocument.h
  61. 129 0
      skia/include/core/SkDrawLooper.h
  62. 150 0
      skia/include/core/SkDrawable.h
  63. 34 0
      skia/include/core/SkEncodedImageFormat.h
  64. 33 0
      skia/include/core/SkExecutor.h
  65. 26 0
      skia/include/core/SkFilterQuality.h
  66. 107 0
      skia/include/core/SkFlattenable.h
  67. 488 0
      skia/include/core/SkFont.h
  68. 79 0
      skia/include/core/SkFontArguments.h
  69. 58 0
      skia/include/core/SkFontLCDConfig.h
  70. 106 0
      skia/include/core/SkFontMetrics.h
  71. 163 0
      skia/include/core/SkFontMgr.h
  72. 38 0
      skia/include/core/SkFontParameters.h
  73. 80 0
      skia/include/core/SkFontStyle.h
  74. 49 0
      skia/include/core/SkFontTypes.h
  75. 185 0
      skia/include/core/SkGraphics.h
  76. 23 0
      skia/include/core/SkICC.h
  77. 1026 0
      skia/include/core/SkImage.h
  78. 68 0
      skia/include/core/SkImageEncoder.h
  79. 479 0
      skia/include/core/SkImageFilter.h
  80. 207 0
      skia/include/core/SkImageGenerator.h
  81. 623 0
      skia/include/core/SkImageInfo.h
  82. 195 0
      skia/include/core/SkLights.h
  83. 93 0
      skia/include/core/SkMallocPixelRef.h
  84. 77 0
      skia/include/core/SkMaskFilter.h
  85. 75 0
      skia/include/core/SkMath.h
  86. 1863 0
      skia/include/core/SkMatrix.h
  87. 495 0
      skia/include/core/SkMatrix44.h
  88. 175 0
      skia/include/core/SkMetaData.h
  89. 9 0
      skia/include/core/SkMilestone.h
  90. 75 0
      skia/include/core/SkMultiPictureDraw.h
  91. 74 0
      skia/include/core/SkOverdrawCanvas.h
  92. 1427 0
      skia/include/core/SkPaint.h
  93. 1779 0
      skia/include/core/SkPath.h
  94. 187 0
      skia/include/core/SkPathEffect.h
  95. 125 0
      skia/include/core/SkPathMeasure.h
  96. 284 0
      skia/include/core/SkPicture.h
  97. 125 0
      skia/include/core/SkPictureRecorder.h
  98. 129 0
      skia/include/core/SkPixelRef.h
  99. 706 0
      skia/include/core/SkPixmap.h
  100. 45 0
      skia/include/core/SkPngChunkReader.h

+ 1 - 0
.gitattributes

@@ -2,3 +2,4 @@
 include/** linguist-vendored
 include/** linguist-vendored
 lib/** linguist-vendored
 lib/** linguist-vendored
 freetype/** linguist-vendored
 freetype/** linguist-vendored
+skia/** linguist-vendored

+ 11 - 9
.gitignore

@@ -1,11 +1,11 @@
-Debug/
-Release/
-Release OpenMP/
-Debug Library/
-Release Library/
-Release Library OpenMP/
-x86/
-x64/
+/Debug/
+/Release/
+/Release OpenMP/
+/Debug Library/
+/Release Library/
+/Release Library OpenMP/
+/x86/
+/x64/
 .vs/
 .vs/
 *.exe
 *.exe
 *.zip
 *.zip
@@ -17,9 +17,11 @@ x64/
 *.suo
 *.suo
 *.VC.opendb
 *.VC.opendb
 *.VC.db
 *.VC.db
-bin/*.lib
+/bin/*.lib
 output.png
 output.png
 render.png
 render.png
 out/
 out/
 build/
 build/
 build_xcode/
 build_xcode/
+skia/win32/
+skia/win64/

+ 19 - 0
CHANGELOG.md

@@ -1,4 +1,23 @@
 
 
+## Version 1.8 (2020-10-17)
+
+- Integrated the Skia library into the project, which is used to preprocess the shape geometry and eliminate any self-intersections and other irregularities previously unsupported by the software
+    - The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively.
+    - The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`
+- Significantly improved performance of the core algorithm by reusing results from previously computed pixels
+- Introduced an additional error correction routine which eliminates MSDF artifacts by analytically predicting results of bilinear interpolation
+- Added the possibility to load font glyphs by their index rather than a Unicode value (use the prefix `g` before the character code in `-font` argument)
+- Added `-distanceshift` argument that can be used to adjust the center of the distance range in the output distance field
+- Fixed several errors in the evaluation of curve distances
+- Fixed an issue with paths containing convergent corners (those whose inner angle is zero)
+- The algorithm for pseudo-distance computation slightly changed, fixing certain rare edge cases and improving consistency
+- Added the ability to supply own `FT_Face` handle to the msdfgen library
+- Minor refactor of the core algorithm
+
+### Version 1.7.1 (2020-03-09)
+
+- Fixed an edge case bug in scanline rasterization
+
 ## Version 1.7 (2020-03-07)
 ## Version 1.7 (2020-03-07)
 
 
 - Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel
 - Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel

+ 8 - 1
CMakeLists.txt

@@ -1,9 +1,10 @@
 cmake_minimum_required(VERSION 3.10)
 cmake_minimum_required(VERSION 3.10)
 
 
-project(msdfgen VERSION 1.7.1 LANGUAGES CXX)
+project(msdfgen VERSION 1.8 LANGUAGES CXX)
 option(MSDFGEN_BUILD_MSDFGEN_STANDALONE "Build the msdfgen standalone executable" ON)
 option(MSDFGEN_BUILD_MSDFGEN_STANDALONE "Build the msdfgen standalone executable" ON)
 option(MSDFGEN_USE_OPENMP "Build with OpenMP support for multithreaded code" OFF)
 option(MSDFGEN_USE_OPENMP "Build with OpenMP support for multithreaded code" OFF)
 option(MSDFGEN_USE_CPP11 "Build with C++11 enabled" ON)
 option(MSDFGEN_USE_CPP11 "Build with C++11 enabled" ON)
+option(MSDFGEN_USE_SKIA "Build with the Skia library" OFF)
 option(FREETYPE_WITH_PNG "Link libpng and zlib because FreeType is configured to require it" OFF)
 option(FREETYPE_WITH_PNG "Link libpng and zlib because FreeType is configured to require it" OFF)
 option(FREETYPE_WITH_HARFBUZZ "Link HarfBuzz because FreeType is configured to require it" OFF)
 option(FREETYPE_WITH_HARFBUZZ "Link HarfBuzz because FreeType is configured to require it" OFF)
 
 
@@ -71,6 +72,12 @@ if(MSDFGEN_USE_OPENMP)
 	target_compile_definitions(msdfgen PRIVATE MSDFGEN_USE_OPENMP)
 	target_compile_definitions(msdfgen PRIVATE MSDFGEN_USE_OPENMP)
 endif()
 endif()
 
 
+if(MSDFGEN_USE_SKIA)
+	find_package(Skia REQUIRED)
+	target_link_libraries(msdfgen-ext PRIVATE Skia::Skia)
+	target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_USE_SKIA)
+endif()
+
 add_library(msdfgen-ext ${msdfgen-ext_SOURCES} ${msdfgen-ext_PUBLIC_HEADERS} ${msdfgen-ext_PRIVATE_HEADERS} "./msdfgen-ext.h")
 add_library(msdfgen-ext ${msdfgen-ext_SOURCES} ${msdfgen-ext_PUBLIC_HEADERS} ${msdfgen-ext_PRIVATE_HEADERS} "./msdfgen-ext.h")
 add_library(msdfgen::msdfgen-ext ALIAS msdfgen-ext)
 add_library(msdfgen::msdfgen-ext ALIAS msdfgen-ext)
 set_target_properties(msdfgen-ext PROPERTIES
 set_target_properties(msdfgen-ext PROPERTIES

TEMPAT SAMPAH
Msdfgen.aps


TEMPAT SAMPAH
Msdfgen.rc


+ 38 - 36
Msdfgen.vcxproj

@@ -231,13 +231,13 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|Win32'">
@@ -245,9 +245,9 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
@@ -255,7 +255,7 @@
     </Link>
     </Link>
     <Lib>
     <Lib>
       <TargetMachine>MachineX86</TargetMachine>
       <TargetMachine>MachineX86</TargetMachine>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
     <ProjectReference />
     <ProjectReference />
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -264,13 +264,13 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Library|x64'">
@@ -278,12 +278,12 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
     </ClCompile>
     </ClCompile>
     <Lib>
     <Lib>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -293,15 +293,15 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>No</GenerateDebugInformation>
       <GenerateDebugInformation>No</GenerateDebugInformation>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -312,16 +312,16 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;MSDFGEN_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>No</GenerateDebugInformation>
       <GenerateDebugInformation>No</GenerateDebugInformation>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -332,9 +332,9 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -345,7 +345,7 @@
     </Link>
     </Link>
     <Lib>
     <Lib>
       <TargetMachine>MachineX86</TargetMachine>
       <TargetMachine>MachineX86</TargetMachine>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library OpenMP|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library OpenMP|Win32'">
@@ -355,9 +355,9 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -369,7 +369,7 @@
     </Link>
     </Link>
     <Lib>
     <Lib>
       <TargetMachine>MachineX86</TargetMachine>
       <TargetMachine>MachineX86</TargetMachine>
-      <AdditionalLibraryDirectories>freetype/win32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -379,15 +379,15 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>false</GenerateDebugInformation>
       <GenerateDebugInformation>false</GenerateDebugInformation>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -398,8 +398,8 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     </ClCompile>
@@ -407,7 +407,7 @@
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>false</GenerateDebugInformation>
       <GenerateDebugInformation>false</GenerateDebugInformation>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
@@ -418,8 +418,8 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
     </ClCompile>
     </ClCompile>
     <Link>
     <Link>
@@ -427,7 +427,7 @@
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
     </Link>
     <Lib>
     <Lib>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library OpenMP|x64'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Library OpenMP|x64'">
@@ -437,8 +437,8 @@
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>include;freetype/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <AdditionalIncludeDirectories>include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     </ClCompile>
@@ -447,7 +447,7 @@
       <OptimizeReferences>true</OptimizeReferences>
       <OptimizeReferences>true</OptimizeReferences>
     </Link>
     </Link>
     <Lib>
     <Lib>
-      <AdditionalLibraryDirectories>freetype/win64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalLibraryDirectories>freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Lib>
     </Lib>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>
   <ItemGroup>
@@ -481,6 +481,7 @@
     <ClInclude Include="core\Vector2.h" />
     <ClInclude Include="core\Vector2.h" />
     <ClInclude Include="ext\import-font.h" />
     <ClInclude Include="ext\import-font.h" />
     <ClInclude Include="ext\import-svg.h" />
     <ClInclude Include="ext\import-svg.h" />
+    <ClInclude Include="ext\resolve-shape-geometry.h" />
     <ClInclude Include="ext\save-png.h" />
     <ClInclude Include="ext\save-png.h" />
     <ClInclude Include="msdfgen-ext.h" />
     <ClInclude Include="msdfgen-ext.h" />
     <ClInclude Include="msdfgen.h" />
     <ClInclude Include="msdfgen.h" />
@@ -508,6 +509,7 @@
     <ClCompile Include="core\Vector2.cpp" />
     <ClCompile Include="core\Vector2.cpp" />
     <ClCompile Include="ext\import-font.cpp" />
     <ClCompile Include="ext\import-font.cpp" />
     <ClCompile Include="ext\import-svg.cpp" />
     <ClCompile Include="ext\import-svg.cpp" />
+    <ClCompile Include="ext\resolve-shape-geometry.cpp" />
     <ClCompile Include="ext\save-png.cpp" />
     <ClCompile Include="ext\save-png.cpp" />
     <ClCompile Include="lib\lodepng.cpp" />
     <ClCompile Include="lib\lodepng.cpp" />
     <ClCompile Include="lib\tinyxml2.cpp" />
     <ClCompile Include="lib\tinyxml2.cpp" />

+ 6 - 0
Msdfgen.vcxproj.filters

@@ -120,6 +120,9 @@
     <ClInclude Include="core\msdf-edge-artifact-patcher.h">
     <ClInclude Include="core\msdf-edge-artifact-patcher.h">
       <Filter>Core</Filter>
       <Filter>Core</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="ext\resolve-shape-geometry.h">
+      <Filter>Extensions</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="main.cpp">
     <ClCompile Include="main.cpp">
@@ -200,6 +203,9 @@
     <ClCompile Include="core\msdf-edge-artifact-patcher.cpp">
     <ClCompile Include="core\msdf-edge-artifact-patcher.cpp">
       <Filter>Core</Filter>
       <Filter>Core</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="ext\resolve-shape-geometry.cpp">
+      <Filter>Extensions</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Msdfgen.rc">
     <ResourceCompile Include="Msdfgen.rc">

+ 2 - 1
README.md

@@ -26,7 +26,8 @@ Extensions contain utilities for loading fonts and SVG files, as well as saving
 Those are exposed by the [msdfgen-ext.h](msdfgen-ext.h) header. This module uses
 Those are exposed by the [msdfgen-ext.h](msdfgen-ext.h) header. This module uses
 [FreeType](http://www.freetype.org/),
 [FreeType](http://www.freetype.org/),
 [TinyXML2](http://www.grinninglizard.com/tinyxml2/),
 [TinyXML2](http://www.grinninglizard.com/tinyxml2/),
-and [LodePNG](http://lodev.org/lodepng/).
+[LodePNG](http://lodev.org/lodepng/),
+and (optionally) [Skia](https://skia.org/).
 
 
 Additionally, there is the [main.cpp](main.cpp), which wraps the functionality into
 Additionally, there is the [main.cpp](main.cpp), which wraps the functionality into
 a comprehensive standalone console program. To start using the program immediately,
 a comprehensive standalone console program. To start using the program immediately,

+ 89 - 0
ext/resolve-shape-geometry.cpp

@@ -0,0 +1,89 @@
+
+#include "resolve-shape-geometry.h"
+
+#ifdef MSDFGEN_USE_SKIA
+
+#include <core/SkPath.h>
+#include <pathops/SkPathOps.h>
+#include "../core/Vector2.h"
+#include "../core/edge-segments.h"
+#include "../core/Contour.h"
+
+#ifdef _WIN32
+    #pragma comment(lib, "skia.lib")
+#endif
+
+namespace msdfgen {
+
+SkPoint pointToSkiaPoint(Point2 p) {
+    return SkPoint::Make((SkScalar) p.x, (SkScalar) p.y);
+}
+
+Point2 pointFromSkiaPoint(const SkPoint p) {
+    return Point2((double) p.x(), (double) p.y());
+}
+
+void shapeToSkiaPath(SkPath &skPath, const Shape &shape) {
+    for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
+        if (!contour->edges.empty()) {
+            skPath.moveTo(pointToSkiaPoint(contour->edges.front()->point(0)));
+            for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
+                {
+                    const LinearSegment *linearSegment = dynamic_cast<const LinearSegment *>(&**edge);
+                    if (linearSegment)
+                        skPath.lineTo(pointToSkiaPoint(linearSegment->p[1]));
+                } {
+                    const QuadraticSegment *quadraticSegment = dynamic_cast<const QuadraticSegment *>(&**edge);
+                    if (quadraticSegment)
+                        skPath.quadTo(pointToSkiaPoint(quadraticSegment->p[1]), pointToSkiaPoint(quadraticSegment->p[2]));
+                } {
+                    const CubicSegment *cubicSegment = dynamic_cast<const CubicSegment *>(&**edge);
+                    if (cubicSegment)
+                        skPath.cubicTo(pointToSkiaPoint(cubicSegment->p[1]), pointToSkiaPoint(cubicSegment->p[2]), pointToSkiaPoint(cubicSegment->p[3]));
+                }
+            }
+        }
+    }
+}
+
+void shapeFromSkiaPath(Shape &shape, const SkPath &skPath) {
+    shape.contours.clear();
+    Contour *contour = &shape.addContour();
+    SkPath::Iter pathIterator(skPath, true);
+    SkPoint edgePoints[4];
+    for (SkPath::Verb op; (op = pathIterator.next(edgePoints)) != SkPath::kDone_Verb;) {
+        switch (op) {
+            case SkPath::kMove_Verb:
+                if (!contour->edges.empty())
+                    contour = &shape.addContour();
+                break;
+            case SkPath::kLine_Verb:
+                contour->addEdge(new LinearSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1])));
+                break;
+            case SkPath::kQuad_Verb:
+                contour->addEdge(new QuadraticSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2])));
+                break;
+            case SkPath::kCubic_Verb:
+                contour->addEdge(new CubicSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]), pointFromSkiaPoint(edgePoints[3])));
+                break;
+            default:;
+        }
+    }
+    if (contour->edges.empty())
+        shape.contours.pop_back();
+}
+
+bool resolveShapeGeometry(Shape &shape) {
+    SkPath skPath;
+    shapeToSkiaPath(skPath, shape);
+    if (!Simplify(skPath, &skPath))
+        return false;
+    // Skia's AsWinding doesn't seem to work for unknown reasons
+    shapeFromSkiaPath(shape, skPath);
+    shape.orientContours();
+    return true;
+}
+
+}
+
+#endif

+ 15 - 0
ext/resolve-shape-geometry.h

@@ -0,0 +1,15 @@
+
+#pragma once
+
+#include "../core/Shape.h"
+
+#ifdef MSDFGEN_USE_SKIA
+
+namespace msdfgen {
+
+/// Resolves any intersections within the shape by subdividing its contours using the Skia library and makes sure its contours have a consistent winding.
+bool resolveShapeGeometry(Shape &shape);
+
+}
+
+#endif

+ 67 - 7
main.cpp

@@ -1,6 +1,6 @@
 
 
 /*
 /*
- * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07) - standalone console program
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.8 (2020-10-17) - standalone console program
  * --------------------------------------------------------------------------------------------
  * --------------------------------------------------------------------------------------------
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  *
  *
@@ -252,10 +252,24 @@ static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const ch
     return NULL;
     return NULL;
 }
 }
 
 
+#if defined(MSDFGEN_USE_SKIA) && defined(MSDFGEN_USE_OPENMP)
+    #define TITLE_SUFFIX    " with Skia & OpenMP"
+    #define EXTRA_UNDERLINE "-------------------"
+#elif defined(MSDFGEN_USE_SKIA)
+    #define TITLE_SUFFIX    " with Skia"
+    #define EXTRA_UNDERLINE "----------"
+#elif defined(MSDFGEN_USE_OPENMP)
+    #define TITLE_SUFFIX    " with OpenMP"
+    #define EXTRA_UNDERLINE "------------"
+#else
+    #define TITLE_SUFFIX
+    #define EXTRA_UNDERLINE
+#endif
+
 static const char *helpText =
 static const char *helpText =
     "\n"
     "\n"
-    "Multi-channel signed distance field generator by Viktor Chlumsky v" MSDFGEN_VERSION "\n"
-    "---------------------------------------------------------------------\n"
+    "Multi-channel signed distance field generator by Viktor Chlumsky v" MSDFGEN_VERSION TITLE_SUFFIX "\n"
+    "---------------------------------------------------------------------" EXTRA_UNDERLINE "\n"
     "  Usage: msdfgen"
     "  Usage: msdfgen"
     #ifdef _WIN32
     #ifdef _WIN32
         ".exe"
         ".exe"
@@ -273,7 +287,8 @@ static const char *helpText =
     "  -defineshape <definition>\n"
     "  -defineshape <definition>\n"
         "\tDefines input shape using the ad-hoc text definition.\n"
         "\tDefines input shape using the ad-hoc text definition.\n"
     "  -font <filename.ttf> <character code>\n"
     "  -font <filename.ttf> <character code>\n"
-        "\tLoads a single glyph from the specified font file. Format of character code is '?', 63, 0x3F (Unicode value), or g34 (glyph index).\n"
+        "\tLoads a single glyph from the specified font file.\n"
+        "\tFormat of character code is '?', 63, 0x3F (Unicode value), or g34 (glyph index).\n"
     "  -shapedesc <filename.txt>\n"
     "  -shapedesc <filename.txt>\n"
         "\tLoads text shape description from a file.\n"
         "\tLoads text shape description from a file.\n"
     "  -stdin\n"
     "  -stdin\n"
@@ -281,6 +296,7 @@ static const char *helpText =
     "  -svg <filename.svg>\n"
     "  -svg <filename.svg>\n"
         "\tLoads the last vector path found in the specified SVG file.\n"
         "\tLoads the last vector path found in the specified SVG file.\n"
     "\n"
     "\n"
+    // Keep alphabetical order!
     "OPTIONS\n"
     "OPTIONS\n"
     "  -angle <angle>\n"
     "  -angle <angle>\n"
         "\tSpecifies the minimum angle between adjacent edges to be considered a corner. Append D for degrees.\n"
         "\tSpecifies the minimum angle between adjacent edges to be considered a corner. Append D for degrees.\n"
@@ -310,12 +326,21 @@ static const char *helpText =
         "\tDisplays this help.\n"
         "\tDisplays this help.\n"
     "  -legacy\n"
     "  -legacy\n"
         "\tUses the original (legacy) distance field algorithms.\n"
         "\tUses the original (legacy) distance field algorithms.\n"
+#ifdef MSDFGEN_USE_SKIA
+    "  -nopreprocess\n"
+        "\tDisables path preprocessing which resolves self-intersections and overlapping contours.\n"
+#else
     "  -nooverlap\n"
     "  -nooverlap\n"
         "\tDisables resolution of overlapping contours.\n"
         "\tDisables resolution of overlapping contours.\n"
     "  -noscanline\n"
     "  -noscanline\n"
         "\tDisables the scanline pass, which corrects the distance field's signs according to the selected fill rule.\n"
         "\tDisables the scanline pass, which corrects the distance field's signs according to the selected fill rule.\n"
+#endif
     "  -o <filename>\n"
     "  -o <filename>\n"
         "\tSets the output file name. The default value is \"output.png\".\n"
         "\tSets the output file name. The default value is \"output.png\".\n"
+#ifdef MSDFGEN_USE_SKIA
+    "  -overlap\n"
+        "\tSwitches to distance field generator with support for overlapping contours.\n"
+#endif
     "  -printmetrics\n"
     "  -printmetrics\n"
         "\tPrints relevant metrics of the shape to the standard output.\n"
         "\tPrints relevant metrics of the shape to the standard output.\n"
     "  -pxrange <range>\n"
     "  -pxrange <range>\n"
@@ -323,9 +348,13 @@ static const char *helpText =
     "  -range <range>\n"
     "  -range <range>\n"
         "\tSets the width of the range between the lowest and highest signed distance in shape units.\n"
         "\tSets the width of the range between the lowest and highest signed distance in shape units.\n"
     "  -reverseorder\n"
     "  -reverseorder\n"
-        "\tGenerates the distance field as if shape vertices were in reverse order.\n"
+        "\tGenerates the distance field as if the shape's vertices were in reverse order.\n"
     "  -scale <scale>\n"
     "  -scale <scale>\n"
         "\tSets the scale used to convert shape units to pixels.\n"
         "\tSets the scale used to convert shape units to pixels.\n"
+#ifdef MSDFGEN_USE_SKIA
+    "  -scanline\n"
+        "\tPerforms an additional scanline pass to fix the signs of the distances.\n"
+#endif
     "  -seed <n>\n"
     "  -seed <n>\n"
         "\tSets the random seed for edge coloring heuristic.\n"
         "\tSets the random seed for edge coloring heuristic.\n"
     "  -size <width> <height>\n"
     "  -size <width> <height>\n"
@@ -362,8 +391,15 @@ int main(int argc, const char * const *argv) {
         METRICS
         METRICS
     } mode = MULTI;
     } mode = MULTI;
     bool legacyMode = false;
     bool legacyMode = false;
-    bool overlapSupport = true;
-    bool scanlinePass = true;
+    bool geometryPreproc = (
+        #ifdef MSDFGEN_USE_SKIA
+            true
+        #else
+            false
+        #endif
+    );
+    bool overlapSupport = !geometryPreproc;
+    bool scanlinePass = !geometryPreproc;
     FillRule fillRule = FILL_NONZERO;
     FillRule fillRule = FILL_NONZERO;
     Format format = AUTO;
     Format format = AUTO;
     const char *input = NULL;
     const char *input = NULL;
@@ -477,11 +513,26 @@ int main(int argc, const char * const *argv) {
             argPos += 1;
             argPos += 1;
             continue;
             continue;
         }
         }
+        ARG_CASE("-nopreprocess", 0) {
+            geometryPreproc = false;
+            argPos += 1;
+            continue;
+        }
+        ARG_CASE("-preprocess", 0) {
+            geometryPreproc = true;
+            argPos += 1;
+            continue;
+        }
         ARG_CASE("-nooverlap", 0) {
         ARG_CASE("-nooverlap", 0) {
             overlapSupport = false;
             overlapSupport = false;
             argPos += 1;
             argPos += 1;
             continue;
             continue;
         }
         }
+        ARG_CASE("-overlap", 0) {
+            overlapSupport = true;
+            argPos += 1;
+            continue;
+        }
         ARG_CASE("-noscanline", 0) {
         ARG_CASE("-noscanline", 0) {
             scanlinePass = false;
             scanlinePass = false;
             argPos += 1;
             argPos += 1;
@@ -493,6 +544,7 @@ int main(int argc, const char * const *argv) {
             continue;
             continue;
         }
         }
         ARG_CASE("-fillrule", 1) {
         ARG_CASE("-fillrule", 1) {
+            scanlinePass = true;
             if (!strcmp(argv[argPos+1], "nonzero")) fillRule = FILL_NONZERO;
             if (!strcmp(argv[argPos+1], "nonzero")) fillRule = FILL_NONZERO;
             else if (!strcmp(argv[argPos+1], "evenodd") || !strcmp(argv[argPos+1], "odd")) fillRule = FILL_ODD;
             else if (!strcmp(argv[argPos+1], "evenodd") || !strcmp(argv[argPos+1], "odd")) fillRule = FILL_ODD;
             else if (!strcmp(argv[argPos+1], "positive")) fillRule = FILL_POSITIVE;
             else if (!strcmp(argv[argPos+1], "positive")) fillRule = FILL_POSITIVE;
@@ -749,6 +801,14 @@ int main(int argc, const char * const *argv) {
     // Validate and normalize shape
     // Validate and normalize shape
     if (!shape.validate())
     if (!shape.validate())
         ABORT("The geometry of the loaded shape is invalid.");
         ABORT("The geometry of the loaded shape is invalid.");
+    if (geometryPreproc) {
+        #ifdef MSDFGEN_USE_SKIA
+            if (!resolveShapeGeometry(shape))
+                puts("Shape geometry preprocessing failed, skipping.");
+        #else
+            ABORT("Shape geometry preprocessing (-preprocess) is not available in this version because the Skia library is not present.");
+        #endif
+    }
     shape.normalize();
     shape.normalize();
     if (yFlip)
     if (yFlip)
         shape.inverseYAxis = !shape.inverseYAxis;
         shape.inverseYAxis = !shape.inverseYAxis;

+ 4 - 1
msdfgen-ext.h

@@ -2,13 +2,15 @@
 #pragma once
 #pragma once
 
 
 /*
 /*
- * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07) - extensions
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.8 (2020-10-17) - extensions
  * ----------------------------------------------------------------------------
  * ----------------------------------------------------------------------------
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  *
  *
  * The extension module provides ways to easily load input and save output using popular formats.
  * The extension module provides ways to easily load input and save output using popular formats.
  *
  *
  * Third party dependencies in extension module:
  * Third party dependencies in extension module:
+ * - Skia by Google
+ *   (to resolve self-intersecting paths)
  * - FreeType 2
  * - FreeType 2
  *   (to load input font files)
  *   (to load input font files)
  * - TinyXML 2 by Lee Thomason
  * - TinyXML 2 by Lee Thomason
@@ -18,6 +20,7 @@
  *
  *
  */
  */
 
 
+#include "ext/resolve-shape-geometry.h"
 #include "ext/save-png.h"
 #include "ext/save-png.h"
 #include "ext/import-svg.h"
 #include "ext/import-svg.h"
 #include "ext/import-font.h"
 #include "ext/import-font.h"

+ 2 - 2
msdfgen.h

@@ -2,7 +2,7 @@
 #pragma once
 #pragma once
 
 
 /*
 /*
- * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.7 (2020-03-07)
+ * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR v1.8 (2020-10-17)
  * ---------------------------------------------------------------
  * ---------------------------------------------------------------
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  * A utility by Viktor Chlumsky, (c) 2014 - 2020
  *
  *
@@ -32,7 +32,7 @@
 #include "core/save-tiff.h"
 #include "core/save-tiff.h"
 #include "core/shape-description.h"
 #include "core/shape-description.h"
 
 
-#define MSDFGEN_VERSION "1.7"
+#define MSDFGEN_VERSION "1.8"
 
 
 namespace msdfgen {
 namespace msdfgen {
 
 

+ 29 - 0
skia/LICENSE

@@ -0,0 +1,29 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+--------------------------------------------------------------------------------

+ 40 - 0
skia/include/android/SkAndroidFrameworkUtils.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAndroidFrameworkUtils_DEFINED
+#define SkAndroidFrameworkUtils_DEFINED
+
+#include "SkTypes.h"
+
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+
+class SkCanvas;
+
+/**
+ *  SkAndroidFrameworkUtils expose private APIs used only by Android framework.
+ */
+class SkAndroidFrameworkUtils {
+public:
+
+#if SK_SUPPORT_GPU
+    /**
+     *  clipWithStencil draws the current clip into a stencil buffer with reference value and mask
+     *  set to 0x1. This function works only on a GPU canvas.
+     *
+     *  @param  canvas A GPU canvas that has a non-empty clip.
+     *
+     *  @return true on success or false if clip is empty or not a GPU canvas.
+     */
+    static bool clipWithStencil(SkCanvas* canvas);
+#endif //SK_SUPPORT_GPU
+
+    static void SafetyNetLog(const char*);
+};
+
+#endif // SK_BUILD_FOR_ANDROID_ANDROID
+
+#endif // SkAndroidFrameworkUtils_DEFINED

+ 154 - 0
skia/include/android/SkAnimatedImage.h

@@ -0,0 +1,154 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAnimatedImage_DEFINED
+#define SkAnimatedImage_DEFINED
+
+#include "SkBitmap.h"
+#include "SkCodecAnimation.h"
+#include "SkDrawable.h"
+#include "SkMatrix.h"
+#include "SkRect.h"
+
+class SkAndroidCodec;
+class SkPicture;
+
+/**
+ *  Thread unsafe drawable for drawing animated images (e.g. GIF).
+ */
+class SK_API SkAnimatedImage : public SkDrawable {
+public:
+    /**
+     *  Create an SkAnimatedImage from the SkAndroidCodec.
+     *
+     *  Returns null on failure to allocate pixels. On success, this will
+     *  decode the first frame.
+     *
+     *  @param scaledSize Size to draw the image, possibly requiring scaling.
+     *  @param cropRect Rectangle to crop to after scaling.
+     *  @param postProcess Picture to apply after scaling and cropping.
+     */
+    static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>,
+            SkISize scaledSize, SkIRect cropRect, sk_sp<SkPicture> postProcess);
+
+    /**
+     *  Simpler version that uses the default size, no cropping, and no postProcess.
+     */
+    static sk_sp<SkAnimatedImage> Make(std::unique_ptr<SkAndroidCodec>);
+
+    ~SkAnimatedImage() override;
+
+    /**
+     *  Reset the animation to the beginning.
+     */
+    void reset();
+
+    /**
+     *  Whether the animation completed.
+     *
+     *  Returns true after all repetitions are complete, or an error stops the
+     *  animation. Gets reset to false if the animation is restarted.
+     */
+    bool isFinished() const { return fFinished; }
+
+    /**
+     * Returned by decodeNextFrame and currentFrameDuration if the animation
+     * is not running.
+     */
+    static constexpr int kFinished = -1;
+
+    /**
+     *  Decode the next frame.
+     *
+     *  If the animation is on the last frame or has hit an error, returns
+     *  kFinished.
+     */
+    int decodeNextFrame();
+
+    /**
+     *  How long to display the current frame.
+     *
+     *  Useful for the first frame, for which decodeNextFrame is called
+     *  internally.
+     */
+    int currentFrameDuration() {
+        return fCurrentFrameDuration;
+    }
+
+    /**
+     *  Change the repetition count.
+     *
+     *  By default, the image will repeat the number of times indicated in the
+     *  encoded data.
+     *
+     *  Use SkCodec::kRepetitionCountInfinite for infinite, and 0 to show all
+     *  frames once and then stop.
+     */
+    void setRepetitionCount(int count);
+
+    /**
+     *  Return the currently set repetition count.
+     */
+    int getRepetitionCount() const {
+        return fRepetitionCount;
+    }
+
+protected:
+    SkRect onGetBounds() override;
+    void onDraw(SkCanvas*) override;
+
+private:
+    struct Frame {
+        SkBitmap fBitmap;
+        int      fIndex;
+        SkCodecAnimation::DisposalMethod fDisposalMethod;
+
+        // init() may have to create a new SkPixelRef, if the
+        // current one is already in use by another owner (e.g.
+        // an SkPicture). This determines whether to copy the
+        // existing one to the new one.
+        enum class OnInit {
+            // Restore the image from the old SkPixelRef to the
+            // new one.
+            kRestoreIfNecessary,
+            // No need to restore.
+            kNoRestore,
+        };
+
+        Frame();
+        bool init(const SkImageInfo& info, OnInit);
+        bool copyTo(Frame*) const;
+    };
+
+    std::unique_ptr<SkAndroidCodec> fCodec;
+    const SkISize                   fScaledSize;
+    const SkImageInfo               fDecodeInfo;
+    const SkIRect                   fCropRect;
+    const sk_sp<SkPicture>          fPostProcess;
+    const int                       fFrameCount;
+    const bool                      fSimple;     // no crop, scale, or postprocess
+    SkMatrix                        fMatrix;     // used only if !fSimple
+
+    bool                            fFinished;
+    int                             fCurrentFrameDuration;
+    Frame                           fDisplayFrame;
+    Frame                           fDecodingFrame;
+    Frame                           fRestoreFrame;
+    int                             fRepetitionCount;
+    int                             fRepetitionsCompleted;
+
+    SkAnimatedImage(std::unique_ptr<SkAndroidCodec>, SkISize scaledSize,
+            SkImageInfo decodeInfo, SkIRect cropRect, sk_sp<SkPicture> postProcess);
+    SkAnimatedImage(std::unique_ptr<SkAndroidCodec>);
+
+    int computeNextFrame(int current, bool* animationEnded);
+    double finish();
+
+    typedef SkDrawable INHERITED;
+};
+
+#endif // SkAnimatedImage_DEFINED

+ 29 - 0
skia/include/android/SkBRDAllocator.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBRDAllocator_DEFINED
+#define SkBRDAllocator_DEFINED
+
+#include "SkBitmap.h"
+#include "SkCodec.h"
+
+/**
+ *  Abstract subclass of SkBitmap's allocator.
+ *  Allows the allocator to indicate if the memory it allocates
+ *  is zero initialized.
+ */
+class SkBRDAllocator : public SkBitmap::Allocator {
+public:
+
+    /**
+     *  Indicates if the memory allocated by this allocator is
+     *  zero initialized.
+     */
+    virtual SkCodec::ZeroInitialized zeroInit() const = 0;
+};
+
+#endif // SkBRDAllocator_DEFINED

+ 92 - 0
skia/include/android/SkBitmapRegionDecoder.h

@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBitmapRegionDecoder_DEFINED
+#define SkBitmapRegionDecoder_DEFINED
+
+#include "SkBitmap.h"
+#include "SkBRDAllocator.h"
+#include "SkEncodedImageFormat.h"
+#include "SkStream.h"
+
+/*
+ * This class aims to provide an interface to test multiple implementations of
+ * SkBitmapRegionDecoder.
+ */
+class SK_API SkBitmapRegionDecoder {
+public:
+
+    enum Strategy {
+        kAndroidCodec_Strategy, // Uses SkAndroidCodec for scaling and subsetting
+    };
+
+    /*
+     * @param data     Refs the data while this object exists, unrefs on destruction
+     * @param strategy Strategy used for scaling and subsetting
+     * @return         Tries to create an SkBitmapRegionDecoder, returns NULL on failure
+     */
+    static SkBitmapRegionDecoder* Create(sk_sp<SkData>, Strategy strategy);
+
+    /*
+     * @param stream   Takes ownership of the stream
+     * @param strategy Strategy used for scaling and subsetting
+     * @return         Tries to create an SkBitmapRegionDecoder, returns NULL on failure
+     */
+    static SkBitmapRegionDecoder* Create(
+            SkStreamRewindable* stream, Strategy strategy);
+
+    /*
+     * Decode a scaled region of the encoded image stream
+     *
+     * @param bitmap          Container for decoded pixels.  It is assumed that the pixels
+     *                        are initially unallocated and will be allocated by this function.
+     * @param allocator       Allocator for the pixels.  If this is NULL, the default
+     *                        allocator (HeapAllocator) will be used.
+     * @param desiredSubset   Subset of the original image to decode.
+     * @param sampleSize      An integer downscaling factor for the decode.
+     * @param colorType       Preferred output colorType.
+     *                        New implementations should return NULL if they do not support
+     *                        decoding to this color type.
+     *                        The old kOriginal_Strategy will decode to a default color type
+     *                        if this color type is unsupported.
+     * @param requireUnpremul If the image is not opaque, we will use this to determine the
+     *                        alpha type to use.
+     * @param prefColorSpace  If non-null and supported, this is the color space that we will
+     *                        decode into.  Otherwise, we will choose a default.
+     *
+     */
+    virtual bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator,
+                              const SkIRect& desiredSubset, int sampleSize,
+                              SkColorType colorType, bool requireUnpremul,
+                              sk_sp<SkColorSpace> prefColorSpace = nullptr) = 0;
+
+    virtual SkEncodedImageFormat getEncodedFormat() = 0;
+
+    virtual SkColorType computeOutputColorType(SkColorType requestedColorType) = 0;
+
+    virtual sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType,
+            sk_sp<SkColorSpace> prefColorSpace = nullptr) = 0;
+
+
+    int width() const { return fWidth; }
+    int height() const { return fHeight; }
+
+    virtual ~SkBitmapRegionDecoder() {}
+
+protected:
+
+    SkBitmapRegionDecoder(int width, int height)
+        : fWidth(width)
+        , fHeight(height)
+    {}
+
+private:
+    const int fWidth;
+    const int fHeight;
+};
+
+#endif

+ 42 - 0
skia/include/atlastext/SkAtlasTextContext.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAtlasTextContext_DEFINED
+#define SkAtlasTextContext_DEFINED
+
+#include "SkRefCnt.h"
+
+class SkAtlasTextRenderer;
+class SkInternalAtlasTextContext;
+
+SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext(class SkInternalAtlasTextContext&);
+
+/**
+ * Class that Atlas Text client uses to register their SkAtlasTextRenderer implementation and
+ * to create one or more SkAtlasTextTargets (destination surfaces for text rendering).
+ */
+class SK_API SkAtlasTextContext : public SkRefCnt {
+public:
+    static sk_sp<SkAtlasTextContext> Make(sk_sp<SkAtlasTextRenderer>);
+
+    SkAtlasTextRenderer* renderer() const {
+        return SkGetAtlasTextRendererFromInternalContext(*fInternalContext);
+    }
+
+    SkInternalAtlasTextContext& internal() { return *fInternalContext; }
+
+private:
+    SkAtlasTextContext() = delete;
+    SkAtlasTextContext(const SkAtlasTextContext&) = delete;
+    SkAtlasTextContext& operator=(const SkAtlasTextContext&) = delete;
+
+    SkAtlasTextContext(sk_sp<SkAtlasTextRenderer>);
+
+    std::unique_ptr<SkInternalAtlasTextContext> fInternalContext;
+};
+
+#endif

+ 35 - 0
skia/include/atlastext/SkAtlasTextFont.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAtlasTextFont_DEFINED
+#define SkAtlasTextFont_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkTypeface.h"
+
+/** Represents a font at a size. TODO: What else do we need here (skewX, scaleX, vertical, ...)? */
+class SK_API SkAtlasTextFont : public SkRefCnt {
+public:
+    static sk_sp<SkAtlasTextFont> Make(sk_sp<SkTypeface> typeface, SkScalar size) {
+        return sk_sp<SkAtlasTextFont>(new SkAtlasTextFont(std::move(typeface), size));
+    }
+
+    SkTypeface* typeface() const { return fTypeface.get(); }
+
+    sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
+
+    SkScalar size() const { return fSize; }
+
+private:
+    SkAtlasTextFont(sk_sp<SkTypeface> typeface, SkScalar size)
+            : fTypeface(std::move(typeface)), fSize(size) {}
+
+    sk_sp<SkTypeface> fTypeface;
+    SkScalar fSize;
+};
+
+#endif

+ 72 - 0
skia/include/atlastext/SkAtlasTextRenderer.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPoint3.h"
+#include "SkRefCnt.h"
+
+#ifndef SkAtlasTextRenderer_DEFINED
+#define SkAtlasTextRenderer_DEFINED
+
+/**
+ * This is the base class for a renderer implemented by the SkAtlasText client. The
+ * SkAtlasTextContext issues texture creations, deletions, uploads, and vertex draws to the
+ * renderer. The renderer must perform those actions in the order called to correctly render
+ * the text drawn to SkAtlasTextTargets.
+ */
+class SK_API SkAtlasTextRenderer : public SkRefCnt {
+public:
+    enum class AtlasFormat {
+        /** Unsigned normalized 8 bit single channel format. */
+        kA8
+    };
+
+    struct SDFVertex {
+        /** Position in device space (not normalized). The third component is w (not z). */
+        SkPoint3 fPosition;
+        /** Color, same value for all four corners of a glyph quad. */
+        uint32_t fColor;
+        /** Texture coordinate (in texel units, not normalized). */
+        int16_t fTextureCoordX;
+        int16_t fTextureCoordY;
+    };
+
+    virtual ~SkAtlasTextRenderer() = default;
+
+    /**
+     * Create a texture of the provided format with dimensions 'width' x 'height'
+     * and return a unique handle.
+     */
+    virtual void* createTexture(AtlasFormat, int width, int height) = 0;
+
+    /**
+     * Delete the texture with the passed handle.
+     */
+    virtual void deleteTexture(void* textureHandle) = 0;
+
+    /**
+     * Place the pixel data specified by 'data' in the texture with handle
+     * 'textureHandle' in the rectangle ['x', 'x' + 'width') x ['y', 'y' + 'height').
+     * 'rowBytes' specifies the byte offset between successive rows in 'data' and will always be
+     * a multiple of the number of bytes per pixel.
+     * The pixel format of data is the same as that of 'textureHandle'.
+     */
+    virtual void setTextureData(void* textureHandle, const void* data, int x, int y, int width,
+                                int height, size_t rowBytes) = 0;
+
+    /**
+     * Draws glyphs using SDFs. The SDF data resides in 'textureHandle'. The array
+     * 'vertices' provides interleaved device-space positions, colors, and
+     * texture coordinates. There are are 4 * 'quadCnt' entries in 'vertices'.
+     */
+    virtual void drawSDFGlyphs(void* targetHandle, void* textureHandle, const SDFVertex vertices[],
+                               int quadCnt) = 0;
+
+    /** Called when a SkAtlasTextureTarget is destroyed. */
+    virtual void targetDeleted(void* targetHandle) = 0;
+};
+
+#endif

+ 100 - 0
skia/include/atlastext/SkAtlasTextTarget.h

@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAtlasTextTarget_DEFINED
+#define SkAtlasTextTarget_DEFINED
+
+#include "SkDeque.h"
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+
+#include <memory>
+
+class SkAtlasTextContext;
+class SkAtlasTextFont;
+class SkMatrix;
+struct SkPoint;
+
+/** Represents a client-created renderable surface and is used to draw text into the surface. */
+class SK_API SkAtlasTextTarget {
+public:
+    virtual ~SkAtlasTextTarget();
+
+    /**
+     * Creates a text drawing target. ‘handle’ is used to identify this rendering surface when
+     * draws are flushed to the SkAtlasTextContext's SkAtlasTextRenderer.
+     */
+    static std::unique_ptr<SkAtlasTextTarget> Make(sk_sp<SkAtlasTextContext>,
+                                                   int width,
+                                                   int height,
+                                                   void* handle);
+
+    /**
+     * Enqueues a text draw in the target. The caller provides an array of glyphs and their
+     * positions. The meaning of 'color' here is interpreted by the client's SkAtlasTextRenderer
+     * when it actually renders the text.
+     */
+    virtual void drawText(const SkGlyphID[], const SkPoint[], int glyphCnt, uint32_t color,
+                          const SkAtlasTextFont&) = 0;
+
+    /** Issues all queued text draws to SkAtlasTextRenderer. */
+    virtual void flush() = 0;
+
+    int width() const { return fWidth; }
+    int height() const { return fHeight; }
+
+    void* handle() const { return fHandle; }
+
+    SkAtlasTextContext* context() const { return fContext.get(); }
+
+    /** Saves the current matrix in a stack. Returns the prior depth of the saved matrix stack. */
+    int save();
+    /** Pops the top matrix on the stack if the stack is not empty. */
+    void restore();
+    /**
+     * Pops the matrix stack until the stack depth is count. Does nothing if the depth is already
+     * less than count.
+     */
+    void restoreToCount(int count);
+
+    /** Pre-translates the current CTM. */
+    void translate(SkScalar dx, SkScalar dy);
+    /** Pre-scales the current CTM. */
+    void scale(SkScalar sx, SkScalar sy);
+    /** Pre-rotates the current CTM about the origin. */
+    void rotate(SkScalar degrees);
+    /** Pre-rotates the current CTM about the (px, py). */
+    void rotate(SkScalar degrees, SkScalar px, SkScalar py);
+    /** Pre-skews the current CTM. */
+    void skew(SkScalar sx, SkScalar sy);
+    /** Pre-concats the current CTM. */
+    void concat(const SkMatrix& matrix);
+
+protected:
+    SkAtlasTextTarget(sk_sp<SkAtlasTextContext>, int width, int height, void* handle);
+
+    const SkMatrix& ctm() const { return *static_cast<const SkMatrix*>(fMatrixStack.back()); }
+
+    void* const fHandle;
+    const sk_sp<SkAtlasTextContext> fContext;
+    const int fWidth;
+    const int fHeight;
+
+private:
+    SkDeque fMatrixStack;
+    int fSaveCnt;
+
+    SkMatrix* accessCTM() const {
+        return static_cast<SkMatrix*>(const_cast<void*>(fMatrixStack.back()));
+    }
+
+    SkAtlasTextTarget() = delete;
+    SkAtlasTextTarget(const SkAtlasTextContext&) = delete;
+    SkAtlasTextTarget& operator=(const SkAtlasTextContext&) = delete;
+};
+
+#endif

+ 159 - 0
skia/include/c/sk_canvas.h

@@ -0,0 +1,159 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_canvas_DEFINED
+#define sk_canvas_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Save the current matrix and clip on the canvas.  When the
+    balancing call to sk_canvas_restore() is made, the previous matrix
+    and clip are restored.
+*/
+SK_API void sk_canvas_save(sk_canvas_t*);
+/**
+    This behaves the same as sk_canvas_save(), but in addition it
+    allocates an offscreen surface. All drawing calls are directed
+    there, and only when the balancing call to sk_canvas_restore() is
+    made is that offscreen transfered to the canvas (or the previous
+    layer).
+
+    @param sk_rect_t* (may be null) This rect, if non-null, is used as
+                      a hint to limit the size of the offscreen, and
+                      thus drawing may be clipped to it, though that
+                      clipping is not guaranteed to happen. If exact
+                      clipping is desired, use sk_canvas_clip_rect().
+    @param sk_paint_t* (may be null) The paint is copied, and is applied
+                       to the offscreen when sk_canvas_restore() is
+                       called.
+*/
+SK_API void sk_canvas_save_layer(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+    This call balances a previous call to sk_canvas_save() or
+    sk_canvas_save_layer(), and is used to remove all modifications to
+    the matrix and clip state since the last save call.  It is an
+    error to call sk_canvas_restore() more times than save and
+    save_layer were called.
+*/
+SK_API void sk_canvas_restore(sk_canvas_t*);
+
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified translation.
+*/
+SK_API void sk_canvas_translate(sk_canvas_t*, float dx, float dy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified scale.
+*/
+SK_API void sk_canvas_scale(sk_canvas_t*, float sx, float sy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified rotation in degrees.
+*/
+SK_API void sk_canvas_rotate_degrees(sk_canvas_t*, float degrees);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified rotation in radians.
+*/
+SK_API void sk_canvas_rotate_radians(sk_canvas_t*, float radians);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified skew.
+*/
+SK_API void sk_canvas_skew(sk_canvas_t*, float sx, float sy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified matrix.
+*/
+SK_API void sk_canvas_concat(sk_canvas_t*, const sk_matrix_t*);
+
+/**
+    Modify the current clip with the specified rectangle.  The new
+    current clip will be the intersection of the old clip and the
+    rectange.
+*/
+SK_API void sk_canvas_clip_rect(sk_canvas_t*, const sk_rect_t*);
+/**
+    Modify the current clip with the specified path.  The new
+    current clip will be the intersection of the old clip and the
+    path.
+*/
+SK_API void sk_canvas_clip_path(sk_canvas_t*, const sk_path_t*);
+
+/**
+    Fill the entire canvas (restricted to the current clip) with the
+    specified paint.
+*/
+SK_API void sk_canvas_draw_paint(sk_canvas_t*, const sk_paint_t*);
+/**
+    Draw the specified rectangle using the specified paint. The
+    rectangle will be filled or stroked based on the style in the
+    paint.
+*/
+SK_API void sk_canvas_draw_rect(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+ *  Draw the circle centered at (cx, cy) with radius rad using the specified paint.
+ *  The circle will be filled or framed based on the style in the paint
+ */
+SK_API void sk_canvas_draw_circle(sk_canvas_t*, float cx, float cy, float rad, const sk_paint_t*);
+/**
+    Draw the specified oval using the specified paint. The oval will be
+    filled or framed based on the style in the paint
+*/
+SK_API void sk_canvas_draw_oval(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+    Draw the specified path using the specified paint. The path will be
+    filled or framed based on the style in the paint
+*/
+SK_API void sk_canvas_draw_path(sk_canvas_t*, const sk_path_t*, const sk_paint_t*);
+/**
+    Draw the specified image, with its top/left corner at (x,y), using
+    the specified paint, transformed by the current matrix.
+
+    @param sk_paint_t* (may be NULL) the paint used to draw the image.
+*/
+SK_API void sk_canvas_draw_image(sk_canvas_t*, const sk_image_t*,
+                                 float x, float y, const sk_paint_t*);
+/**
+    Draw the specified image, scaling and translating so that it fills
+    the specified dst rect. If the src rect is non-null, only that
+    subset of the image is transformed and drawn.
+
+    @param sk_paint_t* (may be NULL) The paint used to draw the image.
+*/
+SK_API void sk_canvas_draw_image_rect(sk_canvas_t*, const sk_image_t*,
+                                      const sk_rect_t* src,
+                                      const sk_rect_t* dst, const sk_paint_t*);
+
+/**
+    Draw the picture into this canvas (replay the pciture's drawing commands).
+
+    @param sk_matrix_t* If non-null, apply that matrix to the CTM when
+                        drawing this picture. This is logically
+                        equivalent to: save, concat, draw_picture,
+                        restore.
+
+    @param sk_paint_t* If non-null, draw the picture into a temporary
+                       buffer, and then apply the paint's alpha,
+                       colorfilter, imagefilter, and xfermode to that
+                       buffer as it is drawn to the canvas.  This is
+                       logically equivalent to save_layer(paint),
+                       draw_picture, restore.
+*/
+SK_API void sk_canvas_draw_picture(sk_canvas_t*, const sk_picture_t*,
+                                   const sk_matrix_t*, const sk_paint_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 25 - 0
skia/include/c/sk_colorspace.h

@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_imageinfo_DEFINED
+#define sk_imageinfo_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+sk_colorspace_t* sk_colorspace_new_srgb();
+
+void sk_colorspace_ref(sk_colorspace_t*);
+void sk_colorspace_unref(sk_colorspace_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 70 - 0
skia/include/c/sk_data.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_data_DEFINED
+#define sk_data_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Returns a new empty sk_data_t.  This call must be balanced with a call to
+    sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_empty(void);
+/**
+    Returns a new sk_data_t by copying the specified source data.
+    This call must be balanced with a call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_with_copy(const void* src, size_t length);
+/**
+    Pass ownership of the given memory to a new sk_data_t, which will
+    call free() when the refernce count of the data goes to zero.  For
+    example:
+        size_t length = 1024;
+        void* buffer = malloc(length);
+        memset(buffer, 'X', length);
+        sk_data_t* data = sk_data_new_from_malloc(buffer, length);
+    This call must be balanced with a call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_from_malloc(const void* memory, size_t length);
+/**
+    Returns a new sk_data_t using a subset of the data in the
+    specified source sk_data_t.  This call must be balanced with a
+    call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_subset(const sk_data_t* src, size_t offset, size_t length);
+
+/**
+    Increment the reference count on the given sk_data_t. Must be
+    balanced by a call to sk_data_unref().
+*/
+SK_API void sk_data_ref(const sk_data_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the sk_data_t
+    and the memory it is managing.  New sk_data_t are created with a
+    reference count of 1.
+*/
+SK_API void sk_data_unref(const sk_data_t*);
+
+/**
+    Returns the number of bytes stored.
+*/
+SK_API size_t sk_data_get_size(const sk_data_t*);
+/**
+    Returns the pointer to the data.
+ */
+SK_API const void* sk_data_get_data(const sk_data_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 71 - 0
skia/include/c/sk_image.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_image_DEFINED
+#define sk_image_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+ *  Return a new image that has made a copy of the provided pixels, or NULL on failure.
+ *  Balance with a call to sk_image_unref().
+ */
+SK_API sk_image_t* sk_image_new_raster_copy(const sk_imageinfo_t*, const void* pixels, size_t rowBytes);
+
+/**
+ *  If the specified data can be interpreted as a compressed image (e.g. PNG or JPEG) then this
+ *  returns an image. If the encoded data is not supported, returns NULL.
+ *
+ *  On success, the encoded data may be processed immediately, or it may be ref()'d for later
+ *  use.
+ */
+SK_API sk_image_t* sk_image_new_from_encoded(const sk_data_t* encoded, const sk_irect_t* subset);
+
+/**
+ *  Encode the image's pixels and return the result as a new PNG in a
+ *  sk_data_t, which the caller must manage: call sk_data_unref() when
+ *  they are done.
+ *
+ *  If the image type cannot be encoded, this will return NULL.
+ */
+SK_API sk_data_t* sk_image_encode(const sk_image_t*);
+
+/**
+ *  Increment the reference count on the given sk_image_t. Must be
+ *  balanced by a call to sk_image_unref().
+*/
+SK_API void sk_image_ref(const sk_image_t*);
+/**
+ *  Decrement the reference count. If the reference count is 1 before
+ *  the decrement, then release both the memory holding the sk_image_t
+ *  and the memory it is managing.  New sk_image_t are created with a
+    reference count of 1.
+*/
+SK_API void sk_image_unref(const sk_image_t*);
+
+/**
+ *  Return the width of the sk_image_t/
+ */
+SK_API int sk_image_get_width(const sk_image_t*);
+/**
+ *  Return the height of the sk_image_t/
+ */
+SK_API int sk_image_get_height(const sk_image_t*);
+
+/**
+ *  Returns a non-zero value unique among all images.
+ */
+SK_API uint32_t sk_image_get_unique_id(const sk_image_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 62 - 0
skia/include/c/sk_imageinfo.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_imageinfo_DEFINED
+#define sk_imageinfo_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+typedef enum {
+    UNKNOWN_SK_COLORTYPE,
+    RGBA_8888_SK_COLORTYPE,
+    BGRA_8888_SK_COLORTYPE,
+    ALPHA_8_SK_COLORTYPE,
+    GRAY_8_SK_COLORTYPE,
+    RGBA_F16_SK_COLORTYPE,
+    RGBA_F32_SK_COLORTYPE,
+} sk_colortype_t;
+
+typedef enum {
+    OPAQUE_SK_ALPHATYPE,
+    PREMUL_SK_ALPHATYPE,
+    UNPREMUL_SK_ALPHATYPE,
+} sk_alphatype_t;
+
+/**
+ *  Allocate a new imageinfo object. If colorspace is not null, it's owner-count will be
+ *  incremented automatically.
+ */
+sk_imageinfo_t* sk_imageinfo_new(int width, int height, sk_colortype_t ct, sk_alphatype_t at,
+                                 sk_colorspace_t* cs);
+
+/**
+ *  Free the imageinfo object. If it contains a reference to a colorspace, its owner-count will
+ *  be decremented automatically.
+ */
+void sk_imageinfo_delete(sk_imageinfo_t*);
+
+int32_t          sk_imageinfo_get_width(sk_imageinfo_t*);
+int32_t          sk_imageinfo_get_height(sk_imageinfo_t*);
+sk_colortype_t   sk_imageinfo_get_colortype(sk_imageinfo_t*);
+sk_alphatype_t   sk_imageinfo_get_alphatype(sk_imageinfo_t*);
+
+/**
+ *  Return the colorspace object reference contained in the imageinfo, or null if there is none.
+ *  Note: this does not modify the owner-count on the colorspace object. If the caller needs to
+ *  use the colorspace beyond the lifetime of the imageinfo, it should manually call
+ *  sk_colorspace_ref() (and then call unref() when it is done).
+ */
+sk_colorspace_t* sk_imageinfo_get_colorspace(sk_imageinfo_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 47 - 0
skia/include/c/sk_maskfilter.h

@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_maskfilter_DEFINED
+#define sk_maskfilter_DEFINED
+
+#include "sk_types.h"
+
+typedef enum {
+    NORMAL_SK_BLUR_STYLE,   //!< fuzzy inside and outside
+    SOLID_SK_BLUR_STYLE,    //!< solid inside, fuzzy outside
+    OUTER_SK_BLUR_STYLE,    //!< nothing inside, fuzzy outside
+    INNER_SK_BLUR_STYLE,    //!< fuzzy inside, nothing outside
+} sk_blurstyle_t;
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Increment the reference count on the given sk_maskfilter_t. Must be
+    balanced by a call to sk_maskfilter_unref().
+*/
+void sk_maskfilter_ref(sk_maskfilter_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_maskfilter_t and any other associated resources.  New
+    sk_maskfilter_t are created with a reference count of 1.
+*/
+void sk_maskfilter_unref(sk_maskfilter_t*);
+
+/**
+    Create a blur maskfilter.
+    @param sk_blurstyle_t The SkBlurStyle to use
+    @param sigma Standard deviation of the Gaussian blur to apply. Must be > 0.
+*/
+sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t, float sigma);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 49 - 0
skia/include/c/sk_matrix.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_matrix_DEFINED
+#define sk_matrix_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/** Set the matrix to identity */
+void sk_matrix_set_identity(sk_matrix_t*);
+
+/** Set the matrix to translate by (tx, ty). */
+void sk_matrix_set_translate(sk_matrix_t*, float tx, float ty);
+/**
+    Preconcats the matrix with the specified translation.
+        M' = M * T(dx, dy)
+*/
+void sk_matrix_pre_translate(sk_matrix_t*, float tx, float ty);
+/**
+    Postconcats the matrix with the specified translation.
+        M' = T(dx, dy) * M
+*/
+void sk_matrix_post_translate(sk_matrix_t*, float tx, float ty);
+
+/** Set the matrix to scale by sx and sy. */
+void sk_matrix_set_scale(sk_matrix_t*, float sx, float sy);
+/**
+    Preconcats the matrix with the specified scale.
+        M' = M * S(sx, sy)
+*/
+void sk_matrix_pre_scale(sk_matrix_t*, float sx, float sy);
+/**
+    Postconcats the matrix with the specified scale.
+        M' = S(sx, sy) * M
+*/
+void sk_matrix_post_scale(sk_matrix_t*, float sx, float sy);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 145 - 0
skia/include/c/sk_paint.h

@@ -0,0 +1,145 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_paint_DEFINED
+#define sk_paint_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Create a new paint with default settings:
+        antialias : false
+        stroke : false
+        stroke width : 0.0f (hairline)
+        stroke miter : 4.0f
+        stroke cap : BUTT_SK_STROKE_CAP
+        stroke join : MITER_SK_STROKE_JOIN
+        color : opaque black
+        shader : NULL
+        maskfilter : NULL
+        xfermode_mode : SRCOVER_SK_XFERMODE_MODE
+*/
+SK_API sk_paint_t* sk_paint_new(void);
+/**
+    Release the memory storing the sk_paint_t and unref() all
+    associated objects.
+*/
+SK_API void sk_paint_delete(sk_paint_t*);
+
+/**
+    Return true iff the paint has antialiasing enabled.
+*/
+SK_API bool sk_paint_is_antialias(const sk_paint_t*);
+/**
+    Set to true to enable antialiasing, false to disable it on this
+    sk_paint_t.
+*/
+SK_API void sk_paint_set_antialias(sk_paint_t*, bool);
+
+/**
+    Return the paint's curent drawing color.
+*/
+SK_API sk_color_t sk_paint_get_color(const sk_paint_t*);
+/**
+    Set the paint's curent drawing color.
+*/
+SK_API void sk_paint_set_color(sk_paint_t*, sk_color_t);
+
+/* stroke settings */
+
+/**
+    Return true iff stroking is enabled rather than filling on this
+    sk_paint_t.
+*/
+SK_API bool sk_paint_is_stroke(const sk_paint_t*);
+/**
+    Set to true to enable stroking rather than filling with this
+    sk_paint_t.
+*/
+SK_API void sk_paint_set_stroke(sk_paint_t*, bool);
+
+/**
+    Return the width for stroking.  A value of 0 strokes in hairline mode.
+ */
+SK_API float sk_paint_get_stroke_width(const sk_paint_t*);
+/**
+   Set the width for stroking.  A value of 0 strokes in hairline mode
+   (always draw 1-pixel wide, regardless of the matrix).
+ */
+SK_API void sk_paint_set_stroke_width(sk_paint_t*, float width);
+
+/**
+    Return the paint's stroke miter value. This is used to control the
+    behavior of miter joins when the joins angle is sharp.
+*/
+SK_API float sk_paint_get_stroke_miter(const sk_paint_t*);
+/**
+   Set the paint's stroke miter value. This is used to control the
+   behavior of miter joins when the joins angle is sharp. This value
+   must be >= 0.
+*/
+SK_API void sk_paint_set_stroke_miter(sk_paint_t*, float miter);
+
+typedef enum {
+    BUTT_SK_STROKE_CAP,
+    ROUND_SK_STROKE_CAP,
+    SQUARE_SK_STROKE_CAP
+} sk_stroke_cap_t;
+
+/**
+    Return the paint's stroke cap type, controlling how the start and
+    end of stroked lines and paths are treated.
+*/
+SK_API sk_stroke_cap_t sk_paint_get_stroke_cap(const sk_paint_t*);
+/**
+    Set the paint's stroke cap type, controlling how the start and
+    end of stroked lines and paths are treated.
+*/
+SK_API void sk_paint_set_stroke_cap(sk_paint_t*, sk_stroke_cap_t);
+
+typedef enum {
+    MITER_SK_STROKE_JOIN,
+    ROUND_SK_STROKE_JOIN,
+    BEVEL_SK_STROKE_JOIN
+} sk_stroke_join_t;
+
+/**
+    Return the paint's stroke join type, specifies the treatment that
+    is applied to corners in paths and rectangles
+ */
+SK_API sk_stroke_join_t sk_paint_get_stroke_join(const sk_paint_t*);
+/**
+    Set the paint's stroke join type, specifies the treatment that
+    is applied to corners in paths and rectangles
+ */
+SK_API void sk_paint_set_stroke_join(sk_paint_t*, sk_stroke_join_t);
+
+/**
+ *  Set the paint's shader to the specified parameter. This will automatically call unref() on
+ *  any previous value, and call ref() on the new value.
+ */
+SK_API void sk_paint_set_shader(sk_paint_t*, sk_shader_t*);
+
+/**
+ *  Set the paint's maskfilter to the specified parameter. This will automatically call unref() on
+ *  any previous value, and call ref() on the new value.
+ */
+SK_API void sk_paint_set_maskfilter(sk_paint_t*, sk_maskfilter_t*);
+
+/**
+ *  Set the paint's xfermode to the specified parameter.
+ */
+SK_API void sk_paint_set_xfermode_mode(sk_paint_t*, sk_xfermode_mode_t);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 84 - 0
skia/include/c/sk_path.h

@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_path_DEFINED
+#define sk_path_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+typedef enum {
+    CW_SK_PATH_DIRECTION,
+    CCW_SK_PATH_DIRECTION,
+} sk_path_direction_t;
+
+/** Create a new, empty path. */
+SK_API sk_path_t* sk_path_new(void);
+/** Release the memory used by a sk_path_t. */
+SK_API void sk_path_delete(sk_path_t*);
+
+/** Set the beginning of the next contour to the point (x,y). */
+SK_API void sk_path_move_to(sk_path_t*, float x, float y);
+/**
+    Add a line from the last point to the specified point (x,y). If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_line_to(sk_path_t*, float x, float y);
+/**
+    Add a quadratic bezier from the last point, approaching control
+    point (x0,y0), and ending at (x1,y1). If no sk_path_move_to() call
+    has been made for this contour, the first point is automatically
+    set to (0,0).
+*/
+SK_API void sk_path_quad_to(sk_path_t*, float x0, float y0, float x1, float y1);
+/**
+    Add a conic curve from the last point, approaching control point
+    (x0,y01), and ending at (x1,y1) with weight w.  If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_conic_to(sk_path_t*, float x0, float y0, float x1, float y1, float w);
+/**
+    Add a cubic bezier from the last point, approaching control points
+    (x0,y0) and (x1,y1), and ending at (x2,y2). If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_cubic_to(sk_path_t*,
+                             float x0, float y0,
+                             float x1, float y1,
+                             float x2, float y2);
+/**
+   Close the current contour. If the current point is not equal to the
+   first point of the contour, a line segment is automatically added.
+*/
+SK_API void sk_path_close(sk_path_t*);
+
+/**
+    Add a closed rectangle contour to the path.
+*/
+SK_API void sk_path_add_rect(sk_path_t*, const sk_rect_t*, sk_path_direction_t);
+/**
+    Add a closed oval contour to the path
+*/
+SK_API void sk_path_add_oval(sk_path_t*, const sk_rect_t*, sk_path_direction_t);
+
+/**
+ *  If the path is empty, return false and set the rect parameter to [0, 0, 0, 0].
+ *  else return true and set the rect parameter to the bounds of the control-points
+ *  of the path.
+ */
+SK_API bool sk_path_get_bounds(const sk_path_t*, sk_rect_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 70 - 0
skia/include/c/sk_picture.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_picture_DEFINED
+#define sk_picture_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Create a new sk_picture_recorder_t.  Its resources should be
+    released with a call to sk_picture_recorder_delete().
+*/
+sk_picture_recorder_t* sk_picture_recorder_new(void);
+/**
+    Release the memory and other resources used by this
+    sk_picture_recorder_t.
+*/
+void sk_picture_recorder_delete(sk_picture_recorder_t*);
+
+/**
+   Returns the canvas that records the drawing commands
+
+   @param sk_rect_t* the cull rect used when recording this
+                     picture. Any drawing the falls outside of this
+                     rect is undefined, and may be drawn or it may not.
+*/
+sk_canvas_t* sk_picture_recorder_begin_recording(sk_picture_recorder_t*, const sk_rect_t*);
+/**
+    Signal that the caller is done recording. This invalidates the
+    canvas returned by begin_recording. Ownership of the sk_picture_t
+    is passed to the caller, who must call sk_picture_unref() when
+    they are done using it.  The returned picture is immutable.
+*/
+sk_picture_t* sk_picture_recorder_end_recording(sk_picture_recorder_t*);
+
+/**
+    Increment the reference count on the given sk_picture_t. Must be
+    balanced by a call to sk_picture_unref().
+*/
+void sk_picture_ref(sk_picture_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_picture_t and any resouces it may be managing.  New
+    sk_picture_t are created with a reference count of 1.
+*/
+void sk_picture_unref(sk_picture_t*);
+
+/**
+    Returns a non-zero value unique among all pictures.
+ */
+uint32_t sk_picture_get_unique_id(sk_picture_t*);
+
+/**
+    Return the cull rect specified when this picture was recorded.
+*/
+sk_rect_t sk_picture_get_bounds(sk_picture_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 143 - 0
skia/include/c/sk_shader.h

@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_shader_DEFINED
+#define sk_shader_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+void sk_shader_ref(sk_shader_t*);
+void sk_shader_unref(sk_shader_t*);
+
+typedef enum {
+    CLAMP_SK_SHADER_TILEMODE,
+    REPEAT_SK_SHADER_TILEMODE,
+    MIRROR_SK_SHADER_TILEMODE,
+} sk_shader_tilemode_t;
+
+/**
+    Returns a shader that generates a linear gradient between the two
+    specified points.
+
+    @param points The start and end points for the gradient.
+    @param colors The array[count] of colors, to be distributed between
+                  the two points
+    @param colorPos May be NULL. array[count] of SkScalars, or NULL, of
+                    the relative position of each corresponding color
+                    in the colors array. If this is NULL, the the
+                    colors are distributed evenly between the start
+                    and end point.  If this is not null, the values
+                    must begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param colorCount Must be >=2. The number of colors (and pos if not
+                      NULL) entries.
+    @param mode The tiling mode
+*/
+sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t points[2],
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t tileMode,
+                                           const sk_matrix_t* localMatrix);
+
+
+/**
+    Returns a shader that generates a radial gradient given the center
+    and radius.
+
+    @param center The center of the circle for this gradient
+    @param radius Must be positive. The radius of the circle for this
+                  gradient
+    @param colors The array[count] of colors, to be distributed
+                  between the center and edge of the circle
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the center and edge of
+                    the circle.  If this is not null, the values must
+                    begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param count Must be >= 2. The number of colors (and pos if not
+                 NULL) entries
+    @param tileMode The tiling mode
+    @param localMatrix May be NULL
+*/
+sk_shader_t* sk_shader_new_radial_gradient(const sk_point_t* center,
+                                           float radius,
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t tileMode,
+                                           const sk_matrix_t* localMatrix);
+
+/**
+    Returns a shader that generates a sweep gradient given a center.
+
+    @param center The coordinates of the center of the sweep
+    @param colors The array[count] of colors, to be distributed around
+                  the center.
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the center and edge of
+                    the circle.  If this is not null, the values must
+                    begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param colorCount Must be >= 2. The number of colors (and pos if
+                      not NULL) entries
+    @param localMatrix May be NULL
+*/
+sk_shader_t* sk_shader_new_sweep_gradient(const sk_point_t* center,
+                                          const sk_color_t colors[],
+                                          const float colorPos[],
+                                          int colorCount,
+                                          const sk_matrix_t* localMatrix);
+
+/**
+    Returns a shader that generates a conical gradient given two circles, or
+    returns NULL if the inputs are invalid. The gradient interprets the
+    two circles according to the following HTML spec.
+    http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
+
+    Returns a shader that generates a sweep gradient given a center.
+
+    @param start, startRadius Defines the first circle.
+    @param end, endRadius Defines the first circle.
+    @param colors The array[count] of colors, to be distributed between
+                  the two circles.
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the two circles.  If
+                    this is not null, the values must begin with 0,
+                    end with 1.0, and intermediate values must be
+                    strictly increasing.
+    @param colorCount Must be >= 2. The number of colors (and pos if
+                      not NULL) entries
+    @param tileMode The tiling mode
+    @param localMatrix May be NULL
+
+*/
+sk_shader_t* sk_shader_new_two_point_conical_gradient(
+        const sk_point_t* start,
+        float startRadius,
+        const sk_point_t* end,
+        float endRadius,
+        const sk_color_t colors[],
+        const float colorPos[],
+        int colorCount,
+        sk_shader_tilemode_t tileMode,
+        const sk_matrix_t* localMatrix);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 73 - 0
skia/include/c/sk_surface.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_surface_DEFINED
+#define sk_surface_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Return a new surface, with the memory for the pixels automatically
+    allocated.  If the requested surface cannot be created, or the
+    request is not a supported configuration, NULL will be returned.
+
+    @param sk_imageinfo_t* Specify the width, height, color type, and
+                           alpha type for the surface.
+
+    @param sk_surfaceprops_t* If not NULL, specify additional non-default
+                              properties of the surface.
+*/
+SK_API sk_surface_t* sk_surface_new_raster(const sk_imageinfo_t*, const sk_surfaceprops_t*);
+
+/**
+    Create a new surface which will draw into the specified pixels
+    with the specified rowbytes.  If the requested surface cannot be
+    created, or the request is not a supported configuration, NULL
+    will be returned.
+
+    @param sk_imageinfo_t* Specify the width, height, color type, and
+                           alpha type for the surface.
+    @param void* pixels Specify the location in memory where the
+                        destination pixels are.  This memory must
+                        outlast this surface.
+     @param size_t rowBytes Specify the difference, in bytes, between
+                           each adjacent row.  Should be at least
+                           (width * sizeof(one pixel)).
+    @param sk_surfaceprops_t* If not NULL, specify additional non-default
+                              properties of the surface.
+*/
+SK_API sk_surface_t* sk_surface_new_raster_direct(const sk_imageinfo_t*,
+                                                  void* pixels, size_t rowBytes,
+                                                  const sk_surfaceprops_t* props);
+
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_surface_t and any pixel memory it may be managing.  New
+    sk_surface_t are created with a reference count of 1.
+*/
+SK_API void sk_surface_unref(sk_surface_t*);
+
+/**
+ *  Return the canvas associated with this surface. Note: the canvas is owned by the surface,
+ *  so the returned object is only valid while the owning surface is valid.
+ */
+SK_API sk_canvas_t* sk_surface_get_canvas(sk_surface_t*);
+
+/**
+ *  Call sk_image_unref() when the returned image is no longer used.
+ */
+SK_API sk_image_t* sk_surface_new_image_snapshot(sk_surface_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 256 - 0
skia/include/c/sk_types.h

@@ -0,0 +1,256 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_types_DEFINED
+#define sk_types_DEFINED
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+    #define SK_C_PLUS_PLUS_BEGIN_GUARD    extern "C" {
+    #define SK_C_PLUS_PLUS_END_GUARD      }
+#else
+    #include <stdbool.h>
+    #define SK_C_PLUS_PLUS_BEGIN_GUARD
+    #define SK_C_PLUS_PLUS_END_GUARD
+#endif
+
+#if !defined(SK_API)
+    #if defined(SKIA_DLL)
+        #if defined(_MSC_VER)
+            #if SKIA_IMPLEMENTATION
+                #define SK_API __declspec(dllexport)
+            #else
+                #define SK_API __declspec(dllimport)
+            #endif
+        #else
+            #define SK_API __attribute__((visibility("default")))
+        #endif
+    #else
+        #define SK_API
+    #endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+typedef uint32_t sk_color_t;
+
+/* This macro assumes all arguments are >=0 and <=255. */
+#define sk_color_set_argb(a, r, g, b)   (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define sk_color_get_a(c)               (((c) >> 24) & 0xFF)
+#define sk_color_get_r(c)               (((c) >> 16) & 0xFF)
+#define sk_color_get_g(c)               (((c) >>  8) & 0xFF)
+#define sk_color_get_b(c)               (((c) >>  0) & 0xFF)
+
+typedef enum {
+    INTERSECT_SK_CLIPTYPE,
+    DIFFERENCE_SK_CLIPTYPE,
+} sk_cliptype_t;
+
+typedef enum {
+    UNKNOWN_SK_PIXELGEOMETRY,
+    RGB_H_SK_PIXELGEOMETRY,
+    BGR_H_SK_PIXELGEOMETRY,
+    RGB_V_SK_PIXELGEOMETRY,
+    BGR_V_SK_PIXELGEOMETRY,
+} sk_pixelgeometry_t;
+
+typedef struct {
+    sk_pixelgeometry_t pixelGeometry;
+} sk_surfaceprops_t;
+
+typedef struct {
+    float   x;
+    float   y;
+} sk_point_t;
+
+typedef struct {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} sk_irect_t;
+
+typedef struct {
+    float   left;
+    float   top;
+    float   right;
+    float   bottom;
+} sk_rect_t;
+
+/**
+    The sk_matrix_t struct holds a 3x3 perspective matrix for
+    transforming coordinates:
+
+        (X,Y) = T[M]((x,y))
+        X = (M[0] * x + M[1] * y + M[2]) / (M[6] * x + M[7] * y + M[8]);
+        Y = (M[3] * x + M[4] * y + M[5]) / (M[6] * x + M[7] * y + M[8]);
+
+    Therefore, the identity matrix is
+
+        sk_matrix_t identity = {{1, 0, 0,
+                                 0, 1, 0,
+                                 0, 0, 1}};
+
+    A matrix that scales by sx and sy is:
+
+        sk_matrix_t scale = {{sx, 0,  0,
+                              0,  sy, 0,
+                              0,  0,  1}};
+
+    A matrix that translates by tx and ty is:
+
+        sk_matrix_t translate = {{1, 0, tx,
+                                  0, 1, ty,
+                                  0, 0, 1}};
+
+    A matrix that rotates around the origin by A radians:
+
+        sk_matrix_t rotate = {{cos(A), -sin(A), 0,
+                               sin(A),  cos(A), 0,
+                               0,       0,      1}};
+
+    Two matrixes can be concatinated by:
+
+         void concat_matrices(sk_matrix_t* dst,
+                             const sk_matrix_t* matrixU,
+                             const sk_matrix_t* matrixV) {
+            const float* u = matrixU->mat;
+            const float* v = matrixV->mat;
+            sk_matrix_t result = {{
+                    u[0] * v[0] + u[1] * v[3] + u[2] * v[6],
+                    u[0] * v[1] + u[1] * v[4] + u[2] * v[7],
+                    u[0] * v[2] + u[1] * v[5] + u[2] * v[8],
+                    u[3] * v[0] + u[4] * v[3] + u[5] * v[6],
+                    u[3] * v[1] + u[4] * v[4] + u[5] * v[7],
+                    u[3] * v[2] + u[4] * v[5] + u[5] * v[8],
+                    u[6] * v[0] + u[7] * v[3] + u[8] * v[6],
+                    u[6] * v[1] + u[7] * v[4] + u[8] * v[7],
+                    u[6] * v[2] + u[7] * v[5] + u[8] * v[8]
+            }};
+            *dst = result;
+        }
+*/
+typedef struct {
+    float   mat[9];
+} sk_matrix_t;
+
+/**
+    A sk_canvas_t encapsulates all of the state about drawing into a
+    destination This includes a reference to the destination itself,
+    and a stack of matrix/clip values.
+*/
+typedef struct sk_canvas_t sk_canvas_t;
+/**
+    A sk_data_ holds an immutable data buffer.
+*/
+typedef struct sk_data_t sk_data_t;
+/**
+    A sk_image_t is an abstraction for drawing a rectagle of pixels.
+    The content of the image is always immutable, though the actual
+    storage may change, if for example that image can be re-created via
+    encoded data or other means.
+*/
+typedef struct sk_image_t sk_image_t;
+
+/**
+ *  Describes the color components. See ICC Profiles.
+ */
+typedef struct sk_colorspace_t sk_colorspace_t;
+
+/**
+ *  Describes an image buffer : width, height, pixel type, colorspace, etc.
+ */
+typedef struct sk_imageinfo_t sk_imageinfo_t;
+
+/**
+    A sk_maskfilter_t is an object that perform transformations on an
+    alpha-channel mask before drawing it; it may be installed into a
+    sk_paint_t.  Each time a primitive is drawn, it is first
+    scan-converted into a alpha mask, which os handed to the
+    maskfilter, which may create a new mask is to render into the
+    destination.
+ */
+typedef struct sk_maskfilter_t sk_maskfilter_t;
+/**
+    A sk_paint_t holds the style and color information about how to
+    draw geometries, text and bitmaps.
+*/
+typedef struct sk_paint_t sk_paint_t;
+/**
+    A sk_path_t encapsulates compound (multiple contour) geometric
+    paths consisting of straight line segments, quadratic curves, and
+    cubic curves.
+*/
+typedef struct sk_path_t sk_path_t;
+/**
+    A sk_picture_t holds recorded canvas drawing commands to be played
+    back at a later time.
+*/
+typedef struct sk_picture_t sk_picture_t;
+/**
+    A sk_picture_recorder_t holds a sk_canvas_t that records commands
+    to create a sk_picture_t.
+*/
+typedef struct sk_picture_recorder_t sk_picture_recorder_t;
+/**
+    A sk_shader_t specifies the source color(s) for what is being drawn. If a
+    paint has no shader, then the paint's color is used. If the paint
+    has a shader, then the shader's color(s) are use instead, but they
+    are modulated by the paint's alpha.
+*/
+typedef struct sk_shader_t sk_shader_t;
+/**
+    A sk_surface_t holds the destination for drawing to a canvas. For
+    raster drawing, the destination is an array of pixels in memory.
+    For GPU drawing, the destination is a texture or a framebuffer.
+*/
+typedef struct sk_surface_t sk_surface_t;
+
+typedef enum {
+    CLEAR_SK_XFERMODE_MODE,
+    SRC_SK_XFERMODE_MODE,
+    DST_SK_XFERMODE_MODE,
+    SRCOVER_SK_XFERMODE_MODE,
+    DSTOVER_SK_XFERMODE_MODE,
+    SRCIN_SK_XFERMODE_MODE,
+    DSTIN_SK_XFERMODE_MODE,
+    SRCOUT_SK_XFERMODE_MODE,
+    DSTOUT_SK_XFERMODE_MODE,
+    SRCATOP_SK_XFERMODE_MODE,
+    DSTATOP_SK_XFERMODE_MODE,
+    XOR_SK_XFERMODE_MODE,
+    PLUS_SK_XFERMODE_MODE,
+    MODULATE_SK_XFERMODE_MODE,
+    SCREEN_SK_XFERMODE_MODE,
+    OVERLAY_SK_XFERMODE_MODE,
+    DARKEN_SK_XFERMODE_MODE,
+    LIGHTEN_SK_XFERMODE_MODE,
+    COLORDODGE_SK_XFERMODE_MODE,
+    COLORBURN_SK_XFERMODE_MODE,
+    HARDLIGHT_SK_XFERMODE_MODE,
+    SOFTLIGHT_SK_XFERMODE_MODE,
+    DIFFERENCE_SK_XFERMODE_MODE,
+    EXCLUSION_SK_XFERMODE_MODE,
+    MULTIPLY_SK_XFERMODE_MODE,
+    HUE_SK_XFERMODE_MODE,
+    SATURATION_SK_XFERMODE_MODE,
+    COLOR_SK_XFERMODE_MODE,
+    LUMINOSITY_SK_XFERMODE_MODE,
+} sk_xfermode_mode_t;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif

+ 287 - 0
skia/include/codec/SkAndroidCodec.h

@@ -0,0 +1,287 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAndroidCodec_DEFINED
+#define SkAndroidCodec_DEFINED
+
+#include "SkCodec.h"
+#include "SkEncodedImageFormat.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+
+/**
+ *  Abstract interface defining image codec functionality that is necessary for
+ *  Android.
+ */
+class SK_API SkAndroidCodec : SkNoncopyable {
+public:
+    enum class ExifOrientationBehavior {
+        /**
+         *  Ignore any exif orientation markers in the data.
+         *
+         *  getInfo's width and height will match the header of the image, and
+         *  no processing will be done to match the marker.
+         */
+        kIgnore,
+
+        /**
+         *  Respect the exif orientation marker.
+         *
+         *  getInfo's width and height will represent what they should be after
+         *  applying the orientation. For example, if the marker specifies a
+         *  rotation by 90 degrees, they will be swapped relative to the header.
+         *  getAndroidPixels will apply the orientation as well.
+         */
+        kRespect,
+    };
+
+    /**
+     *  Pass ownership of an SkCodec to a newly-created SkAndroidCodec.
+     */
+    static std::unique_ptr<SkAndroidCodec> MakeFromCodec(std::unique_ptr<SkCodec>,
+            ExifOrientationBehavior = ExifOrientationBehavior::kIgnore);
+
+    /**
+     *  If this stream represents an encoded image that we know how to decode,
+     *  return an SkAndroidCodec that can decode it. Otherwise return NULL.
+     *
+     *  The SkPngChunkReader handles unknown chunks in PNGs.
+     *  See SkCodec.h for more details.
+     *
+     *  If NULL is returned, the stream is deleted immediately. Otherwise, the
+     *  SkCodec takes ownership of it, and will delete it when done with it.
+     *
+     *  ExifOrientationBehavior is set to kIgnore.
+     */
+    static std::unique_ptr<SkAndroidCodec> MakeFromStream(std::unique_ptr<SkStream>,
+                                                          SkPngChunkReader* = nullptr);
+
+    /**
+     *  If this data represents an encoded image that we know how to decode,
+     *  return an SkAndroidCodec that can decode it. Otherwise return NULL.
+     *
+     *  The SkPngChunkReader handles unknown chunks in PNGs.
+     *  See SkCodec.h for more details.
+     *
+     *  ExifOrientationBehavior is set to kIgnore.
+     */
+    static std::unique_ptr<SkAndroidCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr);
+
+    virtual ~SkAndroidCodec();
+
+    const SkImageInfo& getInfo() const { return fInfo; }
+
+    /**
+     *  Format of the encoded data.
+     */
+    SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); }
+
+    /**
+     *  @param requestedColorType Color type requested by the client
+     *
+     *  |requestedColorType| may be overriden.  We will default to kF16
+     *  for high precision images.
+     *
+     *  In the general case, if it is possible to decode to
+     *  |requestedColorType|, this returns |requestedColorType|.
+     *  Otherwise, this returns a color type that is an appropriate
+     *  match for the the encoded data.
+     */
+    SkColorType computeOutputColorType(SkColorType requestedColorType);
+
+    /**
+     *  @param requestedUnpremul  Indicates if the client requested
+     *                            unpremultiplied output
+     *
+     *  Returns the appropriate alpha type to decode to.  If the image
+     *  has alpha, the value of requestedUnpremul will be honored.
+     */
+    SkAlphaType computeOutputAlphaType(bool requestedUnpremul);
+
+    /**
+     *  @param outputColorType Color type that the client will decode to.
+     *  @param prefColorSpace  Preferred color space to decode to.
+     *                         This may not return |prefColorSpace| for a couple reasons.
+     *                         (1) Android Principles: 565 must be sRGB, F16 must be
+     *                             linear sRGB, transfer function must be parametric.
+     *                         (2) Codec Limitations: F16 requires a linear color space.
+     *
+     *  Returns the appropriate color space to decode to.
+     */
+    sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType,
+                                                sk_sp<SkColorSpace> prefColorSpace = nullptr);
+
+    /**
+     *  Compute the appropriate sample size to get to |size|.
+     *
+     *  @param size As an input parameter, the desired output size of
+     *      the decode. As an output parameter, the smallest sampled size
+     *      larger than the input.
+     *  @return the sample size to set AndroidOptions::fSampleSize to decode
+     *      to the output |size|.
+     */
+    int computeSampleSize(SkISize* size) const;
+
+    /**
+     *  Returns the dimensions of the scaled output image, for an input
+     *  sampleSize.
+     *
+     *  When the sample size divides evenly into the original dimensions, the
+     *  scaled output dimensions will simply be equal to the original
+     *  dimensions divided by the sample size.
+     *
+     *  When the sample size does not divide even into the original
+     *  dimensions, the codec may round up or down, depending on what is most
+     *  efficient to decode.
+     *
+     *  Finally, the codec will always recommend a non-zero output, so the output
+     *  dimension will always be one if the sampleSize is greater than the
+     *  original dimension.
+     */
+    SkISize getSampledDimensions(int sampleSize) const;
+
+    /**
+     *  Return (via desiredSubset) a subset which can decoded from this codec,
+     *  or false if the input subset is invalid.
+     *
+     *  @param desiredSubset in/out parameter
+     *                       As input, a desired subset of the original bounds
+     *                       (as specified by getInfo).
+     *                       As output, if true is returned, desiredSubset may
+     *                       have been modified to a subset which is
+     *                       supported. Although a particular change may have
+     *                       been made to desiredSubset to create something
+     *                       supported, it is possible other changes could
+     *                       result in a valid subset.  If false is returned,
+     *                       desiredSubset's value is undefined.
+     *  @return true         If the input desiredSubset is valid.
+     *                       desiredSubset may be modified to a subset
+     *                       supported by the codec.
+     *          false        If desiredSubset is invalid (NULL or not fully
+     *                       contained within the image).
+     */
+    bool getSupportedSubset(SkIRect* desiredSubset) const;
+    // TODO: Rename SkCodec::getValidSubset() to getSupportedSubset()
+
+    /**
+     *  Returns the dimensions of the scaled, partial output image, for an
+     *  input sampleSize and subset.
+     *
+     *  @param sampleSize Factor to scale down by.
+     *  @param subset     Must be a valid subset of the original image
+     *                    dimensions and a subset supported by SkAndroidCodec.
+     *                    getSubset() can be used to obtain a subset supported
+     *                    by SkAndroidCodec.
+     *  @return           Size of the scaled partial image.  Or zero size
+     *                    if either of the inputs is invalid.
+     */
+    SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const;
+
+    /**
+     *  Additional options to pass to getAndroidPixels().
+     */
+    // FIXME: It's a bit redundant to name these AndroidOptions when this class is already
+    //        called SkAndroidCodec.  On the other hand, it's may be a bit confusing to call
+    //        these Options when SkCodec has a slightly different set of Options.  Maybe these
+    //        should be DecodeOptions or SamplingOptions?
+    struct AndroidOptions {
+        AndroidOptions()
+            : fZeroInitialized(SkCodec::kNo_ZeroInitialized)
+            , fSubset(nullptr)
+            , fSampleSize(1)
+        {}
+
+        /**
+         *  Indicates is destination pixel memory is zero initialized.
+         *
+         *  The default is SkCodec::kNo_ZeroInitialized.
+         */
+        SkCodec::ZeroInitialized fZeroInitialized;
+
+        /**
+         *  If not NULL, represents a subset of the original image to decode.
+         *
+         *  Must be within the bounds returned by getInfo().
+         *
+         *  If the EncodedFormat is SkEncodedImageFormat::kWEBP, the top and left
+         *  values must be even.
+         *
+         *  The default is NULL, meaning a decode of the entire image.
+         */
+        SkIRect* fSubset;
+
+        /**
+         *  The client may provide an integer downscale factor for the decode.
+         *  The codec may implement this downscaling by sampling or another
+         *  method if it is more efficient.
+         *
+         *  The default is 1, representing no downscaling.
+         */
+        int fSampleSize;
+    };
+
+    /**
+     *  Decode into the given pixels, a block of memory of size at
+     *  least (info.fHeight - 1) * rowBytes + (info.fWidth *
+     *  bytesPerPixel)
+     *
+     *  Repeated calls to this function should give the same results,
+     *  allowing the PixelRef to be immutable.
+     *
+     *  @param info A description of the format (config, size)
+     *         expected by the caller.  This can simply be identical
+     *         to the info returned by getInfo().
+     *
+     *         This contract also allows the caller to specify
+     *         different output-configs, which the implementation can
+     *         decide to support or not.
+     *
+     *         A size that does not match getInfo() implies a request
+     *         to scale or subset. If the codec cannot perform this
+     *         scaling or subsetting, it will return an error code.
+     *
+     *  The AndroidOptions object is also used to specify any requested scaling or subsetting
+     *  using options->fSampleSize and options->fSubset. If NULL, the defaults (as specified above
+     *  for AndroidOptions) are used.
+     *
+     *  @return Result kSuccess, or another value explaining the type of failure.
+     */
+    // FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already
+    //        called SkAndroidCodec.  On the other hand, it's may be a bit confusing to call
+    //        this getPixels() when it is a slightly different API than SkCodec's getPixels().
+    //        Maybe this should be decode() or decodeSubset()?
+    SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+            const AndroidOptions* options);
+
+    /**
+     *  Simplified version of getAndroidPixels() where we supply the default AndroidOptions as
+     *  specified above for AndroidOptions. It will not perform any scaling or subsetting.
+     */
+    SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
+
+    SkCodec::Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
+        return this->getAndroidPixels(info, pixels, rowBytes);
+    }
+
+    SkCodec* codec() const { return fCodec.get(); }
+
+protected:
+    SkAndroidCodec(SkCodec*, ExifOrientationBehavior = ExifOrientationBehavior::kIgnore);
+
+    virtual SkISize onGetSampledDimensions(int sampleSize) const = 0;
+
+    virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0;
+
+    virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels,
+            size_t rowBytes, const AndroidOptions& options) = 0;
+
+private:
+    const SkImageInfo               fInfo;
+    const ExifOrientationBehavior   fOrientationBehavior;
+    std::unique_ptr<SkCodec>        fCodec;
+};
+#endif // SkAndroidCodec_DEFINED

+ 921 - 0
skia/include/codec/SkCodec.h

@@ -0,0 +1,921 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCodec_DEFINED
+#define SkCodec_DEFINED
+
+#include "../private/SkNoncopyable.h"
+#include "../private/SkTemplates.h"
+#include "../private/SkEncodedInfo.h"
+#include "SkCodecAnimation.h"
+#include "SkColor.h"
+#include "SkEncodedImageFormat.h"
+#include "SkEncodedOrigin.h"
+#include "SkImageInfo.h"
+#include "SkPixmap.h"
+#include "SkSize.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+#include "SkYUVASizeInfo.h"
+
+#include <vector>
+
+class SkColorSpace;
+class SkData;
+class SkFrameHolder;
+class SkPngChunkReader;
+class SkSampler;
+
+namespace DM {
+class CodecSrc;
+class ColorCodecSrc;
+}
+
+/**
+ *  Abstraction layer directly on top of an image codec.
+ */
+class SK_API SkCodec : SkNoncopyable {
+public:
+    /**
+     *  Minimum number of bytes that must be buffered in SkStream input.
+     *
+     *  An SkStream passed to NewFromStream must be able to use this many
+     *  bytes to determine the image type. Then the same SkStream must be
+     *  passed to the correct decoder to read from the beginning.
+     *
+     *  This can be accomplished by implementing peek() to support peeking
+     *  this many bytes, or by implementing rewind() to be able to rewind()
+     *  after reading this many bytes.
+     */
+    static constexpr size_t MinBufferedBytesNeeded() { return 32; }
+
+    /**
+     *  Error codes for various SkCodec methods.
+     */
+    enum Result {
+        /**
+         *  General return value for success.
+         */
+        kSuccess,
+        /**
+         *  The input is incomplete. A partial image was generated.
+         */
+        kIncompleteInput,
+        /**
+         *  Like kIncompleteInput, except the input had an error.
+         *
+         *  If returned from an incremental decode, decoding cannot continue,
+         *  even with more data.
+         */
+        kErrorInInput,
+        /**
+         *  The generator cannot convert to match the request, ignoring
+         *  dimensions.
+         */
+        kInvalidConversion,
+        /**
+         *  The generator cannot scale to requested size.
+         */
+        kInvalidScale,
+        /**
+         *  Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes
+         *  too small, etc.
+         */
+        kInvalidParameters,
+        /**
+         *  The input did not contain a valid image.
+         */
+        kInvalidInput,
+        /**
+         *  Fulfilling this request requires rewinding the input, which is not
+         *  supported for this input.
+         */
+        kCouldNotRewind,
+        /**
+         *  An internal error, such as OOM.
+         */
+        kInternalError,
+        /**
+         *  This method is not implemented by this codec.
+         *  FIXME: Perhaps this should be kUnsupported?
+         */
+        kUnimplemented,
+    };
+
+    /**
+     *  Readable string representing the error code.
+     */
+    static const char* ResultToString(Result);
+
+    /**
+     *  If this stream represents an encoded image that we know how to decode,
+     *  return an SkCodec that can decode it. Otherwise return NULL.
+     *
+     *  As stated above, this call must be able to peek or read
+     *  MinBufferedBytesNeeded to determine the correct format, and then start
+     *  reading from the beginning. First it will attempt to peek, and it
+     *  assumes that if less than MinBufferedBytesNeeded bytes (but more than
+     *  zero) are returned, this is because the stream is shorter than this,
+     *  so falling back to reading would not provide more data. If peek()
+     *  returns zero bytes, this call will instead attempt to read(). This
+     *  will require that the stream can be rewind()ed.
+     *
+     *  If Result is not NULL, it will be set to either kSuccess if an SkCodec
+     *  is returned or a reason for the failure if NULL is returned.
+     *
+     *  If SkPngChunkReader is not NULL, take a ref and pass it to libpng if
+     *  the image is a png.
+     *
+     *  If the SkPngChunkReader is not NULL then:
+     *      If the image is not a PNG, the SkPngChunkReader will be ignored.
+     *      If the image is a PNG, the SkPngChunkReader will be reffed.
+     *      If the PNG has unknown chunks, the SkPngChunkReader will be used
+     *      to handle these chunks.  SkPngChunkReader will be called to read
+     *      any unknown chunk at any point during the creation of the codec
+     *      or the decode.  Note that if SkPngChunkReader fails to read a
+     *      chunk, this could result in a failure to create the codec or a
+     *      failure to decode the image.
+     *      If the PNG does not contain unknown chunks, the SkPngChunkReader
+     *      will not be used or modified.
+     *
+     *  If NULL is returned, the stream is deleted immediately. Otherwise, the
+     *  SkCodec takes ownership of it, and will delete it when done with it.
+     */
+    static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result* = nullptr,
+                                                   SkPngChunkReader* = nullptr);
+
+    /**
+     *  If this data represents an encoded image that we know how to decode,
+     *  return an SkCodec that can decode it. Otherwise return NULL.
+     *
+     *  If the SkPngChunkReader is not NULL then:
+     *      If the image is not a PNG, the SkPngChunkReader will be ignored.
+     *      If the image is a PNG, the SkPngChunkReader will be reffed.
+     *      If the PNG has unknown chunks, the SkPngChunkReader will be used
+     *      to handle these chunks.  SkPngChunkReader will be called to read
+     *      any unknown chunk at any point during the creation of the codec
+     *      or the decode.  Note that if SkPngChunkReader fails to read a
+     *      chunk, this could result in a failure to create the codec or a
+     *      failure to decode the image.
+     *      If the PNG does not contain unknown chunks, the SkPngChunkReader
+     *      will not be used or modified.
+     */
+    static std::unique_ptr<SkCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr);
+
+    virtual ~SkCodec();
+
+    /**
+     *  Return a reasonable SkImageInfo to decode into.
+     */
+    SkImageInfo getInfo() const { return fEncodedInfo.makeImageInfo(); }
+
+    SkISize dimensions() const { return {fEncodedInfo.width(), fEncodedInfo.height()}; }
+    SkIRect bounds() const {
+        return SkIRect::MakeWH(fEncodedInfo.width(), fEncodedInfo.height());
+    }
+
+    /**
+     *  Returns the image orientation stored in the EXIF data.
+     *  If there is no EXIF data, or if we cannot read the EXIF data, returns kTopLeft.
+     */
+    SkEncodedOrigin getOrigin() const { return fOrigin; }
+
+    /**
+     *  Return a size that approximately supports the desired scale factor.
+     *  The codec may not be able to scale efficiently to the exact scale
+     *  factor requested, so return a size that approximates that scale.
+     *  The returned value is the codec's suggestion for the closest valid
+     *  scale that it can natively support
+     */
+    SkISize getScaledDimensions(float desiredScale) const {
+        // Negative and zero scales are errors.
+        SkASSERT(desiredScale > 0.0f);
+        if (desiredScale <= 0.0f) {
+            return SkISize::Make(0, 0);
+        }
+
+        // Upscaling is not supported. Return the original size if the client
+        // requests an upscale.
+        if (desiredScale >= 1.0f) {
+            return this->dimensions();
+        }
+        return this->onGetScaledDimensions(desiredScale);
+    }
+
+    /**
+     *  Return (via desiredSubset) a subset which can decoded from this codec,
+     *  or false if this codec cannot decode subsets or anything similar to
+     *  desiredSubset.
+     *
+     *  @param desiredSubset In/out parameter. As input, a desired subset of
+     *      the original bounds (as specified by getInfo). If true is returned,
+     *      desiredSubset may have been modified to a subset which is
+     *      supported. Although a particular change may have been made to
+     *      desiredSubset to create something supported, it is possible other
+     *      changes could result in a valid subset.
+     *      If false is returned, desiredSubset's value is undefined.
+     *  @return true if this codec supports decoding desiredSubset (as
+     *      returned, potentially modified)
+     */
+    bool getValidSubset(SkIRect* desiredSubset) const {
+        return this->onGetValidSubset(desiredSubset);
+    }
+
+    /**
+     *  Format of the encoded data.
+     */
+    SkEncodedImageFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
+
+    /**
+     *  Whether or not the memory passed to getPixels is zero initialized.
+     */
+    enum ZeroInitialized {
+        /**
+         *  The memory passed to getPixels is zero initialized. The SkCodec
+         *  may take advantage of this by skipping writing zeroes.
+         */
+        kYes_ZeroInitialized,
+        /**
+         *  The memory passed to getPixels has not been initialized to zero,
+         *  so the SkCodec must write all zeroes to memory.
+         *
+         *  This is the default. It will be used if no Options struct is used.
+         */
+        kNo_ZeroInitialized,
+    };
+
+    /**
+     *  Additional options to pass to getPixels.
+     */
+    struct Options {
+        Options()
+            : fZeroInitialized(kNo_ZeroInitialized)
+            , fSubset(nullptr)
+            , fFrameIndex(0)
+            , fPriorFrame(kNoFrame)
+        {}
+
+        ZeroInitialized            fZeroInitialized;
+        /**
+         *  If not NULL, represents a subset of the original image to decode.
+         *  Must be within the bounds returned by getInfo().
+         *  If the EncodedFormat is SkEncodedImageFormat::kWEBP (the only one which
+         *  currently supports subsets), the top and left values must be even.
+         *
+         *  In getPixels and incremental decode, we will attempt to decode the
+         *  exact rectangular subset specified by fSubset.
+         *
+         *  In a scanline decode, it does not make sense to specify a subset
+         *  top or subset height, since the client already controls which rows
+         *  to get and which rows to skip.  During scanline decodes, we will
+         *  require that the subset top be zero and the subset height be equal
+         *  to the full height.  We will, however, use the values of
+         *  subset left and subset width to decode partial scanlines on calls
+         *  to getScanlines().
+         */
+        const SkIRect*             fSubset;
+
+        /**
+         *  The frame to decode.
+         *
+         *  Only meaningful for multi-frame images.
+         */
+        int                        fFrameIndex;
+
+        /**
+         *  If not kNoFrame, the dst already contains the prior frame at this index.
+         *
+         *  Only meaningful for multi-frame images.
+         *
+         *  If fFrameIndex needs to be blended with a prior frame (as reported by
+         *  getFrameInfo[fFrameIndex].fRequiredFrame), the client can set this to
+         *  any non-kRestorePrevious frame in [fRequiredFrame, fFrameIndex) to
+         *  indicate that that frame is already in the dst. Options.fZeroInitialized
+         *  is ignored in this case.
+         *
+         *  If set to kNoFrame, the codec will decode any necessary required frame(s) first.
+         */
+        int                        fPriorFrame;
+    };
+
+    /**
+     *  Decode into the given pixels, a block of memory of size at
+     *  least (info.fHeight - 1) * rowBytes + (info.fWidth *
+     *  bytesPerPixel)
+     *
+     *  Repeated calls to this function should give the same results,
+     *  allowing the PixelRef to be immutable.
+     *
+     *  @param info A description of the format (config, size)
+     *         expected by the caller.  This can simply be identical
+     *         to the info returned by getInfo().
+     *
+     *         This contract also allows the caller to specify
+     *         different output-configs, which the implementation can
+     *         decide to support or not.
+     *
+     *         A size that does not match getInfo() implies a request
+     *         to scale. If the generator cannot perform this scale,
+     *         it will return kInvalidScale.
+     *
+     *         If the info contains a non-null SkColorSpace, the codec
+     *         will perform the appropriate color space transformation.
+     *         If the caller passes in the same color space that was
+     *         reported by the codec, the color space transformation is
+     *         a no-op.
+     *
+     *  If a scanline decode is in progress, scanline mode will end, requiring the client to call
+     *  startScanlineDecode() in order to return to decoding scanlines.
+     *
+     *  @return Result kSuccess, or another value explaining the type of failure.
+     */
+    Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*);
+
+    /**
+     *  Simplified version of getPixels() that uses the default Options.
+     */
+    Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
+        return this->getPixels(info, pixels, rowBytes, nullptr);
+    }
+
+    Result getPixels(const SkPixmap& pm, const Options* opts = nullptr) {
+        return this->getPixels(pm.info(), pm.writable_addr(), pm.rowBytes(), opts);
+    }
+
+    /**
+     *  If decoding to YUV is supported, this returns true.  Otherwise, this
+     *  returns false and does not modify any of the parameters.
+     *
+     *  @param sizeInfo   Output parameter indicating the sizes and required
+     *                    allocation widths of the Y, U, V, and A planes. Given current codec
+     *                    limitations the size of the A plane will always be 0 and the Y, U, V
+     *                    channels will always be planar.
+     *  @param colorSpace Output parameter.  If non-NULL this is set to kJPEG,
+     *                    otherwise this is ignored.
+     */
+    bool queryYUV8(SkYUVASizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
+        if (nullptr == sizeInfo) {
+            return false;
+        }
+
+        bool result = this->onQueryYUV8(sizeInfo, colorSpace);
+        if (result) {
+            for (int i = 0; i <= 2; ++i) {
+                SkASSERT(sizeInfo->fSizes[i].fWidth > 0 && sizeInfo->fSizes[i].fHeight > 0 &&
+                         sizeInfo->fWidthBytes[i] > 0);
+            }
+            SkASSERT(!sizeInfo->fSizes[3].fWidth &&
+                     !sizeInfo->fSizes[3].fHeight &&
+                     !sizeInfo->fWidthBytes[3]);
+        }
+        return result;
+    }
+
+    /**
+     *  Returns kSuccess, or another value explaining the type of failure.
+     *  This always attempts to perform a full decode.  If the client only
+     *  wants size, it should call queryYUV8().
+     *
+     *  @param sizeInfo   Needs to exactly match the values returned by the
+     *                    query, except the WidthBytes may be larger than the
+     *                    recommendation (but not smaller).
+     *  @param planes     Memory for each of the Y, U, and V planes.
+     */
+    Result getYUV8Planes(const SkYUVASizeInfo& sizeInfo, void* planes[SkYUVASizeInfo::kMaxCount]) {
+        if (!planes || !planes[0] || !planes[1] || !planes[2]) {
+            return kInvalidInput;
+        }
+        SkASSERT(!planes[3]); // TODO: is this a fair assumption?
+
+        if (!this->rewindIfNeeded()) {
+            return kCouldNotRewind;
+        }
+
+        return this->onGetYUV8Planes(sizeInfo, planes);
+    }
+
+    /**
+     *  Prepare for an incremental decode with the specified options.
+     *
+     *  This may require a rewind.
+     *
+     *  @param dstInfo Info of the destination. If the dimensions do not match
+     *      those of getInfo, this implies a scale.
+     *  @param dst Memory to write to. Needs to be large enough to hold the subset,
+     *      if present, or the full image as described in dstInfo.
+     *  @param options Contains decoding options, including if memory is zero
+     *      initialized and whether to decode a subset.
+     *  @return Enum representing success or reason for failure.
+     */
+    Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
+            const Options*);
+
+    Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) {
+        return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr);
+    }
+
+    /**
+     *  Start/continue the incremental decode.
+     *
+     *  Not valid to call before calling startIncrementalDecode().
+     *
+     *  After the first call, should only be called again if more data has been
+     *  provided to the source SkStream.
+     *
+     *  Unlike getPixels and getScanlines, this does not do any filling. This is
+     *  left up to the caller, since they may be skipping lines or continuing the
+     *  decode later. In the latter case, they may choose to initialize all lines
+     *  first, or only initialize the remaining lines after the first call.
+     *
+     *  @param rowsDecoded Optional output variable returning the total number of
+     *      lines initialized. Only meaningful if this method returns kIncompleteInput.
+     *      Otherwise the implementation may not set it.
+     *      Note that some implementations may have initialized this many rows, but
+     *      not necessarily finished those rows (e.g. interlaced PNG). This may be
+     *      useful for determining what rows the client needs to initialize.
+     *  @return kSuccess if all lines requested in startIncrementalDecode have
+     *      been completely decoded. kIncompleteInput otherwise.
+     */
+    Result incrementalDecode(int* rowsDecoded = nullptr) {
+        if (!fStartedIncrementalDecode) {
+            return kInvalidParameters;
+        }
+        return this->onIncrementalDecode(rowsDecoded);
+    }
+
+    /**
+     * The remaining functions revolve around decoding scanlines.
+     */
+
+    /**
+     *  Prepare for a scanline decode with the specified options.
+     *
+     *  After this call, this class will be ready to decode the first scanline.
+     *
+     *  This must be called in order to call getScanlines or skipScanlines.
+     *
+     *  This may require rewinding the stream.
+     *
+     *  Not all SkCodecs support this.
+     *
+     *  @param dstInfo Info of the destination. If the dimensions do not match
+     *      those of getInfo, this implies a scale.
+     *  @param options Contains decoding options, including if memory is zero
+     *      initialized.
+     *  @return Enum representing success or reason for failure.
+     */
+    Result startScanlineDecode(const SkImageInfo& dstInfo, const Options* options);
+
+    /**
+     *  Simplified version of startScanlineDecode() that uses the default Options.
+     */
+    Result startScanlineDecode(const SkImageInfo& dstInfo) {
+        return this->startScanlineDecode(dstInfo, nullptr);
+    }
+
+    /**
+     *  Write the next countLines scanlines into dst.
+     *
+     *  Not valid to call before calling startScanlineDecode().
+     *
+     *  @param dst Must be non-null, and large enough to hold countLines
+     *      scanlines of size rowBytes.
+     *  @param countLines Number of lines to write.
+     *  @param rowBytes Number of bytes per row. Must be large enough to hold
+     *      a scanline based on the SkImageInfo used to create this object.
+     *  @return the number of lines successfully decoded.  If this value is
+     *      less than countLines, this will fill the remaining lines with a
+     *      default value.
+     */
+    int getScanlines(void* dst, int countLines, size_t rowBytes);
+
+    /**
+     *  Skip count scanlines.
+     *
+     *  Not valid to call before calling startScanlineDecode().
+     *
+     *  The default version just calls onGetScanlines and discards the dst.
+     *  NOTE: If skipped lines are the only lines with alpha, this default
+     *  will make reallyHasAlpha return true, when it could have returned
+     *  false.
+     *
+     *  @return true if the scanlines were successfully skipped
+     *          false on failure, possible reasons for failure include:
+     *              An incomplete input image stream.
+     *              Calling this function before calling startScanlineDecode().
+     *              If countLines is less than zero or so large that it moves
+     *                  the current scanline past the end of the image.
+     */
+    bool skipScanlines(int countLines);
+
+    /**
+     *  The order in which rows are output from the scanline decoder is not the
+     *  same for all variations of all image types.  This explains the possible
+     *  output row orderings.
+     */
+    enum SkScanlineOrder {
+        /*
+         * By far the most common, this indicates that the image can be decoded
+         * reliably using the scanline decoder, and that rows will be output in
+         * the logical order.
+         */
+        kTopDown_SkScanlineOrder,
+
+        /*
+         * This indicates that the scanline decoder reliably outputs rows, but
+         * they will be returned in reverse order.  If the scanline format is
+         * kBottomUp, the nextScanline() API can be used to determine the actual
+         * y-coordinate of the next output row, but the client is not forced
+         * to take advantage of this, given that it's not too tough to keep
+         * track independently.
+         *
+         * For full image decodes, it is safe to get all of the scanlines at
+         * once, since the decoder will handle inverting the rows as it
+         * decodes.
+         *
+         * For subset decodes and sampling, it is simplest to get and skip
+         * scanlines one at a time, using the nextScanline() API.  It is
+         * possible to ask for larger chunks at a time, but this should be used
+         * with caution.  As with full image decodes, the decoder will handle
+         * inverting the requested rows, but rows will still be delivered
+         * starting from the bottom of the image.
+         *
+         * Upside down bmps are an example.
+         */
+        kBottomUp_SkScanlineOrder,
+    };
+
+    /**
+     *  An enum representing the order in which scanlines will be returned by
+     *  the scanline decoder.
+     *
+     *  This is undefined before startScanlineDecode() is called.
+     */
+    SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); }
+
+    /**
+     *  Returns the y-coordinate of the next row to be returned by the scanline
+     *  decoder.
+     *
+     *  This will equal fCurrScanline, except in the case of strangely
+     *  encoded image types (bottom-up bmps).
+     *
+     *  Results are undefined when not in scanline decoding mode.
+     */
+    int nextScanline() const { return this->outputScanline(fCurrScanline); }
+
+    /**
+     *  Returns the output y-coordinate of the row that corresponds to an input
+     *  y-coordinate.  The input y-coordinate represents where the scanline
+     *  is located in the encoded data.
+     *
+     *  This will equal inputScanline, except in the case of strangely
+     *  encoded image types (bottom-up bmps, interlaced gifs).
+     */
+    int outputScanline(int inputScanline) const;
+
+    /**
+     *  Return the number of frames in the image.
+     *
+     *  May require reading through the stream.
+     */
+    int getFrameCount() {
+        return this->onGetFrameCount();
+    }
+
+    // Sentinel value used when a frame index implies "no frame":
+    // - FrameInfo::fRequiredFrame set to this value means the frame
+    //   is independent.
+    // - Options::fPriorFrame set to this value means no (relevant) prior frame
+    //   is residing in dst's memory.
+    static constexpr int kNoFrame = -1;
+
+    // This transitional definition was added in August 2018, and will eventually be removed.
+#ifdef SK_LEGACY_SKCODEC_NONE_ENUM
+    static constexpr int kNone = kNoFrame;
+#endif
+
+    /**
+     *  Information about individual frames in a multi-framed image.
+     */
+    struct FrameInfo {
+        /**
+         *  The frame that this frame needs to be blended with, or
+         *  kNoFrame if this frame is independent.
+         *
+         *  Note that this is the *earliest* frame that can be used
+         *  for blending. Any frame from [fRequiredFrame, i) can be
+         *  used, unless its fDisposalMethod is kRestorePrevious.
+         */
+        int fRequiredFrame;
+
+        /**
+         *  Number of milliseconds to show this frame.
+         */
+        int fDuration;
+
+        /**
+         *  Whether the end marker for this frame is contained in the stream.
+         *
+         *  Note: this does not guarantee that an attempt to decode will be complete.
+         *  There could be an error in the stream.
+         */
+        bool fFullyReceived;
+
+        /**
+         *  This is conservative; it will still return non-opaque if e.g. a
+         *  color index-based frame has a color with alpha but does not use it.
+         */
+        SkAlphaType fAlphaType;
+
+        /**
+         *  How this frame should be modified before decoding the next one.
+         */
+        SkCodecAnimation::DisposalMethod fDisposalMethod;
+    };
+
+    /**
+     *  Return info about a single frame.
+     *
+     *  Only supported by multi-frame images. Does not read through the stream,
+     *  so it should be called after getFrameCount() to parse any frames that
+     *  have not already been parsed.
+     */
+    bool getFrameInfo(int index, FrameInfo* info) const {
+        if (index < 0) {
+            return false;
+        }
+        return this->onGetFrameInfo(index, info);
+    }
+
+    /**
+     *  Return info about all the frames in the image.
+     *
+     *  May require reading through the stream to determine info about the
+     *  frames (including the count).
+     *
+     *  As such, future decoding calls may require a rewind.
+     *
+     *  For still (non-animated) image codecs, this will return an empty vector.
+     */
+    std::vector<FrameInfo> getFrameInfo();
+
+    static constexpr int kRepetitionCountInfinite = -1;
+
+    /**
+     *  Return the number of times to repeat, if this image is animated. This number does not
+     *  include the first play through of each frame. For example, a repetition count of 4 means
+     *  that each frame is played 5 times and then the animation stops.
+     *
+     *  It can return kRepetitionCountInfinite, a negative number, meaning that the animation
+     *  should loop forever.
+     *
+     *  May require reading the stream to find the repetition count.
+     *
+     *  As such, future decoding calls may require a rewind.
+     *
+     *  For still (non-animated) image codecs, this will return 0.
+     */
+    int getRepetitionCount() {
+        return this->onGetRepetitionCount();
+    }
+
+protected:
+    const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
+
+    using XformFormat = skcms_PixelFormat;
+
+    SkCodec(SkEncodedInfo&&,
+            XformFormat srcFormat,
+            std::unique_ptr<SkStream>,
+            SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
+
+    virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const {
+        // By default, scaling is not supported.
+        return this->dimensions();
+    }
+
+    // FIXME: What to do about subsets??
+    /**
+     *  Subclasses should override if they support dimensions other than the
+     *  srcInfo's.
+     */
+    virtual bool onDimensionsSupported(const SkISize&) {
+        return false;
+    }
+
+    virtual SkEncodedImageFormat onGetEncodedFormat() const = 0;
+
+    /**
+     * @param rowsDecoded When the encoded image stream is incomplete, this function
+     *                    will return kIncompleteInput and rowsDecoded will be set to
+     *                    the number of scanlines that were successfully decoded.
+     *                    This will allow getPixels() to fill the uninitialized memory.
+     */
+    virtual Result onGetPixels(const SkImageInfo& info,
+                               void* pixels, size_t rowBytes, const Options&,
+                               int* rowsDecoded) = 0;
+
+    virtual bool onQueryYUV8(SkYUVASizeInfo*, SkYUVColorSpace*) const {
+        return false;
+    }
+
+    virtual Result onGetYUV8Planes(const SkYUVASizeInfo&,
+                                   void*[SkYUVASizeInfo::kMaxCount] /*planes*/) {
+        return kUnimplemented;
+    }
+
+    virtual bool onGetValidSubset(SkIRect* /*desiredSubset*/) const {
+        // By default, subsets are not supported.
+        return false;
+    }
+
+    /**
+     *  If the stream was previously read, attempt to rewind.
+     *
+     *  If the stream needed to be rewound, call onRewind.
+     *  @returns true if the codec is at the right position and can be used.
+     *      false if there was a failure to rewind.
+     *
+     *  This is called by getPixels(), getYUV8Planes(), startIncrementalDecode() and
+     *  startScanlineDecode(). Subclasses may call if they need to rewind at another time.
+     */
+    bool SK_WARN_UNUSED_RESULT rewindIfNeeded();
+
+    /**
+     *  Called by rewindIfNeeded, if the stream needed to be rewound.
+     *
+     *  Subclasses should do any set up needed after a rewind.
+     */
+    virtual bool onRewind() {
+        return true;
+    }
+
+    /**
+     * Get method for the input stream
+     */
+    SkStream* stream() {
+        return fStream.get();
+    }
+
+    /**
+     *  The remaining functions revolve around decoding scanlines.
+     */
+
+    /**
+     *  Most images types will be kTopDown and will not need to override this function.
+     */
+    virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; }
+
+    const SkImageInfo& dstInfo() const { return fDstInfo; }
+
+    const Options& options() const { return fOptions; }
+
+    /**
+     *  Returns the number of scanlines that have been decoded so far.
+     *  This is unaffected by the SkScanlineOrder.
+     *
+     *  Returns -1 if we have not started a scanline decode.
+     */
+    int currScanline() const { return fCurrScanline; }
+
+    virtual int onOutputScanline(int inputScanline) const;
+
+    /**
+     *  Return whether we can convert to dst.
+     *
+     *  Will be called for the appropriate frame, prior to initializing the colorXform.
+     */
+    virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
+                                     bool needsColorXform);
+
+    // Some classes never need a colorXform e.g.
+    // - ICO uses its embedded codec's colorXform
+    // - WBMP is just Black/White
+    virtual bool usesColorXform() const { return true; }
+    void applyColorXform(void* dst, const void* src, int count) const;
+
+    bool colorXform() const { return fXformTime != kNo_XformTime; }
+    bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
+
+    virtual int onGetFrameCount() {
+        return 1;
+    }
+
+    virtual bool onGetFrameInfo(int, FrameInfo*) const {
+        return false;
+    }
+
+    virtual int onGetRepetitionCount() {
+        return 0;
+    }
+
+private:
+    const SkEncodedInfo                fEncodedInfo;
+    const XformFormat                  fSrcXformFormat;
+    std::unique_ptr<SkStream>          fStream;
+    bool                               fNeedsRewind;
+    const SkEncodedOrigin              fOrigin;
+
+    SkImageInfo                        fDstInfo;
+    Options                            fOptions;
+
+    enum XformTime {
+        kNo_XformTime,
+        kPalette_XformTime,
+        kDecodeRow_XformTime,
+    };
+    XformTime                          fXformTime;
+    XformFormat                        fDstXformFormat; // Based on fDstInfo.
+    skcms_ICCProfile                   fDstProfile;
+    skcms_AlphaFormat                  fDstXformAlphaFormat;
+
+    // Only meaningful during scanline decodes.
+    int                                fCurrScanline;
+
+    bool                               fStartedIncrementalDecode;
+
+    bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
+
+    /**
+     *  Return whether these dimensions are supported as a scale.
+     *
+     *  The codec may choose to cache the information about scale and subset.
+     *  Either way, the same information will be passed to onGetPixels/onStart
+     *  on success.
+     *
+     *  This must return true for a size returned from getScaledDimensions.
+     */
+    bool dimensionsSupported(const SkISize& dim) {
+        return dim == this->dimensions() || this->onDimensionsSupported(dim);
+    }
+
+    /**
+     *  For multi-framed images, return the object with information about the frames.
+     */
+    virtual const SkFrameHolder* getFrameHolder() const {
+        return nullptr;
+    }
+
+    /**
+     *  Check for a valid Options.fFrameIndex, and decode prior frames if necessary.
+     */
+    Result handleFrameIndex(const SkImageInfo&, void* pixels, size_t rowBytes, const Options&);
+
+    // Methods for scanline decoding.
+    virtual Result onStartScanlineDecode(const SkImageInfo& /*dstInfo*/,
+            const Options& /*options*/) {
+        return kUnimplemented;
+    }
+
+    virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t,
+            const Options&) {
+        return kUnimplemented;
+    }
+
+    virtual Result onIncrementalDecode(int*) {
+        return kUnimplemented;
+    }
+
+
+    virtual bool onSkipScanlines(int /*countLines*/) { return false; }
+
+    virtual int onGetScanlines(void* /*dst*/, int /*countLines*/, size_t /*rowBytes*/) { return 0; }
+
+    /**
+     * On an incomplete decode, getPixels() and getScanlines() will call this function
+     * to fill any uinitialized memory.
+     *
+     * @param dstInfo        Contains the destination color type
+     *                       Contains the destination alpha type
+     *                       Contains the destination width
+     *                       The height stored in this info is unused
+     * @param dst            Pointer to the start of destination pixel memory
+     * @param rowBytes       Stride length in destination pixel memory
+     * @param zeroInit       Indicates if memory is zero initialized
+     * @param linesRequested Number of lines that the client requested
+     * @param linesDecoded   Number of lines that were successfully decoded
+     */
+    void fillIncompleteImage(const SkImageInfo& dstInfo, void* dst, size_t rowBytes,
+            ZeroInitialized zeroInit, int linesRequested, int linesDecoded);
+
+    /**
+     *  Return an object which will allow forcing scanline decodes to sample in X.
+     *
+     *  May create a sampler, if one is not currently being used. Otherwise, does
+     *  not affect ownership.
+     *
+     *  Only valid during scanline decoding or incremental decoding.
+     */
+    virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; }
+
+    friend class DM::CodecSrc;  // for fillIncompleteImage
+    friend class SkSampledCodec;
+    friend class SkIcoCodec;
+    friend class SkAndroidCodec; // for fEncodedInfo
+};
+#endif // SkCodec_DEFINED

+ 43 - 0
skia/include/codec/SkCodecAnimation.h

@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCodecAnimation_DEFINED
+#define SkCodecAnimation_DEFINED
+
+namespace SkCodecAnimation {
+    /**
+     *  This specifies how the next frame is based on this frame.
+     *
+     *  Names are based on the GIF 89a spec.
+     *
+     *  The numbers correspond to values in a GIF.
+     */
+    enum class DisposalMethod {
+        /**
+         *  The next frame should be drawn on top of this one.
+         *
+         *  In a GIF, a value of 0 (not specified) is also treated as Keep.
+         */
+        kKeep               = 1,
+
+        /**
+         *  Similar to Keep, except the area inside this frame's rectangle
+         *  should be cleared to the BackGround color (transparent) before
+         *  drawing the next frame.
+         */
+        kRestoreBGColor     = 2,
+
+        /**
+         *  The next frame should be drawn on top of the previous frame - i.e.
+         *  disregarding this one.
+         *
+         *  In a GIF, a value of 4 is also treated as RestorePrevious.
+         */
+        kRestorePrevious    = 3,
+    };
+};
+#endif // SkCodecAnimation_DEFINED

+ 23 - 0
skia/include/codec/SkEncodedOrigin.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkEncodedOrigin_DEFINED
+#define SkEncodedOrigin_DEFINED
+// These values match the orientation www.exif.org/Exif2-2.PDF.
+enum SkEncodedOrigin {
+    kTopLeft_SkEncodedOrigin     = 1, // Default
+    kTopRight_SkEncodedOrigin    = 2, // Reflected across y-axis
+    kBottomRight_SkEncodedOrigin = 3, // Rotated 180
+    kBottomLeft_SkEncodedOrigin  = 4, // Reflected across x-axis
+    kLeftTop_SkEncodedOrigin     = 5, // Reflected across x-axis, Rotated 90 CCW
+    kRightTop_SkEncodedOrigin    = 6, // Rotated 90 CW
+    kRightBottom_SkEncodedOrigin = 7, // Reflected across x-axis, Rotated 90 CW
+    kLeftBottom_SkEncodedOrigin  = 8, // Rotated 90 CCW
+    kDefault_SkEncodedOrigin     = kTopLeft_SkEncodedOrigin,
+    kLast_SkEncodedOrigin        = kLeftBottom_SkEncodedOrigin,
+};
+#endif // SkEncodedOrigin_DEFINED

+ 130 - 0
skia/include/config/SkUserConfig.h

@@ -0,0 +1,130 @@
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkUserConfig_DEFINED
+#define SkUserConfig_DEFINED
+
+/*  SkTypes.h, the root of the public header files, does the following trick:
+
+    #include "SkPreConfig.h"
+    #include "SkUserConfig.h"
+    #include "SkPostConfig.h"
+
+    SkPreConfig.h runs first, and it is responsible for initializing certain
+    skia defines.
+
+    SkPostConfig.h runs last, and its job is to just check that the final
+    defines are consistent (i.e. that we don't have mutually conflicting
+    defines).
+
+    SkUserConfig.h (this file) runs in the middle. It gets to change or augment
+    the list of flags initially set in preconfig, and then postconfig checks
+    that everything still makes sense.
+
+    Below are optional defines that add, subtract, or change default behavior
+    in Skia. Your port can locally edit this file to enable/disable flags as
+    you choose, or these can be delared on your command line (i.e. -Dfoo).
+
+    By default, this include file will always default to having all of the flags
+    commented out, so including it will have no effect.
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+
+/*  Skia has lots of debug-only code. Often this is just null checks or other
+    parameter checking, but sometimes it can be quite intrusive (e.g. check that
+    each 32bit pixel is in premultiplied form). This code can be very useful
+    during development, but will slow things down in a shipping product.
+
+    By default, these mutually exclusive flags are defined in SkPreConfig.h,
+    based on the presence or absence of NDEBUG, but that decision can be changed
+    here.
+ */
+//#define SK_DEBUG
+//#define SK_RELEASE
+
+/*  Skia has certain debug-only code that is extremely intensive even for debug
+    builds.  This code is useful for diagnosing specific issues, but is not
+    generally applicable, therefore it must be explicitly enabled to avoid
+    the performance impact. By default these flags are undefined, but can be
+    enabled by uncommenting them below.
+ */
+//#define SK_DEBUG_GLYPH_CACHE
+//#define SK_DEBUG_PATH
+
+/*  preconfig will have attempted to determine the endianness of the system,
+    but you can change these mutually exclusive flags here.
+ */
+//#define SK_CPU_BENDIAN
+//#define SK_CPU_LENDIAN
+
+/*  Most compilers use the same bit endianness for bit flags in a byte as the
+    system byte endianness, and this is the default. If for some reason this
+    needs to be overridden, specify which of the mutually exclusive flags to
+    use. For example, some atom processors in certain configurations have big
+    endian byte order but little endian bit orders.
+*/
+//#define SK_UINT8_BITFIELD_BENDIAN
+//#define SK_UINT8_BITFIELD_LENDIAN
+
+
+/*  To write debug messages to a console, skia will call SkDebugf(...) following
+    printf conventions (e.g. const char* format, ...). If you want to redirect
+    this to something other than printf, define yours here
+ */
+//#define SkDebugf(...)  MyFunction(__VA_ARGS__)
+
+/*
+ *  To specify a different default font cache limit, define this. If this is
+ *  undefined, skia will use a built-in value.
+ */
+//#define SK_DEFAULT_FONT_CACHE_LIMIT   (1024 * 1024)
+
+/*
+ *  To specify the default size of the image cache, undefine this and set it to
+ *  the desired value (in bytes). SkGraphics.h as a runtime API to set this
+ *  value as well. If this is undefined, a built-in value will be used.
+ */
+//#define SK_DEFAULT_IMAGE_CACHE_LIMIT (1024 * 1024)
+
+/*  Define this to set the upper limit for text to support LCD. Values that
+    are very large increase the cost in the font cache and draw slower, without
+    improving readability. If this is undefined, Skia will use its default
+    value (e.g. 48)
+ */
+//#define SK_MAX_SIZE_FOR_LCDTEXT     48
+
+/*  Change the ordering to work in X windows.
+ */
+#ifdef SK_SAMPLES_FOR_X
+        #define SK_R32_SHIFT    16
+        #define SK_G32_SHIFT    8
+        #define SK_B32_SHIFT    0
+        #define SK_A32_SHIFT    24
+#endif
+
+
+/* Determines whether to build code that supports the GPU backend. Some classes
+   that are not GPU-specific, such as SkShader subclasses, have optional code
+   that is used allows them to interact with the GPU backend. If you'd like to
+   omit this code set SK_SUPPORT_GPU to 0. This also allows you to omit the gpu
+   directories from your include search path when you're not building the GPU
+   backend. Defaults to 1 (build the GPU code).
+ */
+//#define SK_SUPPORT_GPU 1
+
+/* Skia makes use of histogram logging macros to trace the frequency of
+ * events. By default, Skia provides no-op versions of these macros.
+ * Skia consumers can provide their own definitions of these macros to
+ * integrate with their histogram collection backend.
+ */
+//#define SK_HISTOGRAM_BOOLEAN(name, value)
+//#define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value)
+
+#endif

+ 50 - 0
skia/include/core/SkAnnotation.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAnnotation_DEFINED
+#define SkAnnotation_DEFINED
+
+#include "SkTypes.h"
+
+class SkData;
+struct SkPoint;
+struct SkRect;
+class SkCanvas;
+
+/**
+ *  Annotate the canvas by associating the specified URL with the
+ *  specified rectangle (in local coordinates, just like drawRect).
+ *
+ *  If the backend of this canvas does not support annotations, this call is
+ *  safely ignored.
+ *
+ *  The caller is responsible for managing its ownership of the SkData.
+ */
+SK_API void SkAnnotateRectWithURL(SkCanvas*, const SkRect&, SkData*);
+
+/**
+ *  Annotate the canvas by associating a name with the specified point.
+ *
+ *  If the backend of this canvas does not support annotations, this call is
+ *  safely ignored.
+ *
+ *  The caller is responsible for managing its ownership of the SkData.
+ */
+SK_API void SkAnnotateNamedDestination(SkCanvas*, const SkPoint&, SkData*);
+
+/**
+ *  Annotate the canvas by making the specified rectangle link to a named
+ *  destination.
+ *
+ *  If the backend of this canvas does not support annotations, this call is
+ *  safely ignored.
+ *
+ *  The caller is responsible for managing its ownership of the SkData.
+ */
+SK_API void SkAnnotateLinkToDestination(SkCanvas*, const SkRect&, SkData*);
+
+#endif

+ 31 - 0
skia/include/core/SkBBHFactory.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBBHFactory_DEFINED
+#define SkBBHFactory_DEFINED
+
+#include "SkTypes.h"
+class SkBBoxHierarchy;
+struct SkRect;
+
+class SK_API SkBBHFactory {
+public:
+    /**
+     *  Allocate a new SkBBoxHierarchy. Return NULL on failure.
+     */
+    virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const = 0;
+    virtual ~SkBBHFactory() {}
+};
+
+class SK_API SkRTreeFactory : public SkBBHFactory {
+public:
+    SkBBoxHierarchy* operator()(const SkRect& bounds) const override;
+private:
+    typedef SkBBHFactory INHERITED;
+};
+
+#endif

+ 1195 - 0
skia/include/core/SkBitmap.h

@@ -0,0 +1,1195 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkBitmap.h and docs/SkBitmap_Reference.bmh
+   on 2018-09-13 13:59:55. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkBitmap_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkBitmap_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkBitmap.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkBitmap_DEFINED
+#define SkBitmap_DEFINED
+
+#include "SkColor.h"
+#include "SkImageInfo.h"
+#include "SkPixmap.h"
+#include "SkPoint.h"
+#include "SkRefCnt.h"
+
+struct SkMask;
+struct SkIRect;
+struct SkRect;
+class SkPaint;
+class SkPixelRef;
+class SkString;
+
+/** \class SkBitmap
+    SkBitmap describes a two-dimensional raster pixel array. SkBitmap is built on
+    SkImageInfo, containing integer width and height, SkColorType and SkAlphaType
+    describing the pixel format, and SkColorSpace describing the range of colors.
+    SkBitmap points to SkPixelRef, which describes the physical array of pixels.
+    SkImageInfo bounds may be located anywhere fully inside SkPixelRef bounds.
+
+    SkBitmap can be drawn using SkCanvas. SkBitmap can be a drawing destination for SkCanvas
+    draw member functions. SkBitmap flexibility as a pixel container limits some
+    optimizations available to the target platform.
+
+    If pixel array is primarily read-only, use SkImage for better performance.
+    If pixel array is primarily written to, use SkSurface for better performance.
+
+    Declaring SkBitmap const prevents altering SkImageInfo: the SkBitmap height, width,
+    and so on cannot change. It does not affect SkPixelRef: a caller may write its
+    pixels. Declaring SkBitmap const affects SkBitmap configuration, not its contents.
+
+    SkBitmap is not thread safe. Each thread must have its own copy of SkBitmap fields,
+    although threads may share the underlying pixel array.
+*/
+class SK_API SkBitmap {
+public:
+    class SK_API Allocator;
+
+    /** Creates an empty SkBitmap without pixels, with kUnknown_SkColorType,
+        kUnknown_SkAlphaType, and with a width and height of zero. SkPixelRef origin is
+        set to (0, 0). SkBitmap is not volatile.
+
+        Use setInfo() to associate SkColorType, SkAlphaType, width, and height
+        after SkBitmap has been created.
+
+        @return  empty SkBitmap
+    */
+    SkBitmap();
+
+    /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels
+        allocated, so both bitmaps reference the same pixels.
+
+        @param src  SkBitmap to copy SkImageInfo, and share SkPixelRef
+        @return     copy of src
+    */
+    SkBitmap(const SkBitmap& src);
+
+    /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to
+        SkBitmap.
+
+        @param src  SkBitmap to copy SkImageInfo, and reassign SkPixelRef
+        @return     copy of src
+    */
+    SkBitmap(SkBitmap&& src);
+
+    /** Decrements SkPixelRef reference count, if SkPixelRef is not nullptr.
+    */
+    ~SkBitmap();
+
+    /** Copies settings from src to returned SkBitmap. Shares pixels if src has pixels
+        allocated, so both bitmaps reference the same pixels.
+
+        @param src  SkBitmap to copy SkImageInfo, and share SkPixelRef
+        @return     copy of src
+    */
+    SkBitmap& operator=(const SkBitmap& src);
+
+    /** Copies settings from src to returned SkBitmap. Moves ownership of src pixels to
+        SkBitmap.
+
+        @param src  SkBitmap to copy SkImageInfo, and reassign SkPixelRef
+        @return     copy of src
+    */
+    SkBitmap& operator=(SkBitmap&& src);
+
+    /** Swaps the fields of the two bitmaps.
+
+        @param other  SkBitmap exchanged with original
+    */
+    void swap(SkBitmap& other);
+
+    /** Returns a constant reference to the SkPixmap holding the SkBitmap pixel
+        address, row bytes, and SkImageInfo.
+
+        @return  reference to SkPixmap describing this SkBitmap
+    */
+    const SkPixmap& pixmap() const { return fPixmap; }
+
+    /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace.
+
+        @return  reference to SkImageInfo
+    */
+    const SkImageInfo& info() const { return fPixmap.info(); }
+
+    /** Returns pixel count in each row. Should be equal or less than
+        rowBytes() / info().bytesPerPixel().
+
+        May be less than pixelRef().width(). Will not exceed pixelRef().width() less
+        pixelRefOrigin().fX.
+
+        @return  pixel width in SkImageInfo
+    */
+    int width() const { return fPixmap.width(); }
+
+    /** Returns pixel row count.
+
+        Maybe be less than pixelRef().height(). Will not exceed pixelRef().height() less
+        pixelRefOrigin().fY.
+
+        @return  pixel height in SkImageInfo
+    */
+    int height() const { return fPixmap.height(); }
+
+    /** Returns SkColorType, one of:
+        kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+        kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+        kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+        kGray_8_SkColorType, kRGBA_F16_SkColorType.
+
+        @return  SkColorType in SkImageInfo
+    */
+    SkColorType colorType() const { return fPixmap.colorType(); }
+
+    /** Returns SkAlphaType, one of:
+        kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+        kUnpremul_SkAlphaType.
+
+        @return  SkAlphaType in SkImageInfo
+    */
+    SkAlphaType alphaType() const { return fPixmap.alphaType(); }
+
+    /** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The
+        reference count of SkColorSpace is unchanged. The returned SkColorSpace is
+        immutable.
+
+        @return  SkColorSpace in SkImageInfo, or nullptr
+    */
+    SkColorSpace* colorSpace() const { return fPixmap.colorSpace(); }
+
+    /** Returns smart pointer to SkColorSpace, the range of colors, associated with
+        SkImageInfo. The smart pointer tracks the number of objects sharing this
+        SkColorSpace reference so the memory is released when the owners destruct.
+
+        The returned SkColorSpace is immutable.
+
+        @return  SkColorSpace in SkImageInfo wrapped in a smart pointer
+    */
+    sk_sp<SkColorSpace> refColorSpace() const { return fPixmap.info().refColorSpace(); }
+
+    /** Returns number of bytes per pixel required by SkColorType.
+        Returns zero if colorType( is kUnknown_SkColorType.
+
+        @return  bytes in pixel
+    */
+    int bytesPerPixel() const { return fPixmap.info().bytesPerPixel(); }
+
+    /** Returns number of pixels that fit on row. Should be greater than or equal to
+        width().
+
+        @return  maximum pixels per row
+    */
+    int rowBytesAsPixels() const { return fPixmap.rowBytesAsPixels(); }
+
+    /** Returns bit shift converting row bytes to row pixels.
+        Returns zero for kUnknown_SkColorType.
+
+        @return  one of: 0, 1, 2, 3; left shift to convert pixels to bytes
+    */
+    int shiftPerPixel() const { return fPixmap.shiftPerPixel(); }
+
+    /** Returns true if either width() or height() are zero.
+
+        Does not check if SkPixelRef is nullptr; call drawsNothing() to check width(),
+        height(), and SkPixelRef.
+
+        @return  true if dimensions do not enclose area
+    */
+    bool empty() const { return fPixmap.info().isEmpty(); }
+
+    /** Returns true if SkPixelRef is nullptr.
+
+        Does not check if width() or height() are zero; call drawsNothing() to check
+        width(), height(), and SkPixelRef.
+
+        @return  true if no SkPixelRef is associated
+    */
+    bool isNull() const { return nullptr == fPixelRef; }
+
+    /** Returns true if width() or height() are zero, or if SkPixelRef is nullptr.
+        If true, SkBitmap has no effect when drawn or drawn into.
+
+        @return  true if drawing has no effect
+    */
+    bool drawsNothing() const {
+        return this->empty() || this->isNull();
+    }
+
+    /** Returns row bytes, the interval from one pixel row to the next. Row bytes
+        is at least as large as: width() * info().bytesPerPixel().
+
+        Returns zero if colorType() is kUnknown_SkColorType, or if row bytes supplied to
+        setInfo() is not large enough to hold a row of pixels.
+
+        @return  byte length of pixel row
+    */
+    size_t rowBytes() const { return fPixmap.rowBytes(); }
+
+    /** Sets SkAlphaType, if alphaType is compatible with SkColorType.
+        Returns true unless alphaType is kUnknown_SkAlphaType and current SkAlphaType
+        is not kUnknown_SkAlphaType.
+
+        Returns true if SkColorType is kUnknown_SkColorType. alphaType is ignored, and
+        SkAlphaType remains kUnknown_SkAlphaType.
+
+        Returns true if SkColorType is kRGB_565_SkColorType or kGray_8_SkColorType.
+        alphaType is ignored, and SkAlphaType remains kOpaque_SkAlphaType.
+
+        If SkColorType is kARGB_4444_SkColorType, kRGBA_8888_SkColorType,
+        kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: returns true unless
+        alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType.
+        If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored.
+
+        If SkColorType is kAlpha_8_SkColorType, returns true unless
+        alphaType is kUnknown_SkAlphaType and SkAlphaType is not kUnknown_SkAlphaType.
+        If SkAlphaType is kUnknown_SkAlphaType, alphaType is ignored. If alphaType is
+        kUnpremul_SkAlphaType, it is treated as kPremul_SkAlphaType.
+
+        This changes SkAlphaType in SkPixelRef; all bitmaps sharing SkPixelRef
+        are affected.
+
+        @param alphaType  one of:
+                          kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                          kUnpremul_SkAlphaType
+        @return           true if SkAlphaType is set
+    */
+    bool setAlphaType(SkAlphaType alphaType);
+
+    /** Returns pixel address, the base address corresponding to the pixel origin.
+
+        @return  pixel address
+    */
+    void* getPixels() const { return fPixmap.writable_addr(); }
+
+    /** Returns minimum memory required for pixel storage.
+        Does not include unused memory on last row when rowBytesAsPixels() exceeds width().
+        Returns zero if result does not fit in size_t.
+        Returns zero if height() or width() is 0.
+        Returns height() times rowBytes() if colorType() is kUnknown_SkColorType.
+
+        @return  size in bytes of image buffer
+    */
+    size_t computeByteSize() const { return fPixmap.computeByteSize(); }
+
+    /** Returns true if pixels can not change.
+
+        Most immutable SkBitmap checks trigger an assert only on debug builds.
+
+        @return  true if pixels are immutable
+    */
+    bool isImmutable() const;
+
+    /** Sets internal flag to mark SkBitmap as immutable. Once set, pixels can not change.
+        Any other bitmap sharing the same SkPixelRef are also marked as immutable.
+        Once SkPixelRef is marked immutable, the setting cannot be cleared.
+
+        Writing to immutable SkBitmap pixels triggers an assert on debug builds.
+    */
+    void setImmutable();
+
+    /** Returns true if SkAlphaType is set to hint that all pixels are opaque; their
+        alpha value is implicitly or explicitly 1.0. If true, and all pixels are
+        not opaque, Skia may draw incorrectly.
+
+        Does not check if SkColorType allows alpha, or if any pixel value has
+        transparency.
+
+        @return  true if SkImageInfo SkAlphaType is kOpaque_SkAlphaType
+    */
+    bool isOpaque() const {
+        return SkAlphaTypeIsOpaque(this->alphaType());
+    }
+
+    /** Provides a hint to caller that pixels should not be cached. Only true if
+        setIsVolatile() has been called to mark as volatile.
+
+        Volatile state is not shared by other bitmaps sharing the same SkPixelRef.
+
+        @return  true if marked volatile
+    */
+    bool isVolatile() const;
+
+    /** Sets if pixels should be read from SkPixelRef on every access. SkBitmap are not
+        volatile by default; a GPU back end may upload pixel values expecting them to be
+        accessed repeatedly. Marking temporary SkBitmap as volatile provides a hint to
+        SkBaseDevice that the SkBitmap pixels should not be cached. This can
+        improve performance by avoiding overhead and reducing resource
+        consumption on SkBaseDevice.
+
+        @param isVolatile  true if backing pixels are temporary
+    */
+    void setIsVolatile(bool isVolatile);
+
+    /** Resets to its initial state; all fields are set to zero, as if SkBitmap had
+        been initialized by SkBitmap().
+
+        Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to
+        kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType.
+
+        If SkPixelRef is allocated, its reference count is decreased by one, releasing
+        its memory if SkBitmap is the sole owner.
+    */
+    void reset();
+
+    /** Returns true if all pixels are opaque. SkColorType determines how pixels
+        are encoded, and whether pixel describes alpha. Returns true for SkColorType
+        without alpha in each pixel; for other SkColorType, returns true if all
+        pixels have alpha values equivalent to 1.0 or greater.
+
+        For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always
+        returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType,
+        kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255.
+        For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15.
+        For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or
+        greater.
+
+        Returns false for kUnknown_SkColorType.
+
+        @param bm  SkBitmap to check
+        @return    true if all pixels have opaque values or SkColorType is opaque
+    */
+    static bool ComputeIsOpaque(const SkBitmap& bm) {
+        return bm.pixmap().computeIsOpaque();
+    }
+
+    /** Returns SkRect { 0, 0, width(), height() }.
+
+        @param bounds  container for floating point rectangle
+    */
+    void getBounds(SkRect* bounds) const;
+
+    /** Returns SkIRect { 0, 0, width(), height() }.
+
+        @param bounds  container for integral rectangle
+    */
+    void getBounds(SkIRect* bounds) const;
+
+    /** Returns SkIRect { 0, 0, width(), height() }.
+
+        @return  integral rectangle from origin to width() and height()
+    */
+    SkIRect bounds() const { return fPixmap.info().bounds(); }
+
+    /** Returns SkISize { width(), height() }.
+
+        @return  integral size of width() and height()
+    */
+    SkISize dimensions() const { return fPixmap.info().dimensions(); }
+
+    /** Returns the bounds of this bitmap, offset by its SkPixelRef origin.
+
+        @return  bounds within SkPixelRef bounds
+    */
+    SkIRect getSubset() const {
+        SkIPoint origin = this->pixelRefOrigin();
+        return SkIRect::MakeXYWH(origin.x(), origin.y(), this->width(), this->height());
+    }
+
+    /** Sets width, height, SkAlphaType, SkColorType, SkColorSpace, and optional
+        rowBytes. Frees pixels, and returns true if successful.
+
+        imageInfo.alphaType() may be altered to a value permitted by imageInfo.colorSpace().
+        If imageInfo.colorType() is kUnknown_SkColorType, imageInfo.alphaType() is
+        set to kUnknown_SkAlphaType.
+        If imageInfo.colorType() is kAlpha_8_SkColorType and imageInfo.alphaType() is
+        kUnpremul_SkAlphaType, imageInfo.alphaType() is replaced by kPremul_SkAlphaType.
+        If imageInfo.colorType() is kRGB_565_SkColorType or kGray_8_SkColorType,
+        imageInfo.alphaType() is set to kOpaque_SkAlphaType.
+        If imageInfo.colorType() is kARGB_4444_SkColorType, kRGBA_8888_SkColorType,
+        kBGRA_8888_SkColorType, or kRGBA_F16_SkColorType: imageInfo.alphaType() remains
+        unchanged.
+
+        rowBytes must equal or exceed imageInfo.minRowBytes(). If imageInfo.colorSpace() is
+        kUnknown_SkColorType, rowBytes is ignored and treated as zero; for all other
+        SkColorSpace values, rowBytes of zero is treated as imageInfo.minRowBytes().
+
+        Calls reset() and returns false if:
+        - rowBytes exceeds 31 bits
+        - imageInfo.width() is negative
+        - imageInfo.height() is negative
+        - rowBytes is positive and less than imageInfo.width() times imageInfo.bytesPerPixel()
+
+        @param imageInfo  contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param rowBytes   imageInfo.minRowBytes() or larger; or zero
+        @return           true if SkImageInfo set successfully
+    */
+    bool setInfo(const SkImageInfo& imageInfo, size_t rowBytes = 0);
+
+    /** \enum SkBitmap::AllocFlags
+        AllocFlags provides the option to zero pixel memory when allocated.
+    */
+    enum AllocFlags {
+        kZeroPixels_AllocFlag = 1 << 0, //!< zero pixel memory
+    };
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory. If flags is kZeroPixels_AllocFlag, memory is zeroed.
+
+        Returns false and calls reset() if SkImageInfo could not be set, or memory could
+        not be allocated, or memory could not optionally be zeroed.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc(), if flags is zero, and calloc(), if flags is
+        kZeroPixels_AllocFlag.
+
+        flags set to kZeroPixels_AllocFlag offers equal or better performance than
+        subsequently calling eraseColor() with SK_ColorTRANSPARENT.
+
+        @param info   contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param flags  kZeroPixels_AllocFlag, or zero
+        @return       true if pixels allocation is successful
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocPixelsFlags(const SkImageInfo& info, uint32_t flags);
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory. If flags is kZeroPixels_AllocFlag, memory is zeroed.
+
+        Aborts execution if SkImageInfo could not be set, or memory could
+        not be allocated, or memory could not optionally
+        be zeroed. Abort steps may be provided by the user at compile time by defining
+        SK_ABORT.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc(), if flags is zero, and calloc(), if flags is
+        kZeroPixels_AllocFlag.
+
+        flags set to kZeroPixels_AllocFlag offers equal or better performance than
+        subsequently calling eraseColor() with SK_ColorTRANSPARENT.
+
+        @param info   contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param flags  kZeroPixels_AllocFlag, or zero
+    */
+    void allocPixelsFlags(const SkImageInfo& info, uint32_t flags) {
+        SkASSERT_RELEASE(this->tryAllocPixelsFlags(info, flags));
+    }
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(),
+        or equal zero. Pass in zero for rowBytes to compute the minimum valid value.
+
+        Returns false and calls reset() if SkImageInfo could not be set, or memory could
+        not be allocated.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc().
+
+        @param info      contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param rowBytes  size of pixel row or larger; may be zero
+        @return          true if pixel storage is allocated
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info, size_t rowBytes);
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory. rowBytes must equal or exceed info.width() times info.bytesPerPixel(),
+        or equal zero. Pass in zero for rowBytes to compute the minimum valid value.
+
+        Aborts execution if SkImageInfo could not be set, or memory could
+        not be allocated. Abort steps may be provided by
+        the user at compile time by defining SK_ABORT.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc().
+
+        @param info      contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param rowBytes  size of pixel row or larger; may be zero
+    */
+    void allocPixels(const SkImageInfo& info, size_t rowBytes) {
+        SkASSERT_RELEASE(this->tryAllocPixels(info, rowBytes));
+    }
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory.
+
+        Returns false and calls reset() if SkImageInfo could not be set, or memory could
+        not be allocated.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc().
+
+        @param info  contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @return      true if pixel storage is allocated
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocPixels(const SkImageInfo& info) {
+        return this->tryAllocPixels(info, info.minRowBytes());
+    }
+
+    /** Sets SkImageInfo to info following the rules in setInfo() and allocates pixel
+        memory.
+
+        Aborts execution if SkImageInfo could not be set, or memory could
+        not be allocated. Abort steps may be provided by
+        the user at compile time by defining SK_ABORT.
+
+        On most platforms, allocating pixel memory may succeed even though there is
+        not sufficient memory to hold pixels; allocation does not take place
+        until the pixels are written to. The actual behavior depends on the platform
+        implementation of malloc().
+
+        @param info  contains width, height, SkAlphaType, SkColorType, SkColorSpace
+    */
+    void allocPixels(const SkImageInfo& info) {
+        this->allocPixels(info, info.minRowBytes());
+    }
+
+    /** Sets SkImageInfo to width, height, and native color type; and allocates
+        pixel memory. If isOpaque is true, sets SkImageInfo to kOpaque_SkAlphaType;
+        otherwise, sets to kPremul_SkAlphaType.
+
+        Calls reset() and returns false if width exceeds 29 bits or is negative,
+        or height is negative.
+
+        Returns false if allocation fails.
+
+        Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on
+        the platform. SkBitmap drawn to output device skips converting its pixel format.
+
+        @param width     pixel column count; must be zero or greater
+        @param height    pixel row count; must be zero or greater
+        @param isOpaque  true if pixels do not have transparency
+        @return          true if pixel storage is allocated
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocN32Pixels(int width, int height, bool isOpaque = false) {
+        SkImageInfo info = SkImageInfo::MakeN32(width, height,
+                                            isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+        return this->tryAllocPixels(info);
+    }
+
+    /** Sets SkImageInfo to width, height, and the native color type; and allocates
+        pixel memory. If isOpaque is true, sets SkImageInfo to kPremul_SkAlphaType;
+        otherwise, sets to kOpaque_SkAlphaType.
+
+        Aborts if width exceeds 29 bits or is negative, or height is negative, or
+        allocation fails. Abort steps may be provided by the user at compile time by
+        defining SK_ABORT.
+
+        Use to create SkBitmap that matches SkPMColor, the native pixel arrangement on
+        the platform. SkBitmap drawn to output device skips converting its pixel format.
+
+        @param width     pixel column count; must be zero or greater
+        @param height    pixel row count; must be zero or greater
+        @param isOpaque  true if pixels do not have transparency
+    */
+    void allocN32Pixels(int width, int height, bool isOpaque = false) {
+        SkImageInfo info = SkImageInfo::MakeN32(width, height,
+                                            isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
+        this->allocPixels(info);
+    }
+
+    /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef
+        containing pixels and rowBytes. releaseProc, if not nullptr, is called
+        immediately on failure or when pixels are no longer referenced. context may be
+        nullptr.
+
+        If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes():
+        calls releaseProc if present, calls reset(), and returns false.
+
+        Otherwise, if pixels equals nullptr: sets SkImageInfo, calls releaseProc if
+        present, returns true.
+
+        If SkImageInfo is set, pixels is not nullptr, and releaseProc is not nullptr:
+        when pixels are no longer referenced, calls releaseProc with pixels and context
+        as parameters.
+
+        @param info         contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param pixels       address or pixel storage; may be nullptr
+        @param rowBytes     size of pixel row or larger
+        @param releaseProc  function called when pixels can be deleted; may be nullptr
+        @param context      caller state passed to releaseProc; may be nullptr
+        @return             true if SkImageInfo is set to info
+    */
+    bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+                       void (*releaseProc)(void* addr, void* context), void* context);
+
+    /** Sets SkImageInfo to info following the rules in setInfo(), and creates SkPixelRef
+        containing pixels and rowBytes.
+
+        If SkImageInfo could not be set, or rowBytes is less than info.minRowBytes():
+        calls reset(), and returns false.
+
+        Otherwise, if pixels equals nullptr: sets SkImageInfo, returns true.
+
+        Caller must ensure that pixels are valid for the lifetime of SkBitmap and SkPixelRef.
+
+        @param info      contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param pixels    address or pixel storage; may be nullptr
+        @param rowBytes  size of pixel row or larger
+        @return          true if SkImageInfo is set to info
+    */
+    bool installPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
+        return this->installPixels(info, pixels, rowBytes, nullptr, nullptr);
+    }
+
+    /** Sets SkImageInfo to pixmap.info() following the rules in setInfo(), and creates
+        SkPixelRef containing pixmap.addr() and pixmap.rowBytes().
+
+        If SkImageInfo could not be set, or pixmap.rowBytes() is less than
+        SkImageInfo::minRowBytes(): calls reset(), and returns false.
+
+        Otherwise, if pixmap.addr() equals nullptr: sets SkImageInfo, returns true.
+
+        Caller must ensure that pixmap is valid for the lifetime of SkBitmap and SkPixelRef.
+
+        @param pixmap  SkImageInfo, pixel address, and rowBytes()
+        @return        true if SkImageInfo was set to pixmap.info()
+    */
+    bool installPixels(const SkPixmap& pixmap);
+
+    /** Deprecated.
+    */
+    bool installMaskPixels(const SkMask& mask);
+
+    /** Replaces SkPixelRef with pixels, preserving SkImageInfo and rowBytes().
+        Sets SkPixelRef origin to (0, 0).
+
+        If pixels is nullptr, or if info().colorType() equals kUnknown_SkColorType;
+        release reference to SkPixelRef, and set SkPixelRef to nullptr.
+
+        Caller is responsible for handling ownership pixel memory for the lifetime
+        of SkBitmap and SkPixelRef.
+
+        @param pixels  address of pixel storage, managed by caller
+    */
+    void setPixels(void* pixels);
+
+    /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef.
+        The allocation size is determined by SkImageInfo width, height, and SkColorType.
+
+        Returns false if info().colorType() is kUnknown_SkColorType, or allocation fails.
+
+        @return  true if the allocation succeeds
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocPixels() {
+        return this->tryAllocPixels((Allocator*)nullptr);
+    }
+
+    /** Allocates pixel memory with HeapAllocator, and replaces existing SkPixelRef.
+        The allocation size is determined by SkImageInfo width, height, and SkColorType.
+
+        Aborts if info().colorType() is kUnknown_SkColorType, or allocation fails.
+        Abort steps may be provided by the user at compile
+        time by defining SK_ABORT.
+    */
+    void allocPixels() {
+        this->allocPixels((Allocator*)nullptr);
+    }
+
+    /** Allocates pixel memory with allocator, and replaces existing SkPixelRef.
+        The allocation size is determined by SkImageInfo width, height, and SkColorType.
+        If allocator is nullptr, use HeapAllocator instead.
+
+        Returns false if Allocator::allocPixelRef return false.
+
+        @param allocator  instance of SkBitmap::Allocator instantiation
+        @return           true if custom allocator reports success
+    */
+    bool SK_WARN_UNUSED_RESULT tryAllocPixels(Allocator* allocator);
+
+    /** Allocates pixel memory with allocator, and replaces existing SkPixelRef.
+        The allocation size is determined by SkImageInfo width, height, and SkColorType.
+        If allocator is nullptr, use HeapAllocator instead.
+
+        Aborts if Allocator::allocPixelRef return false. Abort steps may be provided by
+        the user at compile time by defining SK_ABORT.
+
+        @param allocator  instance of SkBitmap::Allocator instantiation
+    */
+    void allocPixels(Allocator* allocator) {
+        SkASSERT_RELEASE(this->tryAllocPixels(allocator));
+    }
+
+    /** Returns SkPixelRef, which contains: pixel base address; its dimensions; and
+        rowBytes(), the interval from one row to the next. Does not change SkPixelRef
+        reference count. SkPixelRef may be shared by multiple bitmaps.
+        If SkPixelRef has not been set, returns nullptr.
+
+        @return  SkPixelRef, or nullptr
+    */
+    SkPixelRef* pixelRef() const { return fPixelRef.get(); }
+
+    /** Returns origin of pixels within SkPixelRef. SkBitmap bounds is always contained
+        by SkPixelRef bounds, which may be the same size or larger. Multiple SkBitmap
+        can share the same SkPixelRef, where each SkBitmap has different bounds.
+
+        The returned origin added to SkBitmap dimensions equals or is smaller than the
+        SkPixelRef dimensions.
+
+        Returns (0, 0) if SkPixelRef is nullptr.
+
+        @return  pixel origin within SkPixelRef
+    */
+    SkIPoint pixelRefOrigin() const;
+
+    /** Replaces pixelRef and origin in SkBitmap.  dx and dy specify the offset
+        within the SkPixelRef pixels for the top-left corner of the bitmap.
+
+        Asserts in debug builds if dx or dy are out of range. Pins dx and dy
+        to legal range in release builds.
+
+        The caller is responsible for ensuring that the pixels match the
+        SkColorType and SkAlphaType in SkImageInfo.
+
+        @param pixelRef  SkPixelRef describing pixel address and rowBytes()
+        @param dx        column offset in SkPixelRef for bitmap origin
+        @param dy        row offset in SkPixelRef for bitmap origin
+    */
+    void setPixelRef(sk_sp<SkPixelRef> pixelRef, int dx, int dy);
+
+    /** Returns true if SkBitmap is can be drawn.
+
+        @return  true if getPixels() is not nullptr
+    */
+    bool readyToDraw() const {
+        return this->getPixels() != nullptr;
+    }
+
+    /** Returns a unique value corresponding to the pixels in SkPixelRef.
+        Returns a different value after notifyPixelsChanged() has been called.
+        Returns zero if SkPixelRef is nullptr.
+
+        Determines if pixels have changed since last examined.
+
+        @return  unique value for pixels in SkPixelRef
+    */
+    uint32_t getGenerationID() const;
+
+    /** Marks that pixels in SkPixelRef have changed. Subsequent calls to
+        getGenerationID() return a different value.
+    */
+    void notifyPixelsChanged() const;
+
+    /** Replaces pixel values with c. All pixels contained by bounds() are affected.
+        If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha
+        is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType,
+        then RGB is ignored.
+
+        @param c  unpremultiplied color
+    */
+    void eraseColor(SkColor c) const;
+
+    /** Replaces pixel values with unpremultiplied color built from a, r, g, and b.
+        All pixels contained by bounds() are affected.
+        If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then a
+        is ignored; r, g, and b are treated as opaque. If colorType() is kAlpha_8_SkColorType,
+        then r, g, and b are ignored.
+
+        @param a  amount of alpha, from fully transparent (0) to fully opaque (255)
+        @param r  amount of red, from no red (0) to full red (255)
+        @param g  amount of green, from no green (0) to full green (255)
+        @param b  amount of blue, from no blue (0) to full blue (255)
+    */
+    void eraseARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) const {
+        this->eraseColor(SkColorSetARGB(a, r, g, b));
+    }
+
+    /** Replaces pixel values inside area with c. If area does not intersect bounds(),
+        call has no effect.
+
+        If the colorType() is kGray_8_SkColorType or kRGB_565_SkColorType, then alpha
+        is ignored; RGB is treated as opaque. If colorType() is kAlpha_8_SkColorType,
+        then RGB is ignored.
+
+        @param c     unpremultiplied color
+        @param area  rectangle to fill
+    */
+    void erase(SkColor c, const SkIRect& area) const;
+
+    /** Deprecated.
+    */
+    void eraseArea(const SkIRect& area, SkColor c) const {
+        this->erase(c, area);
+    }
+
+    /** Returns pixel at (x, y) as unpremultiplied color.
+        Returns black with alpha if SkColorType is kAlpha_8_SkColorType.
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined; and returns undefined values or may crash if
+        SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or
+        pixel address is nullptr.
+
+        SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the
+        conversion to unpremultiplied color; original pixel data may have additional
+        precision.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   pixel converted to unpremultiplied color
+    */
+    SkColor getColor(int x, int y) const {
+        return this->pixmap().getColor(x, y);
+    }
+
+    /** Look up the pixel at (x,y) and return its alpha component, normalized to [0..1].
+        This is roughly equivalent to SkGetColorA(getColor()), but can be more efficent
+        (and more precise if the pixels store more than 8 bits per component).
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   alpha converted to normalized float
+     */
+    float getAlphaf(int x, int y) const {
+        return this->pixmap().getAlphaf(x, y);
+    }
+
+    /** Returns pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y, or kUnknown_SkColorType,
+        trigger an assert() if built with SK_DEBUG defined. Returns nullptr if
+        SkColorType is kUnknown_SkColorType, or SkPixelRef is nullptr.
+
+        Performs a lookup of pixel size; for better performance, call
+        one of: getAddr8(), getAddr16(), or getAddr32().
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   generic pointer to pixel
+    */
+    void* getAddr(int x, int y) const;
+
+    /** Returns address at (x, y).
+
+        Input is not validated. Triggers an assert() if built with SK_DEBUG defined and:
+        - SkPixelRef is nullptr
+        - bytesPerPixel() is not four
+        - x is negative, or not less than width()
+        - y is negative, or not less than height()
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   unsigned 32-bit pointer to pixel at (x, y)
+    */
+    inline uint32_t* getAddr32(int x, int y) const;
+
+    /** Returns address at (x, y).
+
+        Input is not validated. Triggers an assert() if built with SK_DEBUG defined and:
+        - SkPixelRef is nullptr
+        - bytesPerPixel() is not two
+        - x is negative, or not less than width()
+        - y is negative, or not less than height()
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   unsigned 16-bit pointer to pixel at (x, y)
+    */
+    inline uint16_t* getAddr16(int x, int y) const;
+
+    /** Returns address at (x, y).
+
+        Input is not validated. Triggers an assert() if built with SK_DEBUG defined and:
+        - SkPixelRef is nullptr
+        - bytesPerPixel() is not one
+        - x is negative, or not less than width()
+        - y is negative, or not less than height()
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   unsigned 8-bit pointer to pixel at (x, y)
+    */
+    inline uint8_t* getAddr8(int x, int y) const;
+
+    /** Shares SkPixelRef with dst. Pixels are not copied; SkBitmap and dst point
+        to the same pixels; dst bounds() are set to the intersection of subset
+        and the original bounds().
+
+        subset may be larger than bounds(). Any area outside of bounds() is ignored.
+
+        Any contents of dst are discarded. isVolatile() setting is copied to dst.
+        dst is set to colorType(), alphaType(), and colorSpace().
+
+        Return false if:
+        - dst is nullptr
+        - SkPixelRef is nullptr
+        - subset does not intersect bounds()
+
+        @param dst     SkBitmap set to subset
+        @param subset  rectangle of pixels to reference
+        @return        true if dst is replaced by subset
+    */
+    bool extractSubset(SkBitmap* dst, const SkIRect& subset) const;
+
+    /** Copies a SkRect of pixels from SkBitmap to dstPixels. Copy starts at (srcX, srcY),
+        and does not exceed SkBitmap (width(), height()).
+
+        dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of
+        destination. dstRowBytes specifics the gap from one destination row to the next.
+        Returns true if pixels are copied. Returns false if:
+        - dstInfo has no address
+        - dstRowBytes is less than dstInfo.minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
+        If SkBitmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match.
+        If SkBitmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must
+        match. If SkBitmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false if width() or height() is zero or negative.
+        Returns false if abs(srcX) >= Bitmap width(), or if abs(srcY) >= Bitmap height().
+
+        @param dstInfo      destination width, height, SkColorType, SkAlphaType, SkColorSpace
+        @param dstPixels    destination pixel storage
+        @param dstRowBytes  destination row length
+        @param srcX         column index whose absolute value is less than width()
+        @param srcY         row index whose absolute value is less than height()
+        @return             true if pixels are copied to dstPixels
+    */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+                    int srcX, int srcY) const;
+
+    /** Copies a SkRect of pixels from SkBitmap to dst. Copy starts at (srcX, srcY), and
+        does not exceed SkBitmap (width(), height()).
+
+        dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
+        and row bytes of destination. dst.rowBytes() specifics the gap from one destination
+        row to the next. Returns true if pixels are copied. Returns false if:
+        - dst pixel storage equals nullptr
+        - dst.rowBytes is less than SkImageInfo::minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
+        If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
+        If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
+        match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false if width() or height() is zero or negative.
+        Returns false if abs(srcX) >= Bitmap width(), or if abs(srcY) >= Bitmap height().
+
+        @param dst   destination SkPixmap: SkImageInfo, pixels, row bytes
+        @param srcX  column index whose absolute value is less than width()
+        @param srcY  row index whose absolute value is less than height()
+        @return      true if pixels are copied to dst
+    */
+    bool readPixels(const SkPixmap& dst, int srcX, int srcY) const;
+
+    /** Copies a SkRect of pixels from SkBitmap to dst. Copy starts at (0, 0), and
+        does not exceed SkBitmap (width(), height()).
+
+        dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
+        and row bytes of destination. dst.rowBytes() specifics the gap from one destination
+        row to the next. Returns true if pixels are copied. Returns false if:
+        - dst pixel storage equals nullptr
+        - dst.rowBytes is less than SkImageInfo::minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
+        If SkBitmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
+        If SkBitmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
+        match. If SkBitmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        @param dst  destination SkPixmap: SkImageInfo, pixels, row bytes
+        @return     true if pixels are copied to dst
+    */
+    bool readPixels(const SkPixmap& dst) const {
+        return this->readPixels(dst, 0, 0);
+    }
+
+    /** Copies a SkRect of pixels from src. Copy starts at (dstX, dstY), and does not exceed
+        (src.width(), src.height()).
+
+        src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
+        and row bytes of source. src.rowBytes() specifics the gap from one source
+        row to the next. Returns true if pixels are copied. Returns false if:
+        - src pixel storage equals nullptr
+        - src.rowBytes is less than SkImageInfo::minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match.
+        If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match.
+        If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must
+        match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        dstX and dstY may be negative to copy only top or left of source. Returns
+        false if width() or height() is zero or negative.
+        Returns false if abs(dstX) >= Bitmap width(), or if abs(dstY) >= Bitmap height().
+
+        @param src   source SkPixmap: SkImageInfo, pixels, row bytes
+        @param dstX  column index whose absolute value is less than width()
+        @param dstY  row index whose absolute value is less than height()
+        @return      true if src pixels are copied to SkBitmap
+    */
+    bool writePixels(const SkPixmap& src, int dstX, int dstY);
+
+    /** Copies a SkRect of pixels from src. Copy starts at (0, 0), and does not exceed
+        (src.width(), src.height()).
+
+        src specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
+        and row bytes of source. src.rowBytes() specifics the gap from one source
+        row to the next. Returns true if pixels are copied. Returns false if:
+        - src pixel storage equals nullptr
+        - src.rowBytes is less than SkImageInfo::minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkBitmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; src SkColorType must match.
+        If SkBitmap colorType() is kGray_8_SkColorType, src SkColorSpace must match.
+        If SkBitmap alphaType() is kOpaque_SkAlphaType, src SkAlphaType must
+        match. If SkBitmap colorSpace() is nullptr, src SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        @param src  source SkPixmap: SkImageInfo, pixels, row bytes
+        @return     true if src pixels are copied to SkBitmap
+    */
+    bool writePixels(const SkPixmap& src) {
+        return this->writePixels(src, 0, 0);
+    }
+
+    /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to
+        or dst pixels cannot be allocated.
+
+        Uses HeapAllocator to reserve memory for dst SkPixelRef.
+
+        @param dst  holds SkPixelRef to fill with alpha layer
+        @return     true if alpha layer was constructed in dst SkPixelRef
+    */
+    bool extractAlpha(SkBitmap* dst) const {
+        return this->extractAlpha(dst, nullptr, nullptr, nullptr);
+    }
+
+    /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to
+        or dst pixels cannot be allocated.
+
+        If paint is not nullptr and contains SkMaskFilter, SkMaskFilter
+        generates mask alpha from SkBitmap. Uses HeapAllocator to reserve memory for dst
+        SkPixelRef. Sets offset to top-left position for dst for alignment with SkBitmap;
+        (0, 0) unless SkMaskFilter generates mask.
+
+        @param dst     holds SkPixelRef to fill with alpha layer
+        @param paint   holds optional SkMaskFilter; may be nullptr
+        @param offset  top-left position for dst; may be nullptr
+        @return        true if alpha layer was constructed in dst SkPixelRef
+    */
+    bool extractAlpha(SkBitmap* dst, const SkPaint* paint,
+                      SkIPoint* offset) const {
+        return this->extractAlpha(dst, paint, nullptr, offset);
+    }
+
+    /** Sets dst to alpha described by pixels. Returns false if dst cannot be written to
+        or dst pixels cannot be allocated.
+
+        If paint is not nullptr and contains SkMaskFilter, SkMaskFilter
+        generates mask alpha from SkBitmap. allocator may reference a custom allocation
+        class or be set to nullptr to use HeapAllocator. Sets offset to top-left
+        position for dst for alignment with SkBitmap; (0, 0) unless SkMaskFilter generates
+        mask.
+
+        @param dst        holds SkPixelRef to fill with alpha layer
+        @param paint      holds optional SkMaskFilter; may be nullptr
+        @param allocator  function to reserve memory for SkPixelRef; may be nullptr
+        @param offset     top-left position for dst; may be nullptr
+        @return           true if alpha layer was constructed in dst SkPixelRef
+    */
+    bool extractAlpha(SkBitmap* dst, const SkPaint* paint, Allocator* allocator,
+                      SkIPoint* offset) const;
+
+    /** Copies SkBitmap pixel address, row bytes, and SkImageInfo to pixmap, if address
+        is available, and returns true. If pixel address is not available, return
+        false and leave pixmap unchanged.
+
+        pixmap contents become invalid on any future change to SkBitmap.
+
+        @param pixmap  storage for pixel state if pixels are readable; otherwise, ignored
+        @return        true if SkBitmap has direct access to pixels
+    */
+    bool peekPixels(SkPixmap* pixmap) const;
+
+    /** Asserts if internal values are illegal or inconsistent. Only available if
+        SK_DEBUG is defined at compile time.
+    */
+    SkDEBUGCODE(void validate() const;)
+
+    /** \class SkBitmap::Allocator
+        Abstract subclass of HeapAllocator.
+    */
+    class Allocator : public SkRefCnt {
+    public:
+
+        /** Allocates the pixel memory for the bitmap, given its dimensions and
+            SkColorType. Returns true on success, where success means either setPixels()
+            or setPixelRef() was called.
+
+            @param bitmap  SkBitmap containing SkImageInfo as input, and SkPixelRef as output
+            @return        true if SkPixelRef was allocated
+        */
+        virtual bool allocPixelRef(SkBitmap* bitmap) = 0;
+    private:
+        typedef SkRefCnt INHERITED;
+    };
+
+    /** \class SkBitmap::HeapAllocator
+        Subclass of SkBitmap::Allocator that returns a SkPixelRef that allocates its pixel
+        memory from the heap. This is the default SkBitmap::Allocator invoked by
+        allocPixels().
+    */
+    class HeapAllocator : public Allocator {
+    public:
+
+        /** Allocates the pixel memory for the bitmap, given its dimensions and
+            SkColorType. Returns true on success, where success means either setPixels()
+            or setPixelRef() was called.
+
+            @param bitmap  SkBitmap containing SkImageInfo as input, and SkPixelRef as output
+            @return        true if pixels are allocated
+        */
+        bool allocPixelRef(SkBitmap* bitmap) override;
+    };
+
+private:
+    enum Flags {
+        kImageIsVolatile_Flag   = 0x02,
+    };
+
+    sk_sp<SkPixelRef>   fPixelRef;
+    SkPixmap            fPixmap;
+    uint8_t             fFlags;
+
+    friend class SkReadBuffer;        // unflatten
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+inline uint32_t* SkBitmap::getAddr32(int x, int y) const {
+    SkASSERT(fPixmap.addr());
+    return fPixmap.writable_addr32(x, y);
+}
+
+inline uint16_t* SkBitmap::getAddr16(int x, int y) const {
+    SkASSERT(fPixmap.addr());
+    return fPixmap.writable_addr16(x, y);
+}
+
+inline uint8_t* SkBitmap::getAddr8(int x, int y) const {
+    SkASSERT(fPixmap.addr());
+    return fPixmap.writable_addr8(x, y);
+}
+
+#endif

+ 75 - 0
skia/include/core/SkBlendMode.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkBlendMode.h and docs/SkBlendMode_Reference.bmh
+   on 2018-07-13 08:15:10. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkBlendMode_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkBlendMode_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkBlendMode.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkBlendMode_DEFINED
+#define SkBlendMode_DEFINED
+
+#include "SkTypes.h"
+
+enum class SkBlendMode {
+    kClear,                           //!< replaces destination with zero: fully transparent
+    kSrc,                             //!< replaces destination
+    kDst,                             //!< preserves destination
+    kSrcOver,                         //!< source over destination
+    kDstOver,                         //!< destination over source
+    kSrcIn,                           //!< source trimmed inside destination
+    kDstIn,                           //!< destination trimmed by source
+    kSrcOut,                          //!< source trimmed outside destination
+    kDstOut,                          //!< destination trimmed outside source
+    kSrcATop,                         //!< source inside destination blended with destination
+    kDstATop,                         //!< destination inside source blended with source
+    kXor,                             //!< each of source and destination trimmed outside the other
+    kPlus,                            //!< sum of colors
+    kModulate,                        //!< product of premultiplied colors; darkens destination
+    kScreen,                //!< multiply inverse of pixels, inverting result; brightens destination
+    kLastCoeffMode     = kScreen,     //!< last porter duff blend mode
+    kOverlay,                         //!< multiply or screen, depending on destination
+    kDarken,                          //!< darker of source and destination
+    kLighten,                         //!< lighter of source and destination
+    kColorDodge,                      //!< brighten destination to reflect source
+    kColorBurn,                       //!< darken destination to reflect source
+    kHardLight,                       //!< multiply or screen, depending on source
+    kSoftLight,                       //!< lighten or darken, depending on source
+    kDifference,                      //!< subtract darker from lighter with higher contrast
+    kExclusion,                       //!< subtract darker from lighter with lower contrast
+    kMultiply,                        //!< multiply source with destination, darkening image
+    kLastSeparableMode = kMultiply,   //!< last blend mode operating separately on components
+    kHue,                           //!< hue of source with saturation and luminosity of destination
+    kSaturation,                    //!< saturation of source with hue and luminosity of destination
+    kColor,                         //!< hue and saturation of source with luminosity of destination
+    kLuminosity,                    //!< luminosity of source with hue and saturation of destination
+    kLastMode          = kLuminosity, //!< last valid value
+};
+
+/** Returns name of blendMode as null-terminated C string.
+
+    @param blendMode  one of:
+                      SkBlendMode::kClear, SkBlendMode::kSrc, SkBlendMode::kDst,
+                      SkBlendMode::kSrcOver, SkBlendMode::kDstOver, SkBlendMode::kSrcIn,
+                      SkBlendMode::kDstIn, SkBlendMode::kSrcOut, SkBlendMode::kDstOut,
+                      SkBlendMode::kSrcATop, SkBlendMode::kDstATop, SkBlendMode::kXor,
+                      SkBlendMode::kPlus, SkBlendMode::kModulate, SkBlendMode::kScreen,
+                      SkBlendMode::kOverlay, SkBlendMode::kDarken, SkBlendMode::kLighten,
+                      SkBlendMode::kColorDodge, SkBlendMode::kColorBurn, SkBlendMode::kHardLight,
+                      SkBlendMode::kSoftLight, SkBlendMode::kDifference, SkBlendMode::kExclusion,
+                      SkBlendMode::kMultiply, SkBlendMode::kHue, SkBlendMode::kSaturation,
+                      SkBlendMode::kColor, SkBlendMode::kLuminosity
+    @return           C string
+*/
+SK_API const char* SkBlendMode_Name(SkBlendMode blendMode);
+
+#endif

+ 22 - 0
skia/include/core/SkBlurTypes.h

@@ -0,0 +1,22 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBlurTypes_DEFINED
+#define SkBlurTypes_DEFINED
+
+#include "SkTypes.h"
+
+enum SkBlurStyle : int {
+    kNormal_SkBlurStyle,  //!< fuzzy inside and outside
+    kSolid_SkBlurStyle,   //!< solid inside, fuzzy outside
+    kOuter_SkBlurStyle,   //!< nothing inside, fuzzy outside
+    kInner_SkBlurStyle,   //!< fuzzy inside, nothing outside
+
+    kLastEnum_SkBlurStyle = kInner_SkBlurStyle,
+};
+
+#endif

+ 2779 - 0
skia/include/core/SkCanvas.h

@@ -0,0 +1,2779 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkCanvas.h and docs/SkCanvas_Reference.bmh
+   on 2018-08-28 10:32:58. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkCanvas_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkCanvas_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkCanvas.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkCanvas_DEFINED
+#define SkCanvas_DEFINED
+
+#include "../private/SkMacros.h"
+#include "SkBlendMode.h"
+#include "SkClipOp.h"
+#include "SkDeque.h"
+#include "SkPaint.h"
+#include "SkRasterHandleAllocator.h"
+#include "SkSurfaceProps.h"
+#include "SkVertices.h"
+
+class GrContext;
+class GrRenderTargetContext;
+class SkAndroidFrameworkUtils;
+class SkBaseDevice;
+class SkBitmap;
+class SkData;
+class SkDraw;
+class SkDrawable;
+struct SkDrawShadowRec;
+class SkFont;
+class SkGlyphRunBuilder;
+class SkImage;
+class SkImageFilter;
+class SkMetaData;
+class SkPath;
+class SkPicture;
+class SkPixmap;
+class SkRegion;
+class SkRRect;
+struct SkRSXform;
+class SkSurface;
+class SkSurface_Base;
+class SkTextBlob;
+
+/** \class SkCanvas
+    SkCanvas provides an interface for drawing, and how the drawing is clipped and transformed.
+    SkCanvas contains a stack of SkMatrix and clip values.
+
+    SkCanvas and SkPaint together provide the state to draw into SkSurface or SkBaseDevice.
+    Each SkCanvas draw call transforms the geometry of the object by the concatenation of all
+    SkMatrix values in the stack. The transformed geometry is clipped by the intersection
+    of all of clip values in the stack. The SkCanvas draw calls use SkPaint to supply drawing
+    state such as color, SkTypeface, text size, stroke width, SkShader and so on.
+
+    To draw to a pixel-based destination, create raster surface or GPU surface.
+    Request SkCanvas from SkSurface to obtain the interface to draw.
+    SkCanvas generated by raster surface draws to memory visible to the CPU.
+    SkCanvas generated by GPU surface uses Vulkan or OpenGL to draw to the GPU.
+
+    To draw to a document, obtain SkCanvas from SVG canvas, document PDF, or SkPictureRecorder.
+    SkDocument based SkCanvas and other SkCanvas subclasses reference SkBaseDevice describing the
+    destination.
+
+    SkCanvas can be constructed to draw to SkBitmap without first creating raster surface.
+    This approach may be deprecated in the future.
+*/
+class SK_API SkCanvas {
+    enum PrivateSaveLayerFlags {
+        kDontClipToLayer_PrivateSaveLayerFlag   = 1U << 31,
+    };
+
+public:
+
+    /** Allocates raster SkCanvas that will draw directly into pixels.
+
+        SkCanvas is returned if all parameters are valid.
+        Valid parameters include:
+        info dimensions are zero or positive;
+        info contains SkColorType and SkAlphaType supported by raster surface;
+        pixels is not nullptr;
+        rowBytes is zero or large enough to contain info width pixels of SkColorType.
+
+        Pass zero for rowBytes to compute rowBytes from info width and size of pixel.
+        If rowBytes is greater than zero, it must be equal to or greater than
+        info width times bytes required for SkColorType.
+
+        Pixel buffer size should be info height times computed rowBytes.
+        Pixels are not initialized.
+        To access pixels after drawing, call flush() or peekPixels().
+
+        @param info      width, height, SkColorType, SkAlphaType, SkColorSpace, of raster surface;
+                         width, or height, or both, may be zero
+        @param pixels    pointer to destination pixels buffer
+        @param rowBytes  interval from one SkSurface row to the next, or zero
+        @param props     LCD striping orientation and setting for device independent fonts;
+                         may be nullptr
+        @return          SkCanvas if all parameters are valid; otherwise, nullptr
+    */
+    static std::unique_ptr<SkCanvas> MakeRasterDirect(const SkImageInfo& info, void* pixels,
+                                                      size_t rowBytes,
+                                                      const SkSurfaceProps* props = nullptr);
+
+    /** Allocates raster SkCanvas specified by inline image specification. Subsequent SkCanvas
+        calls draw into pixels.
+        SkColorType is set to kN32_SkColorType.
+        SkAlphaType is set to kPremul_SkAlphaType.
+        To access pixels after drawing, call flush() or peekPixels().
+
+        SkCanvas is returned if all parameters are valid.
+        Valid parameters include:
+        width and height are zero or positive;
+        pixels is not nullptr;
+        rowBytes is zero or large enough to contain width pixels of kN32_SkColorType.
+
+        Pass zero for rowBytes to compute rowBytes from width and size of pixel.
+        If rowBytes is greater than zero, it must be equal to or greater than
+        width times bytes required for SkColorType.
+
+        Pixel buffer size should be height times rowBytes.
+
+        @param width     pixel column count on raster surface created; must be zero or greater
+        @param height    pixel row count on raster surface created; must be zero or greater
+        @param pixels    pointer to destination pixels buffer; buffer size should be height
+                         times rowBytes
+        @param rowBytes  interval from one SkSurface row to the next, or zero
+        @return          SkCanvas if all parameters are valid; otherwise, nullptr
+    */
+    static std::unique_ptr<SkCanvas> MakeRasterDirectN32(int width, int height, SkPMColor* pixels,
+                                                         size_t rowBytes) {
+        return MakeRasterDirect(SkImageInfo::MakeN32Premul(width, height), pixels, rowBytes);
+    }
+
+    /** Creates an empty SkCanvas with no backing device or pixels, with
+        a width and height of zero.
+
+        @return  empty SkCanvas
+    */
+    SkCanvas();
+
+    /** Creates SkCanvas of the specified dimensions without a SkSurface.
+        Used by subclasses with custom implementations for draw member functions.
+
+        If props equals nullptr, SkSurfaceProps are created with
+        SkSurfaceProps::InitType settings, which choose the pixel striping
+        direction and order. Since a platform may dynamically change its direction when
+        the device is rotated, and since a platform may have multiple monitors with
+        different characteristics, it is best not to rely on this legacy behavior.
+
+        @param width   zero or greater
+        @param height  zero or greater
+        @param props   LCD striping orientation and setting for device independent fonts;
+                       may be nullptr
+        @return        SkCanvas placeholder with dimensions
+    */
+    SkCanvas(int width, int height, const SkSurfaceProps* props = nullptr);
+
+    /** Deprecated.
+    */
+    explicit SkCanvas(sk_sp<SkBaseDevice> device);
+
+    /** Constructs a canvas that draws into bitmap.
+        Sets SkSurfaceProps::kLegacyFontHost_InitType in constructed SkSurface.
+
+        SkBitmap is copied so that subsequently editing bitmap will not affect
+        constructed SkCanvas.
+
+        May be deprecated in the future.
+
+        @param bitmap  width, height, SkColorType, SkAlphaType, and pixel
+                       storage of raster surface
+        @return        SkCanvas that can be used to draw into bitmap
+    */
+    explicit SkCanvas(const SkBitmap& bitmap);
+
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    /** Private.
+     */
+    enum class ColorBehavior {
+        kLegacy, //!< placeholder
+    };
+
+    /** Private. For use by Android framework only.
+
+        @param bitmap    specifies a bitmap for the canvas to draw into
+        @param behavior  specializes this constructor; value is unused
+        @return          SkCanvas that can be used to draw into bitmap
+    */
+    SkCanvas(const SkBitmap& bitmap, ColorBehavior behavior);
+#endif
+
+    /** Constructs a canvas that draws into bitmap.
+        Use props to match the device characteristics, like LCD striping.
+
+        bitmap is copied so that subsequently editing bitmap will not affect
+        constructed SkCanvas.
+
+        @param bitmap  width, height, SkColorType, SkAlphaType,
+                       and pixel storage of raster surface
+        @param props   order and orientation of RGB striping; and whether to use
+                       device independent fonts
+        @return        SkCanvas that can be used to draw into bitmap
+    */
+    SkCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props);
+
+    /** Draws saved layers, if any.
+        Frees up resources used by SkCanvas.
+    */
+    virtual ~SkCanvas();
+
+    /** Returns storage to associate additional data with the canvas.
+        The storage is freed when SkCanvas is deleted.
+
+        @return  storage that can be read from and written to
+    */
+    SkMetaData& getMetaData();
+
+    /** Returns SkImageInfo for SkCanvas. If SkCanvas is not associated with raster surface or
+        GPU surface, returned SkColorType is set to kUnknown_SkColorType.
+
+        @return  dimensions and SkColorType of SkCanvas
+    */
+    SkImageInfo imageInfo() const;
+
+    /** Copies SkSurfaceProps, if SkCanvas is associated with raster surface or
+        GPU surface, and returns true. Otherwise, returns false and leave props unchanged.
+
+        @param props  storage for writable SkSurfaceProps
+        @return       true if SkSurfaceProps was copied
+    */
+    bool getProps(SkSurfaceProps* props) const;
+
+    /** Triggers the immediate execution of all pending draw operations.
+        If SkCanvas is associated with GPU surface, resolves all pending GPU operations.
+        If SkCanvas is associated with raster surface, has no effect; raster draw
+        operations are never deferred.
+    */
+    void flush();
+
+    /** Gets the size of the base or root layer in global canvas coordinates. The
+        origin of the base layer is always (0,0). The area available for drawing may be
+        smaller (due to clipping or saveLayer).
+
+        @return  integral width and height of base layer
+    */
+    virtual SkISize getBaseLayerSize() const;
+
+    /** Creates SkSurface matching info and props, and associates it with SkCanvas.
+        Returns nullptr if no match found.
+
+        If props is nullptr, matches SkSurfaceProps in SkCanvas. If props is nullptr and SkCanvas
+        does not have SkSurfaceProps, creates SkSurface with default SkSurfaceProps.
+
+        @param info   width, height, SkColorType, SkAlphaType, and SkColorSpace
+        @param props  SkSurfaceProps to match; may be nullptr to match SkCanvas
+        @return       SkSurface matching info and props, or nullptr if no match is available
+    */
+    sk_sp<SkSurface> makeSurface(const SkImageInfo& info, const SkSurfaceProps* props = nullptr);
+
+    /** Returns GPU context of the GPU surface associated with SkCanvas.
+
+        @return  GPU context, if available; nullptr otherwise
+    */
+    virtual GrContext* getGrContext();
+
+    /** Returns the pixel base address, SkImageInfo, rowBytes, and origin if the pixels
+        can be read directly. The returned address is only valid
+        while SkCanvas is in scope and unchanged. Any SkCanvas call or SkSurface call
+        may invalidate the returned address and other returned values.
+
+        If pixels are inaccessible, info, rowBytes, and origin are unchanged.
+
+        @param info      storage for writable pixels' SkImageInfo; may be nullptr
+        @param rowBytes  storage for writable pixels' row bytes; may be nullptr
+        @param origin    storage for SkCanvas top layer origin, its top-left corner;
+                         may be nullptr
+        @return          address of pixels, or nullptr if inaccessible
+    */
+    void* accessTopLayerPixels(SkImageInfo* info, size_t* rowBytes, SkIPoint* origin = nullptr);
+
+    /** Returns custom context that tracks the SkMatrix and clip.
+
+        Use SkRasterHandleAllocator to blend Skia drawing with custom drawing, typically performed
+        by the host platform user interface. The custom context returned is generated by
+        SkRasterHandleAllocator::MakeCanvas, which creates a custom canvas with raster storage for
+        the drawing destination.
+
+        @return  context of custom allocation
+    */
+    SkRasterHandleAllocator::Handle accessTopRasterHandle() const;
+
+    /** Returns true if SkCanvas has direct access to its pixels.
+
+        Pixels are readable when SkBaseDevice is raster. Pixels are not readable when SkCanvas
+        is returned from GPU surface, returned by SkDocument::beginPage, returned by
+        SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility class
+        like SkDebugCanvas.
+
+        pixmap is valid only while SkCanvas is in scope and unchanged. Any
+        SkCanvas or SkSurface call may invalidate the pixmap values.
+
+        @param pixmap  storage for pixel state if pixels are readable; otherwise, ignored
+        @return        true if SkCanvas has direct access to pixels
+    */
+    bool peekPixels(SkPixmap* pixmap);
+
+    /** Copies SkRect of pixels from SkCanvas into dstPixels. SkMatrix and clip are
+        ignored.
+
+        Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
+        Destination SkRect corners are (0, 0) and (dstInfo.width(), dstInfo.height()).
+        Copies each readable pixel intersecting both rectangles, without scaling,
+        converting to dstInfo.colorType() and dstInfo.alphaType() if required.
+
+        Pixels are readable when SkBaseDevice is raster, or backed by a GPU.
+        Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
+        returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility
+        class like SkDebugCanvas.
+
+        The destination pixel storage must be allocated by the caller.
+
+        Pixel values are converted only if SkColorType and SkAlphaType
+        do not match. Only pixels within both source and destination rectangles
+        are copied. dstPixels contents outside SkRect intersection are unchanged.
+
+        Pass negative values for srcX or srcY to offset pixels across or down destination.
+
+        Does not copy, and returns false if:
+        - Source and destination rectangles do not intersect.
+        - SkCanvas pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType().
+        - SkCanvas pixels are not readable; for instance, SkCanvas is document-based.
+        - dstRowBytes is too small to contain one row of pixels.
+
+        @param dstInfo      width, height, SkColorType, and SkAlphaType of dstPixels
+        @param dstPixels    storage for pixels; dstInfo.height() times dstRowBytes, or larger
+        @param dstRowBytes  size of one destination row; dstInfo.width() times pixel size, or larger
+        @param srcX         offset into readable pixels on x-axis; may be negative
+        @param srcY         offset into readable pixels on y-axis; may be negative
+        @return             true if pixels were copied
+    */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+                    int srcX, int srcY);
+
+    /** Copies SkRect of pixels from SkCanvas into pixmap. SkMatrix and clip are
+        ignored.
+
+        Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
+        Destination SkRect corners are (0, 0) and (pixmap.width(), pixmap.height()).
+        Copies each readable pixel intersecting both rectangles, without scaling,
+        converting to pixmap.colorType() and pixmap.alphaType() if required.
+
+        Pixels are readable when SkBaseDevice is raster, or backed by a GPU.
+        Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
+        returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility
+        class like SkDebugCanvas.
+
+        Caller must allocate pixel storage in pixmap if needed.
+
+        Pixel values are converted only if SkColorType and SkAlphaType
+        do not match. Only pixels within both source and destination SkRect
+        are copied. pixmap pixels contents outside SkRect intersection are unchanged.
+
+        Pass negative values for srcX or srcY to offset pixels across or down pixmap.
+
+        Does not copy, and returns false if:
+        - Source and destination rectangles do not intersect.
+        - SkCanvas pixels could not be converted to pixmap.colorType() or pixmap.alphaType().
+        - SkCanvas pixels are not readable; for instance, SkCanvas is document-based.
+        - SkPixmap pixels could not be allocated.
+        - pixmap.rowBytes() is too small to contain one row of pixels.
+
+        @param pixmap  storage for pixels copied from SkCanvas
+        @param srcX    offset into readable pixels on x-axis; may be negative
+        @param srcY    offset into readable pixels on y-axis; may be negative
+        @return        true if pixels were copied
+    */
+    bool readPixels(const SkPixmap& pixmap, int srcX, int srcY);
+
+    /** Copies SkRect of pixels from SkCanvas into bitmap. SkMatrix and clip are
+        ignored.
+
+        Source SkRect corners are (srcX, srcY) and (imageInfo().width(), imageInfo().height()).
+        Destination SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()).
+        Copies each readable pixel intersecting both rectangles, without scaling,
+        converting to bitmap.colorType() and bitmap.alphaType() if required.
+
+        Pixels are readable when SkBaseDevice is raster, or backed by a GPU.
+        Pixels are not readable when SkCanvas is returned by SkDocument::beginPage,
+        returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility
+        class like SkDebugCanvas.
+
+        Caller must allocate pixel storage in bitmap if needed.
+
+        SkBitmap values are converted only if SkColorType and SkAlphaType
+        do not match. Only pixels within both source and destination rectangles
+        are copied. SkBitmap pixels outside SkRect intersection are unchanged.
+
+        Pass negative values for srcX or srcY to offset pixels across or down bitmap.
+
+        Does not copy, and returns false if:
+        - Source and destination rectangles do not intersect.
+        - SkCanvas pixels could not be converted to bitmap.colorType() or bitmap.alphaType().
+        - SkCanvas pixels are not readable; for instance, SkCanvas is document-based.
+        - bitmap pixels could not be allocated.
+        - bitmap.rowBytes() is too small to contain one row of pixels.
+
+        @param bitmap  storage for pixels copied from SkCanvas
+        @param srcX    offset into readable pixels on x-axis; may be negative
+        @param srcY    offset into readable pixels on y-axis; may be negative
+        @return        true if pixels were copied
+    */
+    bool readPixels(const SkBitmap& bitmap, int srcX, int srcY);
+
+    /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored.
+        Source SkRect corners are (0, 0) and (info.width(), info.height()).
+        Destination SkRect corners are (x, y) and
+        (imageInfo().width(), imageInfo().height()).
+
+        Copies each readable pixel intersecting both rectangles, without scaling,
+        converting to imageInfo().colorType() and imageInfo().alphaType() if required.
+
+        Pixels are writable when SkBaseDevice is raster, or backed by a GPU.
+        Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
+        returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility
+        class like SkDebugCanvas.
+
+        Pixel values are converted only if SkColorType and SkAlphaType
+        do not match. Only pixels within both source and destination rectangles
+        are copied. SkCanvas pixels outside SkRect intersection are unchanged.
+
+        Pass negative values for x or y to offset pixels to the left or
+        above SkCanvas pixels.
+
+        Does not copy, and returns false if:
+        - Source and destination rectangles do not intersect.
+        - pixels could not be converted to SkCanvas imageInfo().colorType() or
+        imageInfo().alphaType().
+        - SkCanvas pixels are not writable; for instance, SkCanvas is document-based.
+        - rowBytes is too small to contain one row of pixels.
+
+        @param info      width, height, SkColorType, and SkAlphaType of pixels
+        @param pixels    pixels to copy, of size info.height() times rowBytes, or larger
+        @param rowBytes  size of one row of pixels; info.width() times pixel size, or larger
+        @param x         offset into SkCanvas writable pixels on x-axis; may be negative
+        @param y         offset into SkCanvas writable pixels on y-axis; may be negative
+        @return          true if pixels were written to SkCanvas
+    */
+    bool writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y);
+
+    /** Copies SkRect from pixels to SkCanvas. SkMatrix and clip are ignored.
+        Source SkRect corners are (0, 0) and (bitmap.width(), bitmap.height()).
+
+        Destination SkRect corners are (x, y) and
+        (imageInfo().width(), imageInfo().height()).
+
+        Copies each readable pixel intersecting both rectangles, without scaling,
+        converting to imageInfo().colorType() and imageInfo().alphaType() if required.
+
+        Pixels are writable when SkBaseDevice is raster, or backed by a GPU.
+        Pixels are not writable when SkCanvas is returned by SkDocument::beginPage,
+        returned by SkPictureRecorder::beginRecording, or SkCanvas is the base of a utility
+        class like SkDebugCanvas.
+
+        Pixel values are converted only if SkColorType and SkAlphaType
+        do not match. Only pixels within both source and destination rectangles
+        are copied. SkCanvas pixels outside SkRect intersection are unchanged.
+
+        Pass negative values for x or y to offset pixels to the left or
+        above SkCanvas pixels.
+
+        Does not copy, and returns false if:
+        - Source and destination rectangles do not intersect.
+        - bitmap does not have allocated pixels.
+        - bitmap pixels could not be converted to SkCanvas imageInfo().colorType() or
+        imageInfo().alphaType().
+        - SkCanvas pixels are not writable; for instance, SkCanvas is document based.
+        - bitmap pixels are inaccessible; for instance, bitmap wraps a texture.
+
+        @param bitmap  contains pixels copied to SkCanvas
+        @param x       offset into SkCanvas writable pixels on x-axis; may be negative
+        @param y       offset into SkCanvas writable pixels on y-axis; may be negative
+        @return        true if pixels were written to SkCanvas
+    */
+    bool writePixels(const SkBitmap& bitmap, int x, int y);
+
+    /** Saves SkMatrix and clip.
+        Calling restore() discards changes to SkMatrix and clip,
+        restoring the SkMatrix and clip to their state when save() was called.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(), setMatrix(),
+        and resetMatrix(). Clip may be changed by clipRect(), clipRRect(), clipPath(), clipRegion().
+
+        Saved SkCanvas state is put on a stack; multiple calls to save() should be balance
+        by an equal number of calls to restore().
+
+        Call restoreToCount() with result to restore this and subsequent saves.
+
+        @return  depth of saved stack
+    */
+    int save();
+
+    /** Saves SkMatrix and clip, and allocates a SkBitmap for subsequent drawing.
+        Calling restore() discards changes to SkMatrix and clip, and draws the SkBitmap.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(),
+        setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(),
+        clipPath(), clipRegion().
+
+        SkRect bounds suggests but does not define the SkBitmap size. To clip drawing to
+        a specific rectangle, use clipRect().
+
+        Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and
+        SkBlendMode when restore() is called.
+
+        Call restoreToCount() with returned value to restore this and subsequent saves.
+
+        @param bounds  hint to limit the size of the layer; may be nullptr
+        @param paint   graphics state for layer; may be nullptr
+        @return        depth of saved stack
+    */
+    int saveLayer(const SkRect* bounds, const SkPaint* paint);
+
+    /** Saves SkMatrix and clip, and allocates a SkBitmap for subsequent drawing.
+        Calling restore() discards changes to SkMatrix and clip, and draws the SkBitmap.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(),
+        setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(),
+        clipPath(), clipRegion().
+
+        SkRect bounds suggests but does not define the layer size. To clip drawing to
+        a specific rectangle, use clipRect().
+
+        Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and
+        SkBlendMode when restore() is called.
+
+        Call restoreToCount() with returned value to restore this and subsequent saves.
+
+        @param bounds  hint to limit the size of layer; may be nullptr
+        @param paint   graphics state for layer; may be nullptr
+        @return        depth of saved stack
+    */
+    int saveLayer(const SkRect& bounds, const SkPaint* paint) {
+        return this->saveLayer(&bounds, paint);
+    }
+
+    /** Saves SkMatrix and clip, and allocates a SkBitmap for subsequent drawing.
+        LCD text is preserved when the layer is drawn to the prior layer.
+
+        Calling restore() discards changes to SkMatrix and clip, and draws layer.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(),
+        setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(),
+        clipPath(), clipRegion().
+
+        SkRect bounds suggests but does not define the layer size. To clip drawing to
+        a specific rectangle, use clipRect().
+
+        Optional SkPaint paint applies alpha, SkColorFilter, SkImageFilter, and
+        SkBlendMode when restore() is called.
+
+        Call restoreToCount() with returned value to restore this and subsequent saves.
+
+        Draw text on an opaque background so that LCD text blends correctly with the
+        prior layer. LCD text drawn on a background with transparency may result in
+        incorrect blending.
+
+        @param bounds  hint to limit the size of layer; may be nullptr
+        @param paint   graphics state for layer; may be nullptr
+        @return        depth of saved stack
+    */
+    int saveLayerPreserveLCDTextRequests(const SkRect* bounds, const SkPaint* paint);
+
+    /** Saves SkMatrix and clip, and allocates SkBitmap for subsequent drawing.
+
+        Calling restore() discards changes to SkMatrix and clip,
+        and blends layer with alpha opacity onto prior layer.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(),
+        setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(),
+        clipPath(), clipRegion().
+
+        SkRect bounds suggests but does not define layer size. To clip drawing to
+        a specific rectangle, use clipRect().
+
+        alpha of zero is fully transparent, 255 is fully opaque.
+
+        Call restoreToCount() with returned value to restore this and subsequent saves.
+
+        @param bounds  hint to limit the size of layer; may be nullptr
+        @param alpha   opacity of layer
+        @return        depth of saved stack
+    */
+    int saveLayerAlpha(const SkRect* bounds, U8CPU alpha);
+
+    /** \enum SkCanvas::SaveLayerFlagsSet
+        SaveLayerFlags provides options that may be used in any combination in SaveLayerRec,
+        defining how layer allocated by saveLayer() operates. It may be set to zero,
+        kPreserveLCDText_SaveLayerFlag, kInitWithPrevious_SaveLayerFlag, or both flags.
+    */
+    enum SaveLayerFlagsSet {
+        kPreserveLCDText_SaveLayerFlag  = 1 << 1, //!< creates layer for LCD text
+        kInitWithPrevious_SaveLayerFlag = 1 << 2, //!< initializes with previous contents
+        kMaskAgainstCoverage_EXPERIMENTAL_DONT_USE_SaveLayerFlag =
+                                          1 << 3, //!< experimental: do not use
+
+#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
+        kDontClipToLayer_Legacy_SaveLayerFlag =
+           kDontClipToLayer_PrivateSaveLayerFlag, //!< deprecated
+#endif
+    };
+
+    typedef uint32_t SaveLayerFlags;
+
+    /** \struct SkCanvas::SaveLayerRec
+        SaveLayerRec contains the state used to create the layer.
+    */
+    struct SaveLayerRec {
+
+        /** Sets fBounds, fPaint, and fBackdrop to nullptr. Clears fSaveLayerFlags.
+
+            @return  empty SaveLayerRec
+        */
+        SaveLayerRec() {}
+
+        /** Sets fBounds, fPaint, and fSaveLayerFlags; sets fBackdrop to nullptr.
+
+            @param bounds          layer dimensions; may be nullptr
+            @param paint           applied to layer when overlaying prior layer; may be nullptr
+            @param saveLayerFlags  SaveLayerRec options to modify layer
+            @return                SaveLayerRec with empty fBackdrop
+        */
+        SaveLayerRec(const SkRect* bounds, const SkPaint* paint, SaveLayerFlags saveLayerFlags = 0)
+            : fBounds(bounds)
+            , fPaint(paint)
+            , fSaveLayerFlags(saveLayerFlags)
+        {}
+
+        /** Sets fBounds, fPaint, fBackdrop, and fSaveLayerFlags.
+
+            @param bounds          layer dimensions; may be nullptr
+            @param paint           applied to layer when overlaying prior layer;
+                                   may be nullptr
+            @param backdrop        prior layer copied with SkImageFilter; may be nullptr
+            @param saveLayerFlags  SaveLayerRec options to modify layer
+            @return                SaveLayerRec fully specified
+        */
+        SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
+                     SaveLayerFlags saveLayerFlags)
+            : fBounds(bounds)
+            , fPaint(paint)
+            , fBackdrop(backdrop)
+            , fSaveLayerFlags(saveLayerFlags)
+        {}
+
+        /** Experimental. Not ready for general use.
+            Sets fBounds, fPaint, fBackdrop, fClipMask, fClipMatrix, and fSaveLayerFlags.
+            clipMatrix uses alpha channel of image, transformed by clipMatrix, to clip
+            layer when drawn to SkCanvas.
+
+            Implementation is not complete; has no effect if SkBaseDevice is GPU-backed.
+
+            @param bounds          layer dimensions; may be nullptr
+            @param paint           graphics state applied to layer when overlaying prior
+                                   layer; may be nullptr
+            @param backdrop        prior layer copied with SkImageFilter;
+                                   may be nullptr
+            @param clipMask        clip applied to layer; may be nullptr
+            @param clipMatrix      matrix applied to clipMask; may be nullptr to use
+                                   identity matrix
+            @param saveLayerFlags  SaveLayerRec options to modify layer
+            @return                SaveLayerRec fully specified
+        */
+        SaveLayerRec(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
+                     const SkImage* clipMask, const SkMatrix* clipMatrix,
+                     SaveLayerFlags saveLayerFlags)
+            : fBounds(bounds)
+            , fPaint(paint)
+            , fBackdrop(backdrop)
+            , fClipMask(clipMask)
+            , fClipMatrix(clipMatrix)
+            , fSaveLayerFlags(saveLayerFlags)
+        {}
+
+        /** hints at layer size limit */
+        const SkRect*        fBounds         = nullptr;
+
+        /** modifies overlay */
+        const SkPaint*       fPaint          = nullptr;
+
+        /** applies SkImageFilter to prior layer */
+        const SkImageFilter* fBackdrop       = nullptr;
+
+        /** clips layer with mask alpha */
+        const SkImage*       fClipMask       = nullptr;
+
+        /** transforms mask alpha used to clip */
+        const SkMatrix*      fClipMatrix     = nullptr;
+
+        /** preserves LCD text, creates with prior layer contents */
+        SaveLayerFlags       fSaveLayerFlags = 0;
+    };
+
+    /** Saves SkMatrix and clip, and allocates SkBitmap for subsequent drawing.
+
+        Calling restore() discards changes to SkMatrix and clip,
+        and blends SkBitmap with alpha opacity onto the prior layer.
+
+        SkMatrix may be changed by translate(), scale(), rotate(), skew(), concat(),
+        setMatrix(), and resetMatrix(). Clip may be changed by clipRect(), clipRRect(),
+        clipPath(), clipRegion().
+
+        SaveLayerRec contains the state used to create the layer.
+
+        Call restoreToCount() with returned value to restore this and subsequent saves.
+
+        @param layerRec  layer state
+        @return          depth of save state stack
+    */
+    int saveLayer(const SaveLayerRec& layerRec);
+
+    /** Removes changes to SkMatrix and clip since SkCanvas state was
+        last saved. The state is removed from the stack.
+
+        Does nothing if the stack is empty.
+    */
+    void restore();
+
+    /** Returns the number of saved states, each containing: SkMatrix and clip.
+        Equals the number of save() calls less the number of restore() calls plus one.
+        The save count of a new canvas is one.
+
+        @return  depth of save state stack
+    */
+    int getSaveCount() const;
+
+    /** Restores state to SkMatrix and clip values when save(), saveLayer(),
+        saveLayerPreserveLCDTextRequests(), or saveLayerAlpha() returned saveCount.
+
+        Does nothing if saveCount is greater than state stack count.
+        Restores state to initial values if saveCount is less than or equal to one.
+
+        @param saveCount  depth of state stack to restore
+    */
+    void restoreToCount(int saveCount);
+
+    /** Translates SkMatrix by dx along the x-axis and dy along the y-axis.
+
+        Mathematically, replaces SkMatrix with a translation matrix
+        premultiplied with SkMatrix.
+
+        This has the effect of moving the drawing by (dx, dy) before transforming
+        the result with SkMatrix.
+
+        @param dx  distance to translate on x-axis
+        @param dy  distance to translate on y-axis
+    */
+    void translate(SkScalar dx, SkScalar dy);
+
+    /** Scales SkMatrix by sx on the x-axis and sy on the y-axis.
+
+        Mathematically, replaces SkMatrix with a scale matrix
+        premultiplied with SkMatrix.
+
+        This has the effect of scaling the drawing by (sx, sy) before transforming
+        the result with SkMatrix.
+
+        @param sx  amount to scale on x-axis
+        @param sy  amount to scale on y-axis
+    */
+    void scale(SkScalar sx, SkScalar sy);
+
+    /** Rotates SkMatrix by degrees. Positive degrees rotates clockwise.
+
+        Mathematically, replaces SkMatrix with a rotation matrix
+        premultiplied with SkMatrix.
+
+        This has the effect of rotating the drawing by degrees before transforming
+        the result with SkMatrix.
+
+        @param degrees  amount to rotate, in degrees
+    */
+    void rotate(SkScalar degrees);
+
+    /** Rotates SkMatrix by degrees about a point at (px, py). Positive degrees rotates
+        clockwise.
+
+        Mathematically, constructs a rotation matrix; premultiplies the rotation matrix by
+        a translation matrix; then replaces SkMatrix with the resulting matrix
+        premultiplied with SkMatrix.
+
+        This has the effect of rotating the drawing about a given point before
+        transforming the result with SkMatrix.
+
+        @param degrees  amount to rotate, in degrees
+        @param px       x-axis value of the point to rotate about
+        @param py       y-axis value of the point to rotate about
+    */
+    void rotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+    /** Skews SkMatrix by sx on the x-axis and sy on the y-axis. A positive value of sx
+        skews the drawing right as y-axis values increase; a positive value of sy skews
+        the drawing down as x-axis values increase.
+
+        Mathematically, replaces SkMatrix with a skew matrix premultiplied with SkMatrix.
+
+        This has the effect of skewing the drawing by (sx, sy) before transforming
+        the result with SkMatrix.
+
+        @param sx  amount to skew on x-axis
+        @param sy  amount to skew on y-axis
+    */
+    void skew(SkScalar sx, SkScalar sy);
+
+    /** Replaces SkMatrix with matrix premultiplied with existing SkMatrix.
+
+        This has the effect of transforming the drawn geometry by matrix, before
+        transforming the result with existing SkMatrix.
+
+        @param matrix  matrix to premultiply with existing SkMatrix
+    */
+    void concat(const SkMatrix& matrix);
+
+    /** Replaces SkMatrix with matrix.
+        Unlike concat(), any prior matrix state is overwritten.
+
+        @param matrix  matrix to copy, replacing existing SkMatrix
+    */
+    void setMatrix(const SkMatrix& matrix);
+
+    /** Sets SkMatrix to the identity matrix.
+        Any prior matrix state is overwritten.
+    */
+    void resetMatrix();
+
+    /** Replaces clip with the intersection or difference of clip and rect,
+        with an aliased or anti-aliased clip edge. rect is transformed by SkMatrix
+        before it is combined with clip.
+
+        @param rect         SkRect to combine with clip
+        @param op           SkClipOp to apply to clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipRect(const SkRect& rect, SkClipOp op, bool doAntiAlias);
+
+    /** Replaces clip with the intersection or difference of clip and rect.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        rect is transformed by SkMatrix before it is combined with clip.
+
+        @param rect  SkRect to combine with clip
+        @param op    SkClipOp to apply to clip
+    */
+    void clipRect(const SkRect& rect, SkClipOp op) {
+        this->clipRect(rect, op, false);
+    }
+
+    /** Replaces clip with the intersection of clip and rect.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        rect is transformed by SkMatrix
+        before it is combined with clip.
+
+        @param rect         SkRect to combine with clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipRect(const SkRect& rect, bool doAntiAlias = false) {
+        this->clipRect(rect, SkClipOp::kIntersect, doAntiAlias);
+    }
+
+    /** Sets the maximum clip rectangle, which can be set by clipRect(), clipRRect() and
+        clipPath() and intersect the current clip with the specified rect.
+        The maximum clip affects only future clipping operations; it is not retroactive.
+        The clip restriction is not recorded in pictures.
+
+        Pass an empty rect to disable maximum clip.
+        This private API is for use by Android framework only.
+
+        @param rect  maximum allowed clip in device coordinates
+    */
+    void androidFramework_setDeviceClipRestriction(const SkIRect& rect);
+
+    /** Replaces clip with the intersection or difference of clip and rrect,
+        with an aliased or anti-aliased clip edge.
+        rrect is transformed by SkMatrix
+        before it is combined with clip.
+
+        @param rrect        SkRRect to combine with clip
+        @param op           SkClipOp to apply to clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipRRect(const SkRRect& rrect, SkClipOp op, bool doAntiAlias);
+
+    /** Replaces clip with the intersection or difference of clip and rrect.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        rrect is transformed by SkMatrix before it is combined with clip.
+
+        @param rrect  SkRRect to combine with clip
+        @param op     SkClipOp to apply to clip
+    */
+    void clipRRect(const SkRRect& rrect, SkClipOp op) {
+        this->clipRRect(rrect, op, false);
+    }
+
+    /** Replaces clip with the intersection of clip and rrect,
+        with an aliased or anti-aliased clip edge.
+        rrect is transformed by SkMatrix before it is combined with clip.
+
+        @param rrect        SkRRect to combine with clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) {
+        this->clipRRect(rrect, SkClipOp::kIntersect, doAntiAlias);
+    }
+
+    /** Replaces clip with the intersection or difference of clip and path,
+        with an aliased or anti-aliased clip edge. SkPath::FillType determines if path
+        describes the area inside or outside its contours; and if path contour overlaps
+        itself or another path contour, whether the overlaps form part of the area.
+        path is transformed by SkMatrix before it is combined with clip.
+
+        @param path         SkPath to combine with clip
+        @param op           SkClipOp to apply to clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipPath(const SkPath& path, SkClipOp op, bool doAntiAlias);
+
+    /** Replaces clip with the intersection or difference of clip and path.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        SkPath::FillType determines if path
+        describes the area inside or outside its contours; and if path contour overlaps
+        itself or another path contour, whether the overlaps form part of the area.
+        path is transformed by SkMatrix
+        before it is combined with clip.
+
+        @param path  SkPath to combine with clip
+        @param op    SkClipOp to apply to clip
+    */
+    void clipPath(const SkPath& path, SkClipOp op) {
+        this->clipPath(path, op, false);
+    }
+
+    /** Replaces clip with the intersection of clip and path.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        SkPath::FillType determines if path
+        describes the area inside or outside its contours; and if path contour overlaps
+        itself or another path contour, whether the overlaps form part of the area.
+        path is transformed by SkMatrix before it is combined with clip.
+
+        @param path         SkPath to combine with clip
+        @param doAntiAlias  true if clip is to be anti-aliased
+    */
+    void clipPath(const SkPath& path, bool doAntiAlias = false) {
+        this->clipPath(path, SkClipOp::kIntersect, doAntiAlias);
+    }
+
+    /** Experimental. For testing only.
+        Set to simplify clip stack using PathOps.
+    */
+    void setAllowSimplifyClip(bool allow) {
+        fAllowSimplifyClip = allow;
+    }
+
+    /** Replaces clip with the intersection or difference of clip and SkRegion deviceRgn.
+        Resulting clip is aliased; pixels are fully contained by the clip.
+        deviceRgn is unaffected by SkMatrix.
+
+        @param deviceRgn  SkRegion to combine with clip
+        @param op         SkClipOp to apply to clip
+    */
+    void clipRegion(const SkRegion& deviceRgn, SkClipOp op = SkClipOp::kIntersect);
+
+    /** Returns true if SkRect rect, transformed by SkMatrix, can be quickly determined to be
+        outside of clip. May return false even though rect is outside of clip.
+
+        Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
+
+        @param rect  SkRect to compare with clip
+        @return      true if rect, transformed by SkMatrix, does not intersect clip
+    */
+    bool quickReject(const SkRect& rect) const;
+
+    /** Returns true if path, transformed by SkMatrix, can be quickly determined to be
+        outside of clip. May return false even though path is outside of clip.
+
+        Use to check if an area to be drawn is clipped out, to skip subsequent draw calls.
+
+        @param path  SkPath to compare with clip
+        @return      true if path, transformed by SkMatrix, does not intersect clip
+    */
+    bool quickReject(const SkPath& path) const;
+
+    /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty,
+        return SkRect::MakeEmpty, where all SkRect sides equal zero.
+
+        SkRect returned is outset by one to account for partial pixel coverage if clip
+        is anti-aliased.
+
+        @return  bounds of clip in local coordinates
+    */
+    SkRect getLocalClipBounds() const;
+
+    /** Returns bounds of clip, transformed by inverse of SkMatrix. If clip is empty,
+        return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero.
+
+        bounds is outset by one to account for partial pixel coverage if clip
+        is anti-aliased.
+
+        @param bounds  SkRect of clip in local coordinates
+        @return        true if clip bounds is not empty
+    */
+    bool getLocalClipBounds(SkRect* bounds) const {
+        *bounds = this->getLocalClipBounds();
+        return !bounds->isEmpty();
+    }
+
+    /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty,
+        return SkRect::MakeEmpty, where all SkRect sides equal zero.
+
+        Unlike getLocalClipBounds(), returned SkIRect is not outset.
+
+        @return  bounds of clip in SkBaseDevice coordinates
+    */
+    SkIRect getDeviceClipBounds() const;
+
+    /** Returns SkIRect bounds of clip, unaffected by SkMatrix. If clip is empty,
+        return false, and set bounds to SkRect::MakeEmpty, where all SkRect sides equal zero.
+
+        Unlike getLocalClipBounds(), bounds is not outset.
+
+        @param bounds  SkRect of clip in device coordinates
+        @return        true if clip bounds is not empty
+    */
+    bool getDeviceClipBounds(SkIRect* bounds) const {
+        *bounds = this->getDeviceClipBounds();
+        return !bounds->isEmpty();
+    }
+
+    /** Fills clip with color color.
+        mode determines how ARGB is combined with destination.
+
+        @param color  unpremultiplied ARGB
+        @param mode   SkBlendMode used to combine source color and destination
+    */
+    void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver);
+
+    /** Fills clip with color color using SkBlendMode::kSrc.
+        This has the effect of replacing all pixels contained by clip with color.
+
+        @param color  unpremultiplied ARGB
+    */
+    void clear(SkColor color) {
+        this->drawColor(color, SkBlendMode::kSrc);
+    }
+
+    /** Makes SkCanvas contents undefined. Subsequent calls that read SkCanvas pixels,
+        such as drawing with SkBlendMode, return undefined results. discard() does
+        not change clip or SkMatrix.
+
+        discard() may do nothing, depending on the implementation of SkSurface or SkBaseDevice
+        that created SkCanvas.
+
+        discard() allows optimized performance on subsequent draws by removing
+        cached data associated with SkSurface or SkBaseDevice.
+        It is not necessary to call discard() once done with SkCanvas;
+        any cached data is deleted when owning SkSurface or SkBaseDevice is deleted.
+    */
+    void discard() { this->onDiscard(); }
+
+    /** Fills clip with SkPaint paint. SkPaint components SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkBlendMode affect drawing;
+        SkPathEffect in paint is ignored.
+
+        @param paint  graphics state used to fill SkCanvas
+    */
+    void drawPaint(const SkPaint& paint);
+
+    /** \enum SkCanvas::PointMode
+        Selects if an array of points are drawn as discrete points, as lines, or as
+        an open polygon.
+    */
+    enum PointMode {
+        kPoints_PointMode,  //!< draw each point separately
+        kLines_PointMode,   //!< draw each pair of points as a line segment
+        kPolygon_PointMode, //!< draw the array of points as a open polygon
+    };
+
+    /** Draws pts using clip, SkMatrix and SkPaint paint.
+        count is the number of points; if count is less than one, has no effect.
+        mode may be one of: kPoints_PointMode, kLines_PointMode, or kPolygon_PointMode.
+
+        If mode is kPoints_PointMode, the shape of point drawn depends on paint
+        SkPaint::Cap. If paint is set to SkPaint::kRound_Cap, each point draws a
+        circle of diameter SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap
+        or SkPaint::kButt_Cap, each point draws a square of width and height
+        SkPaint stroke width.
+
+        If mode is kLines_PointMode, each pair of points draws a line segment.
+        One line is drawn for every two points; each point is used once. If count is odd,
+        the final point is ignored.
+
+        If mode is kPolygon_PointMode, each adjacent pair of points draws a line segment.
+        count minus one lines are drawn; the first and last point are used once.
+
+        Each line segment respects paint SkPaint::Cap and SkPaint stroke width.
+        SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style.
+
+        Always draws each element one at a time; is not affected by
+        SkPaint::Join, and unlike drawPath(), does not create a mask from all points
+        and lines before drawing.
+
+        @param mode   whether pts draws points or lines
+        @param count  number of points in the array
+        @param pts    array of points to draw
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint);
+
+    /** Draws point at (x, y) using clip, SkMatrix and SkPaint paint.
+
+        The shape of point drawn depends on paint SkPaint::Cap.
+        If paint is set to SkPaint::kRound_Cap, draw a circle of diameter
+        SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap,
+        draw a square of width and height SkPaint stroke width.
+        SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style.
+
+        @param x      left edge of circle or square
+        @param y      top edge of circle or square
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawPoint(SkScalar x, SkScalar y, const SkPaint& paint);
+
+    /** Draws point p using clip, SkMatrix and SkPaint paint.
+
+        The shape of point drawn depends on paint SkPaint::Cap.
+        If paint is set to SkPaint::kRound_Cap, draw a circle of diameter
+        SkPaint stroke width. If paint is set to SkPaint::kSquare_Cap or SkPaint::kButt_Cap,
+        draw a square of width and height SkPaint stroke width.
+        SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style.
+
+        @param p      top-left edge of circle or square
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawPoint(SkPoint p, const SkPaint& paint) {
+        this->drawPoint(p.x(), p.y(), paint);
+    }
+
+    /** Draws line segment from (x0, y0) to (x1, y1) using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint stroke width describes the line thickness;
+        SkPaint::Cap draws the end rounded or square;
+        SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style.
+
+        @param x0     start of line segment on x-axis
+        @param y0     start of line segment on y-axis
+        @param x1     end of line segment on x-axis
+        @param y1     end of line segment on y-axis
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint);
+
+    /** Draws line segment from p0 to p1 using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint stroke width describes the line thickness;
+        SkPaint::Cap draws the end rounded or square;
+        SkPaint::Style is ignored, as if were set to SkPaint::kStroke_Style.
+
+        @param p0     start of line segment
+        @param p1     end of line segment
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawLine(SkPoint p0, SkPoint p1, const SkPaint& paint) {
+        this->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint);
+    }
+
+    /** Draws SkRect rect using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint::Style determines if rectangle is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness, and
+        SkPaint::Join draws the corners rounded or square.
+
+        @param rect   rectangle to draw
+        @param paint  stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawRect(const SkRect& rect, const SkPaint& paint);
+
+    /** Draws SkIRect rect using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint::Style determines if rectangle is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness, and
+        SkPaint::Join draws the corners rounded or square.
+
+        @param rect   rectangle to draw
+        @param paint  stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawIRect(const SkIRect& rect, const SkPaint& paint) {
+        SkRect r;
+        r.set(rect);    // promotes the ints to scalars
+        this->drawRect(r, paint);
+    }
+
+    /** Draws SkRegion region using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint::Style determines if rectangle is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness, and
+        SkPaint::Join draws the corners rounded or square.
+
+        @param region  region to draw
+        @param paint   SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawRegion(const SkRegion& region, const SkPaint& paint);
+
+    /** Draws oval oval using clip, SkMatrix, and SkPaint.
+        In paint: SkPaint::Style determines if oval is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+
+        @param oval   SkRect bounds of oval
+        @param paint  SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawOval(const SkRect& oval, const SkPaint& paint);
+
+    /** Draws SkRRect rrect using clip, SkMatrix, and SkPaint paint.
+        In paint: SkPaint::Style determines if rrect is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+
+        rrect may represent a rectangle, circle, oval, uniformly rounded rectangle, or
+        may have any combination of positive non-square radii for the four corners.
+
+        @param rrect  SkRRect with up to eight corner radii to draw
+        @param paint  SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawRRect(const SkRRect& rrect, const SkPaint& paint);
+
+    /** Draws SkRRect outer and inner
+        using clip, SkMatrix, and SkPaint paint.
+        outer must contain inner or the drawing is undefined.
+        In paint: SkPaint::Style determines if SkRRect is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+        If stroked and SkRRect corner has zero length radii, SkPaint::Join can
+        draw corners rounded or square.
+
+        GPU-backed platforms optimize drawing when both outer and inner are
+        concave and outer contains inner. These platforms may not be able to draw
+        SkPath built with identical data as fast.
+
+        @param outer  SkRRect outer bounds to draw
+        @param inner  SkRRect inner bounds to draw
+        @param paint  SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint);
+
+    /** Draws circle at (cx, cy) with radius using clip, SkMatrix, and SkPaint paint.
+        If radius is zero or less, nothing is drawn.
+        In paint: SkPaint::Style determines if circle is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+
+        @param cx      circle center on the x-axis
+        @param cy      circle center on the y-axis
+        @param radius  half the diameter of circle
+        @param paint   SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint& paint);
+
+    /** Draws circle at center with radius using clip, SkMatrix, and SkPaint paint.
+        If radius is zero or less, nothing is drawn.
+        In paint: SkPaint::Style determines if circle is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+
+        @param center  circle center
+        @param radius  half the diameter of circle
+        @param paint   SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawCircle(SkPoint center, SkScalar radius, const SkPaint& paint) {
+        this->drawCircle(center.x(), center.y(), radius, paint);
+    }
+
+    /** Draws arc using clip, SkMatrix, and SkPaint paint.
+
+        Arc is part of oval bounded by oval, sweeping from startAngle to startAngle plus
+        sweepAngle. startAngle and sweepAngle are in degrees.
+
+        startAngle of zero places start point at the right middle edge of oval.
+        A positive sweepAngle places arc end point clockwise from start point;
+        a negative sweepAngle places arc end point counterclockwise from start point.
+        sweepAngle may exceed 360 degrees, a full circle.
+        If useCenter is true, draw a wedge that includes lines from oval
+        center to arc end points. If useCenter is false, draw arc between end points.
+
+        If SkRect oval is empty or sweepAngle is zero, nothing is drawn.
+
+        @param oval        SkRect bounds of oval containing arc to draw
+        @param startAngle  angle in degrees where arc begins
+        @param sweepAngle  sweep angle in degrees; positive is clockwise
+        @param useCenter   if true, include the center of the oval
+        @param paint       SkPaint stroke or fill, blend, color, and so on, used to draw
+    */
+    void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
+                 bool useCenter, const SkPaint& paint);
+
+    /** Draws SkRRect bounded by SkRect rect, with corner radii (rx, ry) using clip,
+        SkMatrix, and SkPaint paint.
+
+        In paint: SkPaint::Style determines if SkRRect is stroked or filled;
+        if stroked, SkPaint stroke width describes the line thickness.
+        If rx or ry are less than zero, they are treated as if they are zero.
+        If rx plus ry exceeds rect width or rect height, radii are scaled down to fit.
+        If rx and ry are zero, SkRRect is drawn as SkRect and if stroked is affected by
+        SkPaint::Join.
+
+        @param rect   SkRect bounds of SkRRect to draw
+        @param rx     axis length on x-axis of oval describing rounded corners
+        @param ry     axis length on y-axis of oval describing rounded corners
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, const SkPaint& paint);
+
+    /** Draws SkPath path using clip, SkMatrix, and SkPaint paint.
+        SkPath contains an array of path contour, each of which may be open or closed.
+
+        In paint: SkPaint::Style determines if SkRRect is stroked or filled:
+        if filled, SkPath::FillType determines whether path contour describes inside or
+        outside of fill; if stroked, SkPaint stroke width describes the line thickness,
+        SkPaint::Cap describes line ends, and SkPaint::Join describes how
+        corners are drawn.
+
+        @param path   SkPath to draw
+        @param paint  stroke, blend, color, and so on, used to draw
+    */
+    void drawPath(const SkPath& path, const SkPaint& paint);
+
+    /** Draws SkImage image, with its top-left corner at (left, top),
+        using clip, SkMatrix, and optional SkPaint paint.
+
+        If paint is supplied, apply SkColorFilter, alpha, SkImageFilter, SkBlendMode,
+        and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds. If generated
+        mask extends beyond image bounds, replicate image edge colors, just as SkShader
+        made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the
+        image edge color when it samples outside of its bounds.
+
+        @param image  uncompressed rectangular map of pixels
+        @param left   left side of image
+        @param top    top side of image
+        @param paint  SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                      and so on; or nullptr
+    */
+    void drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                   const SkPaint* paint = nullptr);
+
+    /** Draws SkImage image, with its top-left corner at (left, top),
+        using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds. If generated
+        mask extends beyond image bounds, replicate image edge colors, just as SkShader
+        made from SkImage::makeShader with SkShader::kClamp_TileMode set replicates the
+        image edge color when it samples outside of its bounds.
+
+        @param image  uncompressed rectangular map of pixels
+        @param left   left side of image
+        @param top    pop side of image
+        @param paint  SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                      and so on; or nullptr
+    */
+    void drawImage(const sk_sp<SkImage>& image, SkScalar left, SkScalar top,
+                   const SkPaint* paint = nullptr) {
+        this->drawImage(image.get(), left, top, paint);
+    }
+
+    /** \enum SkCanvas::SrcRectConstraint
+        SrcRectConstraint controls the behavior at the edge of source SkRect,
+        provided to drawImageRect(), trading off speed for precision.
+
+        SkFilterQuality in SkPaint may sample multiple pixels in the image. Source SkRect
+        restricts the bounds of pixels that may be read. SkFilterQuality may slow down if
+        it cannot read outside the bounds, when sampling near the edge of source SkRect.
+        SrcRectConstraint specifies whether an SkImageFilter is allowed to read pixels
+        outside source SkRect.
+    */
+    enum SrcRectConstraint {
+        kStrict_SrcRectConstraint, //!< sample only inside bounds; slower
+        kFast_SrcRectConstraint,   //!< sample outside bounds; faster
+    };
+
+    /** Draws SkRect src of SkImage image, scaled and translated to fill SkRect dst.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within src; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param src         source SkRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within src or draw faster
+    */
+    void drawImageRect(const SkImage* image, const SkRect& src, const SkRect& dst,
+                       const SkPaint* paint,
+                       SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /** Draws SkIRect isrc of SkImage image, scaled and translated to fill SkRect dst.
+        Note that isrc is on integer pixel boundaries; dst may include fractional
+        boundaries. Additionally transform draw using clip, SkMatrix, and optional SkPaint
+        paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param isrc        source SkIRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within isrc or draw faster
+    */
+    void drawImageRect(const SkImage* image, const SkIRect& isrc, const SkRect& dst,
+                       const SkPaint* paint,
+                       SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /** Draws SkImage image, scaled and translated to fill SkRect dst, using clip, SkMatrix,
+        and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+    */
+    void drawImageRect(const SkImage* image, const SkRect& dst, const SkPaint* paint);
+
+    /** Draws SkRect src of SkImage image, scaled and translated to fill SkRect dst.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param src         source SkRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within src or draw faster
+    */
+    void drawImageRect(const sk_sp<SkImage>& image, const SkRect& src, const SkRect& dst,
+                       const SkPaint* paint,
+                       SrcRectConstraint constraint = kStrict_SrcRectConstraint) {
+        this->drawImageRect(image.get(), src, dst, paint, constraint);
+    }
+
+    /** Draws SkIRect isrc of SkImage image, scaled and translated to fill SkRect dst.
+        isrc is on integer pixel boundaries; dst may include fractional boundaries.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within image; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param isrc        source SkIRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within image or draw faster
+    */
+    void drawImageRect(const sk_sp<SkImage>& image, const SkIRect& isrc, const SkRect& dst,
+                       const SkPaint* paint,
+                       SrcRectConstraint constraint = kStrict_SrcRectConstraint) {
+        this->drawImageRect(image.get(), isrc, dst, paint, constraint);
+    }
+
+    /** Draws SkImage image, scaled and translated to fill SkRect dst,
+        using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within image; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param image       SkImage containing pixels, dimensions, and format
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+    */
+    void drawImageRect(const sk_sp<SkImage>& image, const SkRect& dst, const SkPaint* paint) {
+        this->drawImageRect(image.get(), dst, paint);
+    }
+
+    /** Draws SkImage image stretched proportionally to fit into SkRect dst.
+        SkIRect center divides the image into nine sections: four sides, four corners, and
+        the center. Corners are unmodified or scaled down proportionately if their sides
+        are larger than dst; center and four sides are scaled to fit remaining space, if any.
+
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds. If paint
+        SkFilterQuality set to kNone_SkFilterQuality, disable pixel filtering. For all
+        other values of paint SkFilterQuality, use kLow_SkFilterQuality to filter pixels.
+        Any SkMaskFilter on paint is ignored as is paint anti-aliasing state.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        @param image   SkImage containing pixels, dimensions, and format
+        @param center  SkIRect edge of image corners and sides
+        @param dst     destination SkRect of image to draw to
+        @param paint   SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                       and so on; or nullptr
+    */
+    void drawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+                       const SkPaint* paint = nullptr);
+
+    /** Draws SkImage image stretched proportionally to fit into SkRect dst.
+        SkIRect center divides the image into nine sections: four sides, four corners, and
+        the center. Corners are not scaled, or scaled down proportionately if their sides
+        are larger than dst; center and four sides are scaled to fit remaining space, if any.
+
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds. If paint
+        SkFilterQuality set to kNone_SkFilterQuality, disable pixel filtering. For all
+        other values of paint SkFilterQuality, use kLow_SkFilterQuality to filter pixels.
+        Any SkMaskFilter on paint is ignored as is paint anti-aliasing state.
+
+        If generated mask extends beyond image bounds, replicate image edge colors, just
+        as SkShader made from SkImage::makeShader with SkShader::kClamp_TileMode set
+        replicates the image edge color when it samples outside of its bounds.
+
+        @param image   SkImage containing pixels, dimensions, and format
+        @param center  SkIRect edge of image corners and sides
+        @param dst     destination SkRect of image to draw to
+        @param paint   SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                       and so on; or nullptr
+    */
+    void drawImageNine(const sk_sp<SkImage>& image, const SkIRect& center, const SkRect& dst,
+                       const SkPaint* paint = nullptr) {
+        this->drawImageNine(image.get(), center, dst, paint);
+    }
+
+    /** Draws SkBitmap bitmap, with its top-left corner at (left, top),
+        using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        @param bitmap  SkBitmap containing pixels, dimensions, and format
+        @param left    left side of bitmap
+        @param top     top side of bitmap
+        @param paint   SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                       and so on; or nullptr
+    */
+    void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+                    const SkPaint* paint = nullptr);
+
+    /** Draws SkRect src of SkBitmap bitmap, scaled and translated to fill SkRect dst.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within src; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param bitmap      SkBitmap containing pixels, dimensions, and format
+        @param src         source SkRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within src or draw faster
+    */
+    void drawBitmapRect(const SkBitmap& bitmap, const SkRect& src, const SkRect& dst,
+                        const SkPaint* paint,
+                        SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /** Draws SkIRect isrc of SkBitmap bitmap, scaled and translated to fill SkRect dst.
+        isrc is on integer pixel boundaries; dst may include fractional boundaries.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within isrc; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param bitmap      SkBitmap containing pixels, dimensions, and format
+        @param isrc        source SkIRect of image to draw from
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  sample strictly within isrc, or draw faster
+    */
+    void drawBitmapRect(const SkBitmap& bitmap, const SkIRect& isrc, const SkRect& dst,
+                        const SkPaint* paint,
+                        SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /** Draws SkBitmap bitmap, scaled and translated to fill SkRect dst.
+        bitmap bounds is on integer pixel boundaries; dst may include fractional boundaries.
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        constraint set to kStrict_SrcRectConstraint limits SkPaint SkFilterQuality to
+        sample within bitmap; set to kFast_SrcRectConstraint allows sampling outside to
+        improve performance.
+
+        @param bitmap      SkBitmap containing pixels, dimensions, and format
+        @param dst         destination SkRect of image to draw to
+        @param paint       SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                           and so on; or nullptr
+        @param constraint  filter strictly within bitmap or draw faster
+    */
+    void drawBitmapRect(const SkBitmap& bitmap, const SkRect& dst, const SkPaint* paint,
+                        SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /** Draws SkBitmap bitmap stretched proportionally to fit into SkRect dst.
+        SkIRect center divides the bitmap into nine sections: four sides, four corners,
+        and the center. Corners are not scaled, or scaled down proportionately if their
+        sides are larger than dst; center and four sides are scaled to fit remaining
+        space, if any.
+
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint
+        SkFilterQuality set to kNone_SkFilterQuality, disable pixel filtering. For all
+        other values of paint SkFilterQuality, use kLow_SkFilterQuality to filter pixels.
+        Any SkMaskFilter on paint is ignored as is paint anti-aliasing state.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        @param bitmap  SkBitmap containing pixels, dimensions, and format
+        @param center  SkIRect edge of image corners and sides
+        @param dst     destination SkRect of image to draw to
+        @param paint   SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                       and so on; or nullptr
+    */
+    void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
+                        const SkPaint* paint = nullptr);
+
+    /** \struct SkCanvas::Lattice
+        SkCanvas::Lattice divides SkBitmap or SkImage into a rectangular grid.
+        Grid entries on even columns and even rows are fixed; these entries are
+        always drawn at their original size if the destination is large enough.
+        If the destination side is too small to hold the fixed entries, all fixed
+        entries are proportionately scaled down to fit.
+        The grid entries not on even columns and rows are scaled to fit the
+        remaining space, if any.
+    */
+    struct Lattice {
+
+        /** \enum SkCanvas::Lattice::RectType
+            Optional setting per rectangular grid entry to make it transparent,
+            or to fill the grid entry with a color.
+        */
+        enum RectType : uint8_t {
+            kDefault     = 0, //!< draws SkBitmap into lattice rectangle
+            kTransparent,     //!< skips lattice rectangle by making it transparent
+            kFixedColor,      //!< draws one of fColors into lattice rectangle
+        };
+
+        const int*      fXDivs;     //!< x-axis values dividing bitmap
+        const int*      fYDivs;     //!< y-axis values dividing bitmap
+        const RectType* fRectTypes; //!< array of fill types
+        int             fXCount;    //!< number of x-coordinates
+        int             fYCount;    //!< number of y-coordinates
+        const SkIRect*  fBounds;    //!< source bounds to draw from
+        const SkColor*  fColors;    //!< array of colors
+    };
+
+    /** Draws SkBitmap bitmap stretched proportionally to fit into SkRect dst.
+
+        SkCanvas::Lattice lattice divides bitmap into a rectangular grid.
+        Each intersection of an even-numbered row and column is fixed; like the corners
+        of drawBitmapNine(), fixed lattice elements never scale larger than their initial
+        size and shrink proportionately when all fixed elements exceed the bitmap
+        dimension. All other grid elements scale to fill the available space, if any.
+
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If bitmap is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from bitmap bounds. If paint
+        SkFilterQuality set to kNone_SkFilterQuality, disable pixel filtering. For all
+        other values of paint SkFilterQuality, use kLow_SkFilterQuality to filter pixels.
+        Any SkMaskFilter on paint is ignored as is paint anti-aliasing state.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        @param bitmap   SkBitmap containing pixels, dimensions, and format
+        @param lattice  division of bitmap into fixed and variable rectangles
+        @param dst      destination SkRect of image to draw to
+        @param paint    SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                        and so on; or nullptr
+    */
+    void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst,
+                           const SkPaint* paint = nullptr);
+
+    /** Draws SkImage image stretched proportionally to fit into SkRect dst.
+
+        SkCanvas::Lattice lattice divides image into a rectangular grid.
+        Each intersection of an even-numbered row and column is fixed; like the corners
+        of drawBitmapNine(), fixed lattice elements never scale larger than their initial
+        size and shrink proportionately when all fixed elements exceed the bitmap
+        dimension. All other grid elements scale to fill the available space, if any.
+
+        Additionally transform draw using clip, SkMatrix, and optional SkPaint paint.
+
+        If SkPaint paint is supplied, apply SkColorFilter, alpha, SkImageFilter,
+        SkBlendMode, and SkDrawLooper. If image is kAlpha_8_SkColorType, apply SkShader.
+        If paint contains SkMaskFilter, generate mask from image bounds. If paint
+        SkFilterQuality set to kNone_SkFilterQuality, disable pixel filtering. For all
+        other values of paint SkFilterQuality, use kLow_SkFilterQuality to filter pixels.
+        Any SkMaskFilter on paint is ignored as is paint anti-aliasing state.
+
+        If generated mask extends beyond bitmap bounds, replicate bitmap edge colors,
+        just as SkShader made from SkShader::MakeBitmapShader with
+        SkShader::kClamp_TileMode set replicates the bitmap edge color when it samples
+        outside of its bounds.
+
+        @param image    SkImage containing pixels, dimensions, and format
+        @param lattice  division of bitmap into fixed and variable rectangles
+        @param dst      destination SkRect of image to draw to
+        @param paint    SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter,
+                        and so on; or nullptr
+    */
+    void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
+                          const SkPaint* paint = nullptr);
+
+    /**
+     * Experimental. Controls anti-aliasing of each edge of images in an image-set.
+     */
+    enum QuadAAFlags : unsigned {
+        kLeft_QuadAAFlag    = 0b0001,
+        kTop_QuadAAFlag     = 0b0010,
+        kRight_QuadAAFlag   = 0b0100,
+        kBottom_QuadAAFlag  = 0b1000,
+
+        kNone_QuadAAFlags   = 0b0000,
+        kAll_QuadAAFlags    = 0b1111,
+    };
+
+    /** This is used by the experimental API below. */
+    struct ImageSetEntry {
+        sk_sp<const SkImage> fImage;
+        SkRect fSrcRect;
+        SkRect fDstRect;
+        float fAlpha;
+        unsigned fAAFlags;  // QuadAAFlags
+    };
+
+    /**
+     * This is an experimental API for the SkiaRenderer Chromium project. The signature will
+     * surely evolve if this is not removed. It currently offers no performance advantage over
+     * drawing images independently, though may in the future. The antialiasing flags are intended
+     * to allow control over each edge's AA status, to allow perfect seaming for tile sets. The
+     * current implementation only antialiases if all edges are flagged, however.
+     * Results are undefined if an image's src rect is not within the image's bounds.
+     */
+    void experimental_DrawImageSetV1(const ImageSetEntry imageSet[], int cnt,
+                                     SkFilterQuality quality, SkBlendMode mode);
+
+    /** Draws text, with origin at (x, y), using clip, SkMatrix, and SkPaint paint.
+
+        text meaning depends on SkPaint::TextEncoding; by default, text is encoded as
+        UTF-8.
+
+        x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default
+        text draws left to right, positioning the first glyph left side bearing at x
+        and its baseline at y. Text size is affected by SkMatrix and SkPaint text size.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        @param text        character code points or glyphs drawn
+        @param byteLength  byte length of text array
+        @param x           start of text on x-axis
+        @param y           start of text on y-axis
+        @param paint       text size, blend, color, and so on, used to draw
+    */
+    void drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+                  const SkPaint& paint);
+
+    // Experimental
+    void drawSimpleText(const void* text, size_t byteLength, SkTextEncoding encoding,
+                        SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint);
+
+    /** Draws null terminated string, with origin at (x, y), using clip, SkMatrix, and
+        SkPaint paint.
+
+        string meaning depends on SkPaint::TextEncoding; by default, strings are encoded
+        as UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired
+        results, since zero bytes may be embedded in the string.
+
+        x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default
+        string draws left to right, positioning the first glyph left side bearing at x
+        and its baseline at y. Text size is affected by SkMatrix and SkPaint text size.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        @param string  character code points or glyphs drawn,
+                       ending with a char value of zero
+        @param x       start of string on x-axis
+        @param y       start of string on y-axis
+        @param paint   text size, blend, color, and so on, used to draw
+    */
+    void drawString(const char* string, SkScalar x, SkScalar y, const SkPaint& paint) {
+        if (!string) {
+            return;
+        }
+        this->drawText(string, strlen(string), x, y, paint);
+    }
+
+    /** Draws null terminated string, with origin at (x, y), using clip, SkMatrix, and
+        SkPaint paint.
+
+        string meaning depends on SkPaint::TextEncoding; by default, strings are encoded
+        as UTF-8. Other values of SkPaint::TextEncoding are unlikely to produce the desired
+        results, since zero bytes may be embedded in the string.
+
+        x and y meaning depends on SkPaint::Align and SkPaint vertical text; by default
+        string draws left to right, positioning the first glyph left side bearing at x
+        and its baseline at y. Text size is affected by SkMatrix and SkPaint text size.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        @param string  character code points or glyphs drawn,
+                       ending with a char value of zero
+        @param x       start of string on x-axis
+        @param y       start of string on y-axis
+        @param paint   text size, blend, color, and so on, used to draw
+    */
+    void drawString(const SkString& string, SkScalar x, SkScalar y, const SkPaint& paint);
+
+    /** Draws each glyph in text with the origin in pos array, using clip, SkMatrix, and
+        SkPaint paint. The number of entries in pos array must match the number of glyphs
+        described by byteLength of text.
+
+        text meaning depends on SkPaint::TextEncoding; by default, text is encoded as
+        UTF-8. pos elements meaning depends on SkPaint vertical text; by default
+        glyph left side bearing and baseline are relative to SkPoint in pos array.
+        Text size is affected by SkMatrix and SkPaint text size.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        Layout engines such as Harfbuzz typically position each glyph
+        rather than using the font advance widths.
+
+        @param text        character code points or glyphs drawn
+        @param byteLength  byte length of text array
+        @param pos         array of glyph origins
+        @param paint       text size, blend, color, and so on, used to draw
+    */
+    void drawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+                     const SkPaint& paint);
+
+    /** Draws each glyph in text with its origin composed from xpos array and
+        constY, using clip, SkMatrix, and SkPaint paint. The number of entries in xpos array
+        must match the number of glyphs described by byteLength of text.
+
+        text meaning depends on SkPaint::TextEncoding; by default, text is encoded as
+        UTF-8. xpos elements meaning depends on SkPaint vertical text;
+        by default each glyph left side bearing is positioned at an xpos element and
+        its baseline is positioned at constY. Text size is affected by SkMatrix and
+        SkPaint text size.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        Layout engines such as Harfbuzz typically position each glyph
+        rather than using the font advance widths if all glyphs share the same
+        baseline.
+
+        @param text        character code points or glyphs drawn
+        @param byteLength  byte length of text array
+        @param xpos        array of x-axis positions, used to position each glyph
+        @param constY      shared y-axis value for all of x-axis positions
+        @param paint       text size, blend, color, and so on, used to draw
+    */
+    void drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
+                      const SkPaint& paint);
+
+    /** Draws text, transforming each glyph by the corresponding SkRSXform,
+        using clip, SkMatrix, and SkPaint paint.
+
+        SkRSXform xform array specifies a separate square scale, rotation, and translation
+        for each glyph. xform does not affect paint SkShader.
+
+        Optional SkRect cullRect is a conservative bounds of text, taking into account
+        SkRSXform and paint. If cullRect is outside of clip, canvas can skip drawing.
+
+        All elements of paint: SkPathEffect, SkMaskFilter, SkShader,
+        SkColorFilter, SkImageFilter, and SkDrawLooper; apply to text. By default, draws
+        filled 12 point black glyphs.
+
+        @param text        character code points or glyphs drawn
+        @param byteLength  byte length of text array
+        @param xform       SkRSXform rotates, scales, and translates each glyph individually
+        @param cullRect    SkRect bounds of text for efficient clipping; or nullptr
+        @param paint       text size, blend, color, and so on, used to draw
+    */
+    void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                         const SkRect* cullRect, const SkPaint& paint);
+
+    /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint.
+
+        blob contains glyphs, their positions, and paint attributes specific to text:
+        SkTypeface, SkPaint text size, SkPaint text scale x,
+        SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold,
+        SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text,
+        and SkPaint subpixel text.
+
+        SkPaint::TextEncoding must be set to SkPaint::kGlyphID_TextEncoding.
+
+        Elements of paint: anti-alias, SkBlendMode, color including alpha,
+        SkColorFilter, SkPaint dither, SkDrawLooper, SkMaskFilter, SkPathEffect, SkShader, and
+        SkPaint::Style; apply to blob. If SkPaint contains SkPaint::kStroke_Style:
+        SkPaint miter limit, SkPaint::Cap, SkPaint::Join, and SkPaint stroke width;
+        apply to SkPath created from blob.
+
+        @param blob   glyphs, positions, and their paints' text size, typeface, and so on
+        @param x      horizontal offset applied to blob
+        @param y      vertical offset applied to blob
+        @param paint  blend, color, stroking, and so on, used to draw
+    */
+    void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint);
+
+    /** Draws SkTextBlob blob at (x, y), using clip, SkMatrix, and SkPaint paint.
+
+        blob contains glyphs, their positions, and paint attributes specific to text:
+        SkTypeface, SkPaint text size, SkPaint text scale x,
+        SkPaint text skew x, SkPaint::Align, SkPaint::Hinting, anti-alias, SkPaint fake bold,
+        SkPaint font embedded bitmaps, SkPaint full hinting spacing, LCD text, SkPaint linear text,
+        and SkPaint subpixel text.
+
+        SkPaint::TextEncoding must be set to SkPaint::kGlyphID_TextEncoding.
+
+        Elements of paint: SkPathEffect, SkMaskFilter, SkShader, SkColorFilter,
+        SkImageFilter, and SkDrawLooper; apply to blob.
+
+        @param blob   glyphs, positions, and their paints' text size, typeface, and so on
+        @param x      horizontal offset applied to blob
+        @param y      vertical offset applied to blob
+        @param paint  blend, color, stroking, and so on, used to draw
+    */
+    void drawTextBlob(const sk_sp<SkTextBlob>& blob, SkScalar x, SkScalar y, const SkPaint& paint) {
+        this->drawTextBlob(blob.get(), x, y, paint);
+    }
+
+    /** Draws SkPicture picture, using clip and SkMatrix.
+        Clip and SkMatrix are unchanged by picture contents, as if
+        save() was called before and restore() was called after drawPicture().
+
+        SkPicture records a series of draw commands for later playback.
+
+        @param picture  recorded drawing commands to play
+    */
+    void drawPicture(const SkPicture* picture) {
+        this->drawPicture(picture, nullptr, nullptr);
+    }
+
+    /** Draws SkPicture picture, using clip and SkMatrix.
+        Clip and SkMatrix are unchanged by picture contents, as if
+        save() was called before and restore() was called after drawPicture().
+
+        SkPicture records a series of draw commands for later playback.
+
+        @param picture  recorded drawing commands to play
+    */
+    void drawPicture(const sk_sp<SkPicture>& picture) {
+        this->drawPicture(picture.get());
+    }
+
+    /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with
+        SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter,
+        SkImageFilter, and SkBlendMode, if provided.
+
+        matrix transformation is equivalent to: save(), concat(), drawPicture(), restore().
+        paint use is equivalent to: saveLayer(), drawPicture(), restore().
+
+        @param picture  recorded drawing commands to play
+        @param matrix   SkMatrix to rotate, scale, translate, and so on; may be nullptr
+        @param paint    SkPaint to apply transparency, filtering, and so on; may be nullptr
+    */
+    void drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint);
+
+    /** Draws SkPicture picture, using clip and SkMatrix; transforming picture with
+        SkMatrix matrix, if provided; and use SkPaint paint alpha, SkColorFilter,
+        SkImageFilter, and SkBlendMode, if provided.
+
+        matrix transformation is equivalent to: save(), concat(), drawPicture(), restore().
+        paint use is equivalent to: saveLayer(), drawPicture(), restore().
+
+        @param picture  recorded drawing commands to play
+        @param matrix   SkMatrix to rotate, scale, translate, and so on; may be nullptr
+        @param paint    SkPaint to apply transparency, filtering, and so on; may be nullptr
+    */
+    void drawPicture(const sk_sp<SkPicture>& picture, const SkMatrix* matrix,
+                     const SkPaint* paint) {
+        this->drawPicture(picture.get(), matrix, paint);
+    }
+
+    /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
+        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+
+        @param vertices  triangle mesh to draw
+        @param mode      combines vertices colors with SkShader, if both are present
+        @param paint     specifies the SkShader, used as SkVertices texture; may be nullptr
+    */
+    void drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint);
+
+    /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix.
+        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+
+        @param vertices  triangle mesh to draw
+        @param mode      combines vertices colors with SkShader, if both are present
+        @param paint     specifies the SkShader, used as SkVertices texture, may be nullptr
+    */
+    void drawVertices(const sk_sp<SkVertices>& vertices, SkBlendMode mode, const SkPaint& paint);
+
+    /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to
+        deform vertices with bone weights.
+        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+        The first element of bones should be an object to world space transformation matrix that
+        will be applied before performing mesh deformations. If no such transformation is needed,
+        it should be the identity matrix.
+        boneCount must be at most 80, and thus the size of bones should be at most 80.
+
+        @param vertices   triangle mesh to draw
+        @param bones      bone matrix data
+        @param boneCount  number of bone matrices
+        @param mode       combines vertices colors with SkShader, if both are present
+        @param paint      specifies the SkShader, used as SkVertices texture, may be nullptr
+    */
+    void drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], int boneCount,
+                      SkBlendMode mode, const SkPaint& paint);
+
+    /** Draws SkVertices vertices, a triangle mesh, using clip and SkMatrix. Bone data is used to
+        deform vertices with bone weights.
+        If vertices texs and vertices colors are defined in vertices, and SkPaint paint
+        contains SkShader, SkBlendMode mode combines vertices colors with SkShader.
+        The first element of bones should be an object to world space transformation matrix that
+        will be applied before performing mesh deformations. If no such transformation is needed,
+        it should be the identity matrix.
+        boneCount must be at most 80, and thus the size of bones should be at most 80.
+
+        @param vertices   triangle mesh to draw
+        @param bones      bone matrix data
+        @param boneCount  number of bone matrices
+        @param mode       combines vertices colors with SkShader, if both are present
+        @param paint      specifies the SkShader, used as SkVertices texture, may be nullptr
+    */
+    void drawVertices(const sk_sp<SkVertices>& vertices, const SkVertices::Bone bones[],
+                      int boneCount, SkBlendMode mode, const SkPaint& paint);
+
+    /** Draws a Coons patch: the interpolation of four cubics with shared corners,
+        associating a color, and optionally a texture SkPoint, with each corner.
+
+        Coons patch uses clip and SkMatrix, paint SkShader, SkColorFilter,
+        alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated
+        as Coons patch texture; SkBlendMode mode combines color colors and SkShader if
+        both are provided.
+
+        SkPoint array cubics specifies four SkPath cubic starting at the top-left corner,
+        in clockwise order, sharing every fourth point. The last SkPath cubic ends at the
+        first point.
+
+        Color array color associates colors with corners in top-left, top-right,
+        bottom-right, bottom-left order.
+
+        If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
+        corners in top-left, top-right, bottom-right, bottom-left order.
+
+        @param cubics     SkPath cubic array, sharing common points
+        @param colors     color array, one for each corner
+        @param texCoords  SkPoint array of texture coordinates, mapping SkShader to corners;
+                          may be nullptr
+        @param mode       SkBlendMode for colors, and for SkShader if paint has one
+        @param paint      SkShader, SkColorFilter, SkBlendMode, used to draw
+    */
+    void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                   const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint);
+
+    /** Draws SkPath cubic Coons patch: the interpolation of four cubics with shared corners,
+        associating a color, and optionally a texture SkPoint, with each corner.
+
+        Coons patch uses clip and SkMatrix, paint SkShader, SkColorFilter,
+        alpha, SkImageFilter, and SkBlendMode. If SkShader is provided it is treated
+        as Coons patch texture; SkBlendMode mode combines color colors and SkShader if
+        both are provided.
+
+        SkPoint array cubics specifies four SkPath cubic starting at the top-left corner,
+        in clockwise order, sharing every fourth point. The last SkPath cubic ends at the
+        first point.
+
+        Color array color associates colors with corners in top-left, top-right,
+        bottom-right, bottom-left order.
+
+        If paint contains SkShader, SkPoint array texCoords maps SkShader as texture to
+        corners in top-left, top-right, bottom-right, bottom-left order.
+
+        @param cubics     SkPath cubic array, sharing common points
+        @param colors     color array, one for each corner
+        @param texCoords  SkPoint array of texture coordinates, mapping SkShader to corners;
+                          may be nullptr
+        @param paint      SkShader, SkColorFilter, SkBlendMode, used to draw
+    */
+    void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                   const SkPoint texCoords[4], const SkPaint& paint) {
+        this->drawPatch(cubics, colors, texCoords, SkBlendMode::kModulate, paint);
+    }
+
+    /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint.
+        paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode
+        to draw, if present. For each entry in the array, SkRect tex locates sprite in
+        atlas, and SkRSXform xform transforms it into destination space.
+
+        xform, text, and colors if present, must contain count entries.
+        Optional colors are applied for each sprite using SkBlendMode mode, treating
+        sprite as source and colors as destination.
+        Optional cullRect is a conservative bounds of all transformed sprites.
+        If cullRect is outside of clip, canvas can skip drawing.
+
+        @param atlas     SkImage containing sprites
+        @param xform     SkRSXform mappings for sprites in atlas
+        @param tex       SkRect locations of sprites in atlas
+        @param colors    one per sprite, blended with sprite using SkBlendMode; may be nullptr
+        @param count     number of sprites to draw
+        @param mode      SkBlendMode combining colors and sprites
+        @param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr
+        @param paint     SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr
+    */
+    void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
+                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
+                   const SkPaint* paint);
+
+    /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint.
+        paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode
+        to draw, if present. For each entry in the array, SkRect tex locates sprite in
+        atlas, and SkRSXform xform transforms it into destination space.
+
+        xform, text, and colors if present, must contain count entries.
+        Optional colors is applied for each sprite using SkBlendMode.
+        Optional cullRect is a conservative bounds of all transformed sprites.
+        If cullRect is outside of clip, canvas can skip drawing.
+
+        @param atlas     SkImage containing sprites
+        @param xform     SkRSXform mappings for sprites in atlas
+        @param tex       SkRect locations of sprites in atlas
+        @param colors    one per sprite, blended with sprite using SkBlendMode; may be nullptr
+        @param count     number of sprites to draw
+        @param mode      SkBlendMode combining colors and sprites
+        @param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr
+        @param paint     SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr
+    */
+    void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
+                   const SkColor colors[], int count, SkBlendMode mode, const SkRect* cullRect,
+                   const SkPaint* paint) {
+        this->drawAtlas(atlas.get(), xform, tex, colors, count, mode, cullRect, paint);
+    }
+
+    /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint.
+        paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode
+        to draw, if present. For each entry in the array, SkRect tex locates sprite in
+        atlas, and SkRSXform xform transforms it into destination space.
+
+        xform and text must contain count entries.
+        Optional cullRect is a conservative bounds of all transformed sprites.
+        If cullRect is outside of clip, canvas can skip drawing.
+
+        @param atlas     SkImage containing sprites
+        @param xform     SkRSXform mappings for sprites in atlas
+        @param tex       SkRect locations of sprites in atlas
+        @param count     number of sprites to draw
+        @param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr
+        @param paint     SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr
+    */
+    void drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], int count,
+                   const SkRect* cullRect, const SkPaint* paint) {
+        this->drawAtlas(atlas, xform, tex, nullptr, count, SkBlendMode::kDst, cullRect, paint);
+    }
+
+    /** Draws a set of sprites from atlas, using clip, SkMatrix, and optional SkPaint paint.
+        paint uses anti-alias, alpha, SkColorFilter, SkImageFilter, and SkBlendMode
+        to draw, if present. For each entry in the array, SkRect tex locates sprite in
+        atlas, and SkRSXform xform transforms it into destination space.
+
+        xform and text must contain count entries.
+        Optional cullRect is a conservative bounds of all transformed sprites.
+        If cullRect is outside of clip, canvas can skip drawing.
+
+        @param atlas     SkImage containing sprites
+        @param xform     SkRSXform mappings for sprites in atlas
+        @param tex       SkRect locations of sprites in atlas
+        @param count     number of sprites to draw
+        @param cullRect  bounds of transformed sprites for efficient clipping; may be nullptr
+        @param paint     SkColorFilter, SkImageFilter, SkBlendMode, and so on; may be nullptr
+    */
+    void drawAtlas(const sk_sp<SkImage>& atlas, const SkRSXform xform[], const SkRect tex[],
+                   int count, const SkRect* cullRect, const SkPaint* paint) {
+        this->drawAtlas(atlas.get(), xform, tex, nullptr, count, SkBlendMode::kDst,
+                        cullRect, paint);
+    }
+
+    /** Draws SkDrawable drawable using clip and SkMatrix, concatenated with
+        optional matrix.
+
+        If SkCanvas has an asynchronous implementation, as is the case
+        when it is recording into SkPicture, then drawable will be referenced,
+        so that SkDrawable::draw() can be called when the operation is finalized. To force
+        immediate drawing, call SkDrawable::draw() instead.
+
+        @param drawable  custom struct encapsulating drawing commands
+        @param matrix    transformation applied to drawing; may be nullptr
+    */
+    void drawDrawable(SkDrawable* drawable, const SkMatrix* matrix = nullptr);
+
+    /** Draws SkDrawable drawable using clip and SkMatrix, offset by (x, y).
+
+        If SkCanvas has an asynchronous implementation, as is the case
+        when it is recording into SkPicture, then drawable will be referenced,
+        so that SkDrawable::draw() can be called when the operation is finalized. To force
+        immediate drawing, call SkDrawable::draw() instead.
+
+        @param drawable  custom struct encapsulating drawing commands
+        @param x         offset into SkCanvas writable pixels on x-axis
+        @param y         offset into SkCanvas writable pixels on y-axis
+    */
+    void drawDrawable(SkDrawable* drawable, SkScalar x, SkScalar y);
+
+    /** Associates SkRect on SkCanvas with an annotation; a key-value pair, where the key is
+        a null-terminated UTF-8 string, and optional value is stored as SkData.
+
+        Only some canvas implementations, such as recording to SkPicture, or drawing to
+        document PDF, use annotations.
+
+        @param rect   SkRect extent of canvas to annotate
+        @param key    string used for lookup
+        @param value  data holding value stored in annotation
+    */
+    void drawAnnotation(const SkRect& rect, const char key[], SkData* value);
+
+    /** Associates SkRect on SkCanvas when an annotation; a key-value pair, where the key is
+        a null-terminated UTF-8 string, and optional value is stored as SkData.
+
+        Only some canvas implementations, such as recording to SkPicture, or drawing to
+        document PDF, use annotations.
+
+        @param rect   SkRect extent of canvas to annotate
+        @param key    string used for lookup
+        @param value  data holding value stored in annotation
+    */
+    void drawAnnotation(const SkRect& rect, const char key[], const sk_sp<SkData>& value) {
+        this->drawAnnotation(rect, key, value.get());
+    }
+
+    /** Returns true if clip is empty; that is, nothing will draw.
+
+        May do work when called; it should not be called
+        more often than needed. However, once called, subsequent calls perform no
+        work until clip changes.
+
+        @return  true if clip is empty
+    */
+    virtual bool isClipEmpty() const;
+
+    /** Returns true if clip is SkRect and not empty.
+        Returns false if the clip is empty, or if it is not SkRect.
+
+        @return  true if clip is SkRect and not empty
+    */
+    virtual bool isClipRect() const;
+
+    /** Returns SkMatrix.
+        This does not account for translation by SkBaseDevice or SkSurface.
+
+        @return  SkMatrix in SkCanvas
+    */
+    const SkMatrix& getTotalMatrix() const;
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    // don't call
+    virtual GrRenderTargetContext* internal_private_accessTopLayerRenderTargetContext();
+    SkIRect internal_private_getTopLayerBounds() const { return getTopLayerBounds(); }
+
+    // TEMP helpers until we switch virtual over to const& for src-rect
+    void legacy_drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+                              const SkPaint* paint,
+                              SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+    void legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+                               const SkPaint* paint,
+                               SrcRectConstraint constraint = kStrict_SrcRectConstraint);
+
+    /**
+     *  Returns the global clip as a region. If the clip contains AA, then only the bounds
+     *  of the clip may be returned.
+     */
+    void temporary_internal_getRgnClip(SkRegion* region);
+
+    void private_draw_shadow_rec(const SkPath&, const SkDrawShadowRec&);
+
+
+protected:
+    // default impl defers to getDevice()->newSurface(info)
+    virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props);
+
+    // default impl defers to its device
+    virtual bool onPeekPixels(SkPixmap* pixmap);
+    virtual bool onAccessTopLayerPixels(SkPixmap* pixmap);
+    virtual SkImageInfo onImageInfo() const;
+    virtual bool onGetProps(SkSurfaceProps* props) const;
+    virtual void onFlush();
+
+    // Subclass save/restore notifiers.
+    // Overriders should call the corresponding INHERITED method up the inheritance chain.
+    // getSaveLayerStrategy()'s return value may suppress full layer allocation.
+    enum SaveLayerStrategy {
+        kFullLayer_SaveLayerStrategy,
+        kNoLayer_SaveLayerStrategy,
+    };
+
+    virtual void willSave() {}
+    // Overriders should call the corresponding INHERITED method up the inheritance chain.
+    virtual SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& ) {
+        return kFullLayer_SaveLayerStrategy;
+    }
+    virtual void willRestore() {}
+    virtual void didRestore() {}
+    virtual void didConcat(const SkMatrix& ) {}
+    virtual void didSetMatrix(const SkMatrix& ) {}
+    virtual void didTranslate(SkScalar dx, SkScalar dy) {
+        this->didConcat(SkMatrix::MakeTrans(dx, dy));
+    }
+
+    // NOTE: If you are adding a new onDraw virtual to SkCanvas, PLEASE add an override to
+    // SkCanvasVirtualEnforcer (in SkCanvasVirtualEnforcer.h). This ensures that subclasses using
+    // that mechanism  will be required to implement the new function.
+    virtual void onDrawPaint(const SkPaint& paint);
+    virtual void onDrawRect(const SkRect& rect, const SkPaint& paint);
+    virtual void onDrawRRect(const SkRRect& rrect, const SkPaint& paint);
+    virtual void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint);
+    virtual void onDrawOval(const SkRect& rect, const SkPaint& paint);
+    virtual void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
+                           bool useCenter, const SkPaint& paint);
+    virtual void onDrawPath(const SkPath& path, const SkPaint& paint);
+    virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint);
+
+    virtual void onDrawText(const void* text, size_t byteLength, SkScalar x,
+                            SkScalar y, const SkPaint& paint);
+    virtual void onDrawPosText(const void* text, size_t byteLength,
+                               const SkPoint pos[], const SkPaint& paint);
+    virtual void onDrawPosTextH(const void* text, size_t byteLength,
+                                const SkScalar xpos[], SkScalar constY,
+                                const SkPaint& paint);
+    virtual void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                                   const SkRect* cullRect, const SkPaint& paint);
+    virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                                const SkPaint& paint);
+
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4], SkBlendMode mode, const SkPaint& paint);
+    virtual void onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
+                              const SkPaint& paint);
+
+    // TODO: Remove old signature
+    virtual void onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
+                                      const SkPaint& paint) {
+        this->onDrawVerticesObject(vertices, nullptr, 0, mode, paint);
+    }
+    virtual void onDrawVerticesObject(const SkVertices* vertices, const SkVertices::Bone bones[],
+                                      int boneCount, SkBlendMode mode, const SkPaint& paint);
+
+    virtual void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, const SkPaint* paint);
+    virtual void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+                                 const SkPaint* paint, SrcRectConstraint constraint);
+    virtual void onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+                                 const SkPaint* paint);
+    virtual void onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
+                                    const SkPaint* paint);
+
+    virtual void onDrawImageSet(const ImageSetEntry imageSet[], int count, SkFilterQuality,
+                                SkBlendMode);
+
+    virtual void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy,
+                              const SkPaint* paint);
+    virtual void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+                                  const SkPaint* paint, SrcRectConstraint constraint);
+    virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
+                                  const SkPaint* paint);
+    virtual void onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice,
+                                     const SkRect& dst, const SkPaint* paint);
+
+    virtual void onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect rect[],
+                             const SkColor colors[], int count, SkBlendMode mode,
+                             const SkRect* cull, const SkPaint* paint);
+
+    virtual void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value);
+    virtual void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&);
+
+    virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix);
+    virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                               const SkPaint* paint);
+
+    enum ClipEdgeStyle {
+        kHard_ClipEdgeStyle,
+        kSoft_ClipEdgeStyle
+    };
+
+    virtual void onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle);
+    virtual void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle);
+    virtual void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle);
+    virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp op);
+
+    virtual void onDiscard();
+
+    // Clip rectangle bounds. Called internally by saveLayer.
+    // returns false if the entire rectangle is entirely clipped out
+    // If non-NULL, The imageFilter parameter will be used to expand the clip
+    // and offscreen bounds for any margin required by the filter DAG.
+    bool clipRectBounds(const SkRect* bounds, SaveLayerFlags flags, SkIRect* intersection,
+                        const SkImageFilter* imageFilter = nullptr);
+
+    SkBaseDevice* getTopDevice() const;
+
+private:
+    /** After calling saveLayer(), there can be any number of devices that make
+     up the top-most drawing area. LayerIter can be used to iterate through
+     those devices. Note that the iterator is only valid until the next API
+     call made on the canvas. Ownership of all pointers in the iterator stays
+     with the canvas, so none of them should be modified or deleted.
+     */
+    class LayerIter /*: SkNoncopyable*/ {
+    public:
+        /** Initialize iterator with canvas, and set values for 1st device */
+        LayerIter(SkCanvas*);
+        ~LayerIter();
+
+        /** Return true if the iterator is done */
+        bool done() const { return fDone; }
+        /** Cycle to the next device */
+        void next();
+
+        // These reflect the current device in the iterator
+
+        SkBaseDevice*   device() const;
+        const SkMatrix& matrix() const;
+        SkIRect clipBounds() const;
+        const SkPaint&  paint() const;
+        int             x() const;
+        int             y() const;
+
+    private:
+        // used to embed the SkDrawIter object directly in our instance, w/o
+        // having to expose that class def to the public. There is an assert
+        // in our constructor to ensure that fStorage is large enough
+        // (though needs to be a compile-time-assert!). We use intptr_t to work
+        // safely with 32 and 64 bit machines (to ensure the storage is enough)
+        intptr_t          fStorage[32];
+        class SkDrawIter* fImpl;    // this points at fStorage
+        SkPaint           fDefaultPaint;
+        bool              fDone;
+    };
+
+    static bool BoundsAffectsClip(SaveLayerFlags);
+
+    static void DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter,
+                                     SkBaseDevice* dst, const SkIPoint& dstOrigin,
+                                     const SkMatrix& ctm);
+
+    enum ShaderOverrideOpacity {
+        kNone_ShaderOverrideOpacity,        //!< there is no overriding shader (bitmap or image)
+        kOpaque_ShaderOverrideOpacity,      //!< the overriding shader is opaque
+        kNotOpaque_ShaderOverrideOpacity,   //!< the overriding shader may not be opaque
+    };
+
+    // notify our surface (if we have one) that we are about to draw, so it
+    // can perform copy-on-write or invalidate any cached images
+    void predrawNotify(bool willOverwritesEntireSurface = false);
+    void predrawNotify(const SkRect* rect, const SkPaint* paint, ShaderOverrideOpacity);
+    void predrawNotify(const SkRect* rect, const SkPaint* paint, bool shaderOverrideIsOpaque) {
+        this->predrawNotify(rect, paint, shaderOverrideIsOpaque ? kOpaque_ShaderOverrideOpacity
+                                                                : kNotOpaque_ShaderOverrideOpacity);
+    }
+
+    SkBaseDevice* getDevice() const;
+
+    class MCRec;
+
+    SkDeque     fMCStack;
+    // points to top of stack
+    MCRec*      fMCRec;
+
+    // the first N recs that can fit here mean we won't call malloc
+    static constexpr int kMCRecSize      = 128;  // most recent measurement
+    static constexpr int kMCRecCount     = 32;   // common depth for save/restores
+    static constexpr int kDeviceCMSize   = 224;  // most recent measurement
+
+    intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)];
+    intptr_t fDeviceCMStorage[kDeviceCMSize / sizeof(intptr_t)];
+
+    const SkSurfaceProps fProps;
+
+    int         fSaveCount;         // value returned by getSaveCount()
+
+    SkMetaData* fMetaData;
+    std::unique_ptr<SkRasterHandleAllocator> fAllocator;
+
+    SkSurface_Base*  fSurfaceBase;
+    SkSurface_Base* getSurfaceBase() const { return fSurfaceBase; }
+    void setSurfaceBase(SkSurface_Base* sb) {
+        fSurfaceBase = sb;
+    }
+    friend class SkSurface_Base;
+    friend class SkSurface_Gpu;
+
+    SkIRect fClipRestrictionRect = SkIRect::MakeEmpty();
+
+    void doSave();
+    void checkForDeferredSave();
+    void internalSetMatrix(const SkMatrix&);
+
+    friend class SkAndroidFrameworkUtils;
+    friend class SkCanvasPriv;      // needs kDontClipToLayer_PrivateSaveLayerFlag
+    friend class SkDrawIter;        // needs setupDrawForLayerDevice()
+    friend class AutoDrawLooper;
+    friend class SkDebugCanvas;     // needs experimental fAllowSimplifyClip
+    friend class SkSurface_Raster;  // needs getDevice()
+    friend class SkNoDrawCanvas;    // needs resetForNextPicture()
+    friend class SkPictureRecord;   // predrawNotify (why does it need it? <reed>)
+    friend class SkOverdrawCanvas;
+    friend class SkRasterHandleAllocator;
+
+protected:
+    // For use by SkNoDrawCanvas (via SkCanvasVirtualEnforcer, which can't be a friend)
+    SkCanvas(const SkIRect& bounds);
+private:
+    SkCanvas(const SkBitmap&, std::unique_ptr<SkRasterHandleAllocator>,
+             SkRasterHandleAllocator::Handle);
+
+    SkCanvas(SkCanvas&&) = delete;
+    SkCanvas(const SkCanvas&) = delete;
+    SkCanvas& operator=(SkCanvas&&) = delete;
+    SkCanvas& operator=(const SkCanvas&) = delete;
+
+    void resetForNextPicture(const SkIRect& bounds);
+
+    // needs gettotalclip()
+    friend class SkCanvasStateUtils;
+
+    // call this each time we attach ourselves to a device
+    //  - constructor
+    //  - internalSaveLayer
+    void setupDevice(SkBaseDevice*);
+
+    void init(sk_sp<SkBaseDevice>);
+
+    /**
+     * Gets the bounds of the top level layer in global canvas coordinates. We don't want this
+     * to be public because it exposes decisions about layer sizes that are internal to the canvas.
+     */
+    SkIRect getTopLayerBounds() const;
+
+    void internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
+                                const SkRect& dst, const SkPaint* paint,
+                                SrcRectConstraint);
+    void internalDrawPaint(const SkPaint& paint);
+    void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy);
+    void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, SkImage* clipImage,
+                            const SkMatrix& clipMatrix);
+
+    // shared by save() and saveLayer()
+    void internalSave();
+    void internalRestore();
+
+    /*
+     *  Returns true if drawing the specified rect (or all if it is null) with the specified
+     *  paint (or default if null) would overwrite the entire root device of the canvas
+     *  (i.e. the canvas' surface if it had one).
+     */
+    bool wouldOverwriteEntireSurface(const SkRect*, const SkPaint*, ShaderOverrideOpacity) const;
+
+    /**
+     *  Returns true if the paint's imagefilter can be invoked directly, without needed a layer.
+     */
+    bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint&);
+
+    /**
+     *  Returns true if the clip (for any active layer) contains antialiasing.
+     *  If the clip is empty, this will return false.
+     */
+    bool androidFramework_isClipAA() const;
+
+    /**
+     *  Keep track of the device clip bounds and if the matrix is scale-translate.  This allows
+     *  us to do a fast quick reject in the common case.
+     */
+    bool   fIsScaleTranslate;
+    SkRect fDeviceClipBounds;
+
+    bool fAllowSoftClip;
+    bool fAllowSimplifyClip;
+
+    class AutoValidateClip {
+    public:
+        explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) {
+            fCanvas->validateClip();
+        }
+        ~AutoValidateClip() { fCanvas->validateClip(); }
+
+    private:
+        const SkCanvas* fCanvas;
+
+        AutoValidateClip(AutoValidateClip&&) = delete;
+        AutoValidateClip(const AutoValidateClip&) = delete;
+        AutoValidateClip& operator=(AutoValidateClip&&) = delete;
+        AutoValidateClip& operator=(const AutoValidateClip&) = delete;
+    };
+
+#ifdef SK_DEBUG
+    void validateClip() const;
+#else
+    void validateClip() const {}
+#endif
+
+    std::unique_ptr<SkGlyphRunBuilder> fScratchGlyphRunBuilder;
+
+    typedef SkRefCnt INHERITED;
+};
+
+/** \class SkAutoCanvasRestore
+    Stack helper class calls SkCanvas::restoreToCount when SkAutoCanvasRestore
+    goes out of scope. Use this to guarantee that the canvas is restored to a known
+    state.
+*/
+class SkAutoCanvasRestore {
+public:
+
+    /** Preserves SkCanvas::save() count. Optionally saves SkCanvas clip and SkCanvas matrix.
+
+        @param canvas  SkCanvas to guard
+        @param doSave  call SkCanvas::save()
+        @return        utility to restore SkCanvas state on destructor
+    */
+    SkAutoCanvasRestore(SkCanvas* canvas, bool doSave) : fCanvas(canvas), fSaveCount(0) {
+        if (fCanvas) {
+            fSaveCount = canvas->getSaveCount();
+            if (doSave) {
+                canvas->save();
+            }
+        }
+    }
+
+    /** Restores SkCanvas to saved state. Destructor is called when container goes out of
+        scope.
+    */
+    ~SkAutoCanvasRestore() {
+        if (fCanvas) {
+            fCanvas->restoreToCount(fSaveCount);
+        }
+    }
+
+    /** Restores SkCanvas to saved state immediately. Subsequent calls and
+        ~SkAutoCanvasRestore have no effect.
+    */
+    void restore() {
+        if (fCanvas) {
+            fCanvas->restoreToCount(fSaveCount);
+            fCanvas = nullptr;
+        }
+    }
+
+private:
+    SkCanvas*   fCanvas;
+    int         fSaveCount;
+
+    SkAutoCanvasRestore(SkAutoCanvasRestore&&) = delete;
+    SkAutoCanvasRestore(const SkAutoCanvasRestore&) = delete;
+    SkAutoCanvasRestore& operator=(SkAutoCanvasRestore&&) = delete;
+    SkAutoCanvasRestore& operator=(const SkAutoCanvasRestore&) = delete;
+};
+#define SkAutoCanvasRestore(...) SK_REQUIRE_LOCAL_VAR(SkAutoCanvasRestore)
+
+#endif

+ 93 - 0
skia/include/core/SkCanvasVirtualEnforcer.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCanvasVirtualEnforcer_DEFINED
+#define SkCanvasVirtualEnforcer_DEFINED
+
+#include "SkCanvas.h"
+
+// If you would ordinarily want to inherit from Base (eg SkCanvas, SkNWayCanvas), instead
+// inherit from SkCanvasVirtualEnforcer<Base>, which will make the build fail if you forget
+// to override one of SkCanvas' key virtual hooks.
+template <typename Base>
+class SkCanvasVirtualEnforcer : public Base {
+public:
+    using Base::Base;
+
+protected:
+    void onDrawPaint(const SkPaint& paint) override = 0;
+    void onDrawRect(const SkRect& rect, const SkPaint& paint) override = 0;
+    void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override = 0;
+    void onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+                      const SkPaint& paint) override = 0;
+    void onDrawOval(const SkRect& rect, const SkPaint& paint) override = 0;
+    void onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
+                   const SkPaint& paint) override = 0;
+    void onDrawPath(const SkPath& path, const SkPaint& paint) override = 0;
+    void onDrawRegion(const SkRegion& region, const SkPaint& paint) override = 0;
+
+    void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+                    const SkPaint& paint) override = 0;
+    void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+                       const SkPaint& paint) override = 0;
+    void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+                        SkScalar constY, const SkPaint& paint) override = 0;
+    void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[],
+                           const SkRect* cullRect, const SkPaint& paint) override = 0;
+    void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+                        const SkPaint& paint) override = 0;
+
+    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                     const SkPoint texCoords[4], SkBlendMode mode,
+                     const SkPaint& paint) override = 0;
+    void onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
+                      const SkPaint& paint) override = 0;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override = 0;
+
+    void onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
+                     const SkPaint* paint) override = 0;
+    void onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+                         const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) override = 0;
+    void onDrawImageNine(const SkImage* image, const SkIRect& center, const SkRect& dst,
+                         const SkPaint* paint) override = 0;
+    void onDrawImageLattice(const SkImage* image, const SkCanvas::Lattice& lattice,
+                            const SkRect& dst, const SkPaint* paint) override = 0;
+
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    // This is under active development for Chrome and not used in Android. Hold off on adding
+    // implementations in Android's SkCanvas subclasses until this stabilizes.
+    void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, SkFilterQuality,
+                        SkBlendMode) override {};
+#else
+    void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, SkFilterQuality,
+                        SkBlendMode) override = 0;
+#endif
+
+    void onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy,
+                      const SkPaint* paint) override = 0;
+    void onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+                          const SkPaint* paint,
+                          SkCanvas::SrcRectConstraint constraint) override = 0;
+    void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
+                          const SkPaint* paint) override = 0;
+    void onDrawBitmapLattice(const SkBitmap& bitmap, const SkCanvas::Lattice& lattice,
+                             const SkRect& dst, const SkPaint* paint) override = 0;
+
+    void onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect rect[],
+                     const SkColor colors[], int count, SkBlendMode mode, const SkRect* cull,
+                     const SkPaint* paint) override = 0;
+
+    void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override = 0;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override = 0;
+
+    void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override = 0;
+    void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                       const SkPaint* paint) override = 0;
+};
+
+#endif

+ 33 - 0
skia/include/core/SkClipOp.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkClipOp_DEFINED
+#define SkClipOp_DEFINED
+
+#include "SkTypes.h"
+
+enum class SkClipOp {
+    kDifference    = 0,
+    kIntersect     = 1,
+
+#ifdef SK_SUPPORT_DEPRECATED_CLIPOPS
+    kUnion_deprecated             = 2,
+    kXOR_deprecated               = 3,
+    kReverseDifference_deprecated = 4,
+    kReplace_deprecated           = 5,
+#else
+    kExtraEnumNeedInternallyPleaseIgnoreWillGoAway2   = 2,
+    kExtraEnumNeedInternallyPleaseIgnoreWillGoAway3   = 3,
+    kExtraEnumNeedInternallyPleaseIgnoreWillGoAway4   = 4,
+    kExtraEnumNeedInternallyPleaseIgnoreWillGoAway5   = 5,
+#endif
+
+    // Used internally for validation, can only shrink to 1 when the deprecated flag is gone
+    kMax_EnumValue = 5,
+};
+
+#endif

+ 389 - 0
skia/include/core/SkColor.h

@@ -0,0 +1,389 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkColor.h and docs/SkColor_Reference.bmh
+   on 2018-06-14 13:13:34. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkColor_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkColor_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkColor.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkColor_DEFINED
+#define SkColor_DEFINED
+
+#include "SkImageInfo.h"
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+/** \file SkColor.h
+
+    Types, consts, functions, and macros for colors.
+*/
+
+/** 8-bit type for an alpha value. 255 is 100% opaque, zero is 100% transparent.
+*/
+typedef uint8_t SkAlpha;
+
+/** 32-bit ARGB color value, unpremultiplied. Color components are always in
+    a known order. This is different from SkPMColor, which has its bytes in a configuration
+    dependent order, to match the format of kBGRA_8888_SkColorType bitmaps. SkColor
+    is the type used to specify colors in SkPaint and in gradients.
+
+    Color that is premultiplied has the same component values as color
+    that is unpremultiplied if alpha is 255, fully opaque, although may have the
+    component values in a different order.
+*/
+typedef uint32_t SkColor;
+
+/** Returns color value from 8-bit component values. Asserts if SK_DEBUG is defined
+    if a, r, g, or b exceed 255. Since color is unpremultiplied, a may be smaller
+    than the largest of r, g, and b.
+
+    @param a  amount of alpha, from fully transparent (0) to fully opaque (255)
+    @param r  amount of red, from no red (0) to full red (255)
+    @param g  amount of green, from no green (0) to full green (255)
+    @param b  amount of blue, from no blue (0) to full blue (255)
+    @return   color and alpha, unpremultiplied
+*/
+static constexpr inline SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+    return SkASSERT(a <= 255 && r <= 255 && g <= 255 && b <= 255),
+           (a << 24) | (r << 16) | (g << 8) | (b << 0);
+}
+
+/** Returns color value from 8-bit component values, with alpha set
+    fully opaque to 255.
+*/
+#define SkColorSetRGB(r, g, b)  SkColorSetARGB(0xFF, r, g, b)
+
+/** Returns alpha byte from color value.
+*/
+#define SkColorGetA(color)      (((color) >> 24) & 0xFF)
+
+/** Returns red component of color, from zero to 255.
+*/
+#define SkColorGetR(color)      (((color) >> 16) & 0xFF)
+
+/** Returns green component of color, from zero to 255.
+*/
+#define SkColorGetG(color)      (((color) >>  8) & 0xFF)
+
+/** Returns blue component of color, from zero to 255.
+*/
+#define SkColorGetB(color)      (((color) >>  0) & 0xFF)
+
+/** Returns unpremultiplied color with red, blue, and green set from c; and alpha set
+    from a. Alpha component of c is ignored and is replaced by a in result.
+
+    @param c  packed RGB, eight bits per component
+    @param a  alpha: transparent at zero, fully opaque at 255
+    @return   color with transparency
+*/
+static constexpr inline SkColor SkColorSetA(SkColor c, U8CPU a) {
+    return (c & 0x00FFFFFF) | (a << 24);
+}
+
+/** Represents fully transparent SkAlpha value. SkAlpha ranges from zero,
+    fully transparent; to 255, fully opaque.
+*/
+constexpr SkAlpha SK_AlphaTRANSPARENT = 0x00;
+
+/** Represents fully opaque SkAlpha value. SkAlpha ranges from zero,
+    fully transparent; to 255, fully opaque.
+*/
+constexpr SkAlpha SK_AlphaOPAQUE      = 0xFF;
+
+/** Represents fully transparent SkColor. May be used to initialize a destination
+    containing a mask or a non-rectangular image.
+*/
+constexpr SkColor SK_ColorTRANSPARENT = SkColorSetARGB(0x00, 0x00, 0x00, 0x00);
+
+/** Represents fully opaque black.
+*/
+constexpr SkColor SK_ColorBLACK       = SkColorSetARGB(0xFF, 0x00, 0x00, 0x00);
+
+/** Represents fully opaque dark gray.
+    Note that SVG dark gray is equivalent to 0xFFA9A9A9.
+*/
+constexpr SkColor SK_ColorDKGRAY      = SkColorSetARGB(0xFF, 0x44, 0x44, 0x44);
+
+/** Represents fully opaque gray.
+    Note that HTML gray is equivalent to 0xFF808080.
+*/
+constexpr SkColor SK_ColorGRAY        = SkColorSetARGB(0xFF, 0x88, 0x88, 0x88);
+
+/** Represents fully opaque light gray. HTML silver is equivalent to 0xFFC0C0C0.
+    Note that SVG light gray is equivalent to 0xFFD3D3D3.
+*/
+constexpr SkColor SK_ColorLTGRAY      = SkColorSetARGB(0xFF, 0xCC, 0xCC, 0xCC);
+
+/** Represents fully opaque white.
+*/
+constexpr SkColor SK_ColorWHITE       = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF);
+
+/** Represents fully opaque red.
+*/
+constexpr SkColor SK_ColorRED         = SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00);
+
+/** Represents fully opaque green. HTML lime is equivalent.
+    Note that HTML green is equivalent to 0xFF008000.
+*/
+constexpr SkColor SK_ColorGREEN       = SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00);
+
+/** Represents fully opaque blue.
+*/
+constexpr SkColor SK_ColorBLUE        = SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF);
+
+/** Represents fully opaque yellow.
+*/
+constexpr SkColor SK_ColorYELLOW      = SkColorSetARGB(0xFF, 0xFF, 0xFF, 0x00);
+
+/** Represents fully opaque cyan. HTML aqua is equivalent.
+*/
+constexpr SkColor SK_ColorCYAN        = SkColorSetARGB(0xFF, 0x00, 0xFF, 0xFF);
+
+/** Represents fully opaque magenta. HTML fuchsia is equivalent.
+*/
+constexpr SkColor SK_ColorMAGENTA     = SkColorSetARGB(0xFF, 0xFF, 0x00, 0xFF);
+
+/** Converts RGB to its HSV components.
+    hsv[0] contains hsv hue, a value from zero to less than 360.
+    hsv[1] contains hsv saturation, a value from zero to one.
+    hsv[2] contains hsv value, a value from zero to one.
+
+    @param red    red component value from zero to 255
+    @param green  green component value from zero to 255
+    @param blue   blue component value from zero to 255
+    @param hsv    three element array which holds the resulting HSV components
+*/
+SK_API void SkRGBToHSV(U8CPU red, U8CPU green, U8CPU blue, SkScalar hsv[3]);
+
+/** Converts ARGB to its HSV components. Alpha in ARGB is ignored.
+    hsv[0] contains hsv hue, and is assigned a value from zero to less than 360.
+    hsv[1] contains hsv saturation, a value from zero to one.
+    hsv[2] contains hsv value, a value from zero to one.
+
+    @param color  ARGB color to convert
+    @param hsv    three element array which holds the resulting HSV components
+*/
+static inline void SkColorToHSV(SkColor color, SkScalar hsv[3]) {
+    SkRGBToHSV(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color), hsv);
+}
+
+/** Converts HSV components to an ARGB color. Alpha is passed through unchanged.
+    hsv[0] represents hsv hue, an angle from zero to less than 360.
+    hsv[1] represents hsv saturation, and varies from zero to one.
+    hsv[2] represents hsv value, and varies from zero to one.
+
+    Out of range hsv values are pinned.
+
+    @param alpha  alpha component of the returned ARGB color
+    @param hsv    three element array which holds the input HSV components
+    @return       ARGB equivalent to HSV
+*/
+SK_API SkColor SkHSVToColor(U8CPU alpha, const SkScalar hsv[3]);
+
+/** Converts HSV components to an ARGB color. Alpha is set to 255.
+    hsv[0] represents hsv hue, an angle from zero to less than 360.
+    hsv[1] represents hsv saturation, and varies from zero to one.
+    hsv[2] represents hsv value, and varies from zero to one.
+
+    Out of range hsv values are pinned.
+
+    @param hsv  three element array which holds the input HSV components
+    @return     RGB equivalent to HSV
+*/
+static inline SkColor SkHSVToColor(const SkScalar hsv[3]) {
+    return SkHSVToColor(0xFF, hsv);
+}
+
+/** 32-bit ARGB color value, premultiplied. The byte order for this value is
+    configuration dependent, matching the format of kBGRA_8888_SkColorType bitmaps.
+    This is different from SkColor, which is unpremultiplied, and is always in the
+    same byte order.
+*/
+typedef uint32_t SkPMColor;
+
+/** Returns a SkPMColor value from unpremultiplied 8-bit component values.
+
+    @param a  amount of alpha, from fully transparent (0) to fully opaque (255)
+    @param r  amount of red, from no red (0) to full red (255)
+    @param g  amount of green, from no green (0) to full green (255)
+    @param b  amount of blue, from no blue (0) to full blue (255)
+    @return   premultiplied color
+*/
+SK_API SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+/** Returns pmcolor closest to color c. Multiplies c RGB components by the c alpha,
+    and arranges the bytes to match the format of kN32_SkColorType.
+
+    @param c  unpremultiplied ARGB color
+    @return   premultiplied color
+*/
+SK_API SkPMColor SkPreMultiplyColor(SkColor c);
+
+/** \struct SkRGBA4f
+    RGBA color value, holding four floating point components. Color components are always in
+    a known order. kAT determines if the SkRGBA4f's R, G, and B components are premultiplied
+    by alpha or not.
+
+    Skia's public API always uses unpremultiplied colors, which can be stored as
+    SkRGBA4f<kUnpremul_SkAlphaType>. For convenience, this type can also be referred to
+    as SkColor4f.
+*/
+template <SkAlphaType kAT>
+struct SkRGBA4f {
+    float fR;  //!< red component
+    float fG;  //!< green component
+    float fB;  //!< blue component
+    float fA;  //!< alpha component
+
+    /** Compares SkRGBA4f with other, and returns true if all components are equal.
+
+        @param other  SkRGBA4f to compare
+        @return       true if SkRGBA4f equals other
+    */
+    bool operator==(const SkRGBA4f& other) const {
+        return fA == other.fA && fR == other.fR && fG == other.fG && fB == other.fB;
+    }
+
+    /** Compares SkRGBA4f with other, and returns true if not all components are equal.
+
+        @param other  SkRGBA4f to compare
+        @return       true if SkRGBA4f is not equal to other
+    */
+    bool operator!=(const SkRGBA4f& other) const {
+        return !(*this == other);
+    }
+
+    /** Returns SkRGBA4f multiplied by scale.
+
+        @param scale  value to multiply by
+        @return       SkRGBA4f as (fR * scale, fG * scale, fB * scale, fA * scale)
+    */
+    SkRGBA4f operator*(float scale) const {
+        return { fR * scale, fG * scale, fB * scale, fA * scale };
+    }
+
+    /** Returns SkRGBA4f multiplied component-wise by scale.
+
+        @param scale  SkRGBA4f to multiply by
+        @return       SkRGBA4f as (fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA)
+    */
+    SkRGBA4f operator*(const SkRGBA4f& scale) const {
+        return { fR * scale.fR, fG * scale.fG, fB * scale.fB, fA * scale.fA };
+    }
+
+    /** Returns a pointer to components of SkRGBA4f, for array access.
+
+        @return       pointer to array [fR, fG, fB, fA]
+    */
+    const float* vec() const { return &fR; }
+
+    /** Returns a pointer to components of SkRGBA4f, for array access.
+
+        @return       pointer to array [fR, fG, fB, fA]
+    */
+    float* vec() { return &fR; }
+
+    /** Returns one component. Asserts if index is out of range and SK_DEBUG is defined.
+
+        @param index  one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA)
+        @return       value corresponding to index
+    */
+    float operator[](int index) const {
+        SkASSERT(index >= 0 && index < 4);
+        return this->vec()[index];
+    }
+
+    /** Returns one component. Asserts if index is out of range and SK_DEBUG is defined.
+
+        @param index  one of: 0 (fR), 1 (fG), 2 (fB), 3 (fA)
+        @return       value corresponding to index
+    */
+    float& operator[](int index) {
+        SkASSERT(index >= 0 && index < 4);
+        return this->vec()[index];
+    }
+
+    /** Returns true if SkRGBA4f is an opaque color. Asserts if fA is out of range and
+        SK_DEBUG is defined.
+
+        @return       true if SkRGBA4f is opaque
+    */
+    bool isOpaque() const {
+        SkASSERT(fA <= 1.0f && fA >= 0.0f);
+        return fA == 1.0f;
+    }
+
+    /** Returns closest SkRGBA4f to SkColor. Only allowed if SkRGBA4f is unpremultiplied.
+
+        @return       SkColor as SkRGBA4f
+    */
+    static SkRGBA4f FromColor(SkColor);  // impl. depends on kAT
+
+    /** Returns closest SkColor to SkRGBA4f. Only allowed if SkRGBA4f is unpremultiplied.
+
+        @return       color as SkColor
+    */
+    SkColor toSkColor() const;  // impl. depends on kAT
+
+    /** Returns closest SkRGBA4f to SkPMColor. Only allowed if SkRGBA4f is premultiplied.
+
+        @return        SkPMColor as SkRGBA4f
+    */
+    static SkRGBA4f FromPMColor(SkPMColor);  // impl. depends on kAT
+
+    /** Returns SkRGBA4f premultiplied by alpha. Asserts at compile time if SkRGBA4f is
+        already premultiplied.
+
+        @return       premultiplied color
+    */
+    SkRGBA4f<kPremul_SkAlphaType> premul() const {
+        static_assert(kAT == kUnpremul_SkAlphaType, "");
+        return { fR * fA, fG * fA, fB * fA, fA };
+    }
+
+    /** Returns SkRGBA4f unpremultiplied by alpha. Asserts at compile time if SkRGBA4f is
+        already unpremultiplied.
+
+        @return       unpremultiplied color
+    */
+    SkRGBA4f<kUnpremul_SkAlphaType> unpremul() const {
+        static_assert(kAT == kPremul_SkAlphaType, "");
+
+        if (fA == 0.0f) {
+            return { 0, 0, 0, 0 };
+        } else {
+            float invAlpha = 1 / fA;
+            return { fR * invAlpha, fG * invAlpha, fB * invAlpha, fA };
+        }
+    }
+
+    // This produces bytes in RGBA order (eg GrColor). Impl. is the same, regardless of kAT
+    uint32_t toBytes_RGBA() const;
+    static SkRGBA4f FromBytes_RGBA(uint32_t color);
+
+    SkRGBA4f makeOpaque() const {
+        return { fR, fG, fB, 1.0f };
+    }
+};
+
+/** \struct SkColor4f
+    RGBA color value, holding four floating point components. Color components are always in
+    a known order, and are unpremultiplied.
+
+    This is a specialization of SkRGBA4f. For details, @see SkRGBA4f.
+*/
+using SkColor4f = SkRGBA4f<kUnpremul_SkAlphaType>;
+
+template <> SK_API SkColor4f SkColor4f::FromColor(SkColor);
+template <> SK_API SkColor   SkColor4f::toSkColor() const;
+
+#endif

+ 196 - 0
skia/include/core/SkColorFilter.h

@@ -0,0 +1,196 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkColorFilter_DEFINED
+#define SkColorFilter_DEFINED
+
+#include "SkBlendMode.h"
+#include "SkColor.h"
+#include "SkFlattenable.h"
+#include "SkRefCnt.h"
+
+class GrContext;
+class GrColorSpaceInfo;
+class GrFragmentProcessor;
+class SkArenaAlloc;
+class SkBitmap;
+class SkColorSpace;
+class SkColorSpaceXformer;
+class SkRasterPipeline;
+class SkString;
+
+/**
+ *  ColorFilters are optional objects in the drawing pipeline. When present in
+ *  a paint, they are called with the "src" colors, and return new colors, which
+ *  are then passed onto the next stage (either ImageFilter or Xfermode).
+ *
+ *  All subclasses are required to be reentrant-safe : it must be legal to share
+ *  the same instance between several threads.
+ */
+class SK_API SkColorFilter : public SkFlattenable {
+public:
+    /**
+     *  If the filter can be represented by a source color plus Mode, this
+     *  returns true, and sets (if not NULL) the color and mode appropriately.
+     *  If not, this returns false and ignores the parameters.
+     */
+    virtual bool asColorMode(SkColor* color, SkBlendMode* bmode) const;
+
+    /**
+     *  If the filter can be represented by a 5x4 matrix, this
+     *  returns true, and sets the matrix appropriately.
+     *  If not, this returns false and ignores the parameter.
+     */
+    virtual bool asColorMatrix(SkScalar matrix[20]) const;
+
+    /**
+     *  If the filter can be represented by per-component table, return true,
+     *  and if table is not null, copy the bitmap containing the table into it.
+     *
+     *  The table bitmap will be in SkBitmap::kA8_Config. Each row corresponding
+     *  to each component in ARGB order. e.g. row[0] == alpha, row[1] == red,
+     *  etc. To transform a color, you (logically) perform the following:
+     *
+     *      a' = *table.getAddr8(a, 0);
+     *      r' = *table.getAddr8(r, 1);
+     *      g' = *table.getAddr8(g, 2);
+     *      b' = *table.getAddr8(b, 3);
+     *
+     *  The original component value is the horizontal index for a given row,
+     *  and the stored value at that index is the new value for that component.
+     */
+    virtual bool asComponentTable(SkBitmap* table) const;
+
+    void appendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool shaderIsOpaque) const;
+
+    enum Flags {
+        /** If set the filter methods will not change the alpha channel of the colors.
+        */
+        kAlphaUnchanged_Flag = 1 << 0,
+    };
+
+    /** Returns the flags for this filter. Override in subclasses to return custom flags.
+    */
+    virtual uint32_t getFlags() const { return 0; }
+
+    SkColor filterColor(SkColor) const;
+    SkColor4f filterColor4f(const SkColor4f&, SkColorSpace*) const;
+
+    /** Create a colorfilter that uses the specified color and mode.
+        If the Mode is DST, this function will return NULL (since that
+        mode will have no effect on the result).
+        @param c    The source color used with the specified mode
+        @param mode The blend that is applied to each color in
+                        the colorfilter's filterSpan[16,32] methods
+        @return colorfilter object that applies the src color and mode,
+                    or NULL if the mode will have no effect.
+    */
+    static sk_sp<SkColorFilter> MakeModeFilter(SkColor c, SkBlendMode mode);
+
+    /** Construct a colorfilter whose effect is to first apply the inner filter and then apply
+     *  this filter, applied to the output of the inner filter.
+     *
+     *  result = this(inner(...))
+     *
+     *  Due to internal limits, it is possible that this will return NULL, so the caller must
+     *  always check.
+     */
+    sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter> inner) const;
+
+    // DEPRECATED, call makeComposed instead
+    static sk_sp<SkColorFilter> MakeComposeFilter(sk_sp<SkColorFilter> outer,
+                                                  sk_sp<SkColorFilter> inner) {
+        return outer ? outer->makeComposed(inner) : inner;
+    }
+
+    /** Construct a color filter that transforms a color by a 4x5 matrix. The matrix is in row-
+     *  major order and the translation column is specified in unnormalized, 0...255, space.
+     */
+    static sk_sp<SkColorFilter> MakeMatrixFilterRowMajor255(const SkScalar array[20]);
+
+    /** Construct a colorfilter that applies the srgb gamma curve to the RGB channels */
+    static sk_sp<SkColorFilter> MakeLinearToSRGBGamma();
+
+    /** Construct a colorfilter that applies the inverse of the srgb gamma curve to the
+     *  RGB channels
+     */
+    static sk_sp<SkColorFilter> MakeSRGBToLinearGamma();
+
+#if SK_SUPPORT_GPU
+    /**
+     *  A subclass may implement this factory function to work with the GPU backend. It returns
+     *  a GrFragmentProcessor that implemets the color filter in GPU shader code.
+     *
+     *  The fragment processor receives a premultiplied input color and produces a premultiplied
+     *  output color.
+     *
+     *  A null return indicates that the color filter isn't implemented for the GPU backend.
+     */
+    virtual std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
+            GrContext*, const GrColorSpaceInfo& dstColorSpaceInfo) const;
+#endif
+
+    bool affectsTransparentBlack() const {
+        return this->filterColor(SK_ColorTRANSPARENT) != SK_ColorTRANSPARENT;
+    }
+
+    static void RegisterFlattenables();
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkColorFilter_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkColorFilter_Type;
+    }
+
+    static sk_sp<SkColorFilter> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkColorFilter>(static_cast<SkColorFilter*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkColorFilter_Type, data, size, procs).release()));
+    }
+
+protected:
+    SkColorFilter() {}
+
+    sk_sp<SkColorFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
+        return this->onMakeColorSpace(xformer);
+    }
+    virtual sk_sp<SkColorFilter> onMakeColorSpace(SkColorSpaceXformer*) const {
+        return sk_ref_sp(const_cast<SkColorFilter*>(this));
+    }
+
+    /**
+     *  If this subclass can optimally createa composition with the inner filter, return it as
+     *  a new filter (which the caller must unref() when it is done). If no such optimization
+     *  is known, return NULL.
+     *
+     *  e.g. result(color) == this_filter(inner(color))
+     */
+    virtual sk_sp<SkColorFilter> onMakeComposed(sk_sp<SkColorFilter>) const { return nullptr; }
+
+private:
+    /*
+     *  Returns 1 if this is a single filter (not a composition of other filters), otherwise it
+     *  reutrns the number of leaf-node filters in a composition. This should be the same value
+     *  as the number of GrFragmentProcessors returned by asFragmentProcessors's array parameter.
+     *
+     *  e.g. compose(filter, compose(compose(filter, filter), filter)) --> 4
+     */
+    virtual int privateComposedFilterCount() const { return 1; }
+
+    virtual void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
+                                bool shaderIsOpaque) const = 0;
+
+    friend class SkColorSpaceXformer;
+    friend class SkComposeColorFilter;
+
+    typedef SkFlattenable INHERITED;
+};
+
+#endif

+ 163 - 0
skia/include/core/SkColorPriv.h

@@ -0,0 +1,163 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkColorPriv_DEFINED
+#define SkColorPriv_DEFINED
+
+#include "../private/SkTo.h"
+#include "SkColor.h"
+#include "SkMath.h"
+
+/** Turn 0..255 into 0..256 by adding 1 at the half-way point. Used to turn a
+    byte into a scale value, so that we can say scale * value >> 8 instead of
+    alpha * value / 255.
+
+    In debugging, asserts that alpha is 0..255
+*/
+static inline unsigned SkAlpha255To256(U8CPU alpha) {
+    SkASSERT(SkToU8(alpha) == alpha);
+    // this one assues that blending on top of an opaque dst keeps it that way
+    // even though it is less accurate than a+(a>>7) for non-opaque dsts
+    return alpha + 1;
+}
+
+/** Multiplify value by 0..256, and shift the result down 8
+    (i.e. return (value * alpha256) >> 8)
+ */
+#define SkAlphaMul(value, alpha256)     (((value) * (alpha256)) >> 8)
+
+static inline U8CPU SkUnitScalarClampToByte(SkScalar x) {
+    return static_cast<U8CPU>(SkScalarPin(x, 0, 1) * 255 + 0.5);
+}
+
+#define SK_A32_BITS     8
+#define SK_R32_BITS     8
+#define SK_G32_BITS     8
+#define SK_B32_BITS     8
+
+#define SK_A32_MASK     ((1 << SK_A32_BITS) - 1)
+#define SK_R32_MASK     ((1 << SK_R32_BITS) - 1)
+#define SK_G32_MASK     ((1 << SK_G32_BITS) - 1)
+#define SK_B32_MASK     ((1 << SK_B32_BITS) - 1)
+
+/*
+ *  Skia's 32bit backend only supports 1 swizzle order at a time (compile-time).
+ *  This is specified by 4 defines SK_A32_SHIFT, SK_R32_SHIFT, ... for G and B.
+ *
+ *  For easier compatibility with Skia's GPU backend, we further restrict these
+ *  to either (in memory-byte-order) RGBA or BGRA. Note that this "order" does
+ *  not directly correspond to the same shift-order, since we have to take endianess
+ *  into account.
+ *
+ *  Here we enforce this constraint.
+ */
+
+#ifdef SK_CPU_BENDIAN
+    #define SK_RGBA_R32_SHIFT   24
+    #define SK_RGBA_G32_SHIFT   16
+    #define SK_RGBA_B32_SHIFT   8
+    #define SK_RGBA_A32_SHIFT   0
+
+    #define SK_BGRA_B32_SHIFT   24
+    #define SK_BGRA_G32_SHIFT   16
+    #define SK_BGRA_R32_SHIFT   8
+    #define SK_BGRA_A32_SHIFT   0
+#else
+    #define SK_RGBA_R32_SHIFT   0
+    #define SK_RGBA_G32_SHIFT   8
+    #define SK_RGBA_B32_SHIFT   16
+    #define SK_RGBA_A32_SHIFT   24
+
+    #define SK_BGRA_B32_SHIFT   0
+    #define SK_BGRA_G32_SHIFT   8
+    #define SK_BGRA_R32_SHIFT   16
+    #define SK_BGRA_A32_SHIFT   24
+#endif
+
+#if defined(SK_PMCOLOR_IS_RGBA) || defined(SK_PMCOLOR_IS_BGRA)
+    #error "Configure PMCOLOR by setting SK_R32_SHIFT, etc"
+#endif
+
+// Deduce which SK_PMCOLOR_IS_ to define from the _SHIFT defines
+
+#if (SK_A32_SHIFT == SK_RGBA_A32_SHIFT && \
+     SK_R32_SHIFT == SK_RGBA_R32_SHIFT && \
+     SK_G32_SHIFT == SK_RGBA_G32_SHIFT && \
+     SK_B32_SHIFT == SK_RGBA_B32_SHIFT)
+    #define SK_PMCOLOR_IS_RGBA
+#elif (SK_A32_SHIFT == SK_BGRA_A32_SHIFT && \
+       SK_R32_SHIFT == SK_BGRA_R32_SHIFT && \
+       SK_G32_SHIFT == SK_BGRA_G32_SHIFT && \
+       SK_B32_SHIFT == SK_BGRA_B32_SHIFT)
+    #define SK_PMCOLOR_IS_BGRA
+#else
+    #error "need 32bit packing to be either RGBA or BGRA"
+#endif
+
+#define SkGetPackedA32(packed)      ((uint32_t)((packed) << (24 - SK_A32_SHIFT)) >> 24)
+#define SkGetPackedR32(packed)      ((uint32_t)((packed) << (24 - SK_R32_SHIFT)) >> 24)
+#define SkGetPackedG32(packed)      ((uint32_t)((packed) << (24 - SK_G32_SHIFT)) >> 24)
+#define SkGetPackedB32(packed)      ((uint32_t)((packed) << (24 - SK_B32_SHIFT)) >> 24)
+
+#define SkA32Assert(a)  SkASSERT((unsigned)(a) <= SK_A32_MASK)
+#define SkR32Assert(r)  SkASSERT((unsigned)(r) <= SK_R32_MASK)
+#define SkG32Assert(g)  SkASSERT((unsigned)(g) <= SK_G32_MASK)
+#define SkB32Assert(b)  SkASSERT((unsigned)(b) <= SK_B32_MASK)
+
+/**
+ *  Pack the components into a SkPMColor, checking (in the debug version) that
+ *  the components are 0..255, and are already premultiplied (i.e. alpha >= color)
+ */
+static inline SkPMColor SkPackARGB32(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+    SkA32Assert(a);
+    SkASSERT(r <= a);
+    SkASSERT(g <= a);
+    SkASSERT(b <= a);
+
+    return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) |
+           (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
+}
+
+/**
+ *  Same as SkPackARGB32, but this version guarantees to not check that the
+ *  values are premultiplied in the debug version.
+ */
+static inline SkPMColor SkPackARGB32NoCheck(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+    return (a << SK_A32_SHIFT) | (r << SK_R32_SHIFT) |
+           (g << SK_G32_SHIFT) | (b << SK_B32_SHIFT);
+}
+
+static inline
+SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
+    SkA32Assert(a);
+    SkR32Assert(r);
+    SkG32Assert(g);
+    SkB32Assert(b);
+
+    if (a != 255) {
+        r = SkMulDiv255Round(r, a);
+        g = SkMulDiv255Round(g, a);
+        b = SkMulDiv255Round(b, a);
+    }
+    return SkPackARGB32(a, r, g, b);
+}
+
+// When Android is compiled optimizing for size, SkAlphaMulQ doesn't get
+// inlined; forcing inlining significantly improves performance.
+static SK_ALWAYS_INLINE uint32_t SkAlphaMulQ(uint32_t c, unsigned scale) {
+    uint32_t mask = 0xFF00FF;
+
+    uint32_t rb = ((c & mask) * scale) >> 8;
+    uint32_t ag = ((c >> 8) & mask) * scale;
+    return (rb & mask) | (ag & ~mask);
+}
+
+static inline SkPMColor SkPMSrcOver(SkPMColor src, SkPMColor dst) {
+    return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
+}
+
+#endif

+ 237 - 0
skia/include/core/SkColorSpace.h

@@ -0,0 +1,237 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkColorSpace_DEFINED
+#define SkColorSpace_DEFINED
+
+#include "../private/SkOnce.h"
+#include "SkMatrix44.h"
+#include "SkRefCnt.h"
+#include <memory>
+
+class SkData;
+struct skcms_ICCProfile;
+
+enum SkGammaNamed {
+    kLinear_SkGammaNamed,
+    kSRGB_SkGammaNamed,
+    k2Dot2Curve_SkGammaNamed,
+    kNonStandard_SkGammaNamed,
+};
+
+/**
+ *  Describes a color gamut with primaries and a white point.
+ */
+struct SK_API SkColorSpacePrimaries {
+    float fRX;
+    float fRY;
+    float fGX;
+    float fGY;
+    float fBX;
+    float fBY;
+    float fWX;
+    float fWY;
+
+    /**
+     *  Convert primaries and a white point to a toXYZD50 matrix, the preferred color gamut
+     *  representation of SkColorSpace.
+     */
+    bool toXYZD50(SkMatrix44* toXYZD50) const;
+};
+
+/**
+ *  Contains the coefficients for a common transfer function equation, specified as
+ *  a transformation from a curved space to linear.
+ *
+ *  LinearVal = sign(InputVal) * (  C*|InputVal| + F       ), for 0.0f <= |InputVal| <  D
+ *  LinearVal = sign(InputVal) * ( (A*|InputVal| + B)^G + E), for D    <= |InputVal|
+ *
+ *  Function must be positive and increasing.
+ */
+struct SK_API SkColorSpaceTransferFn {
+    float fG;
+    float fA;
+    float fB;
+    float fC;
+    float fD;
+    float fE;
+    float fF;
+};
+
+class SK_API SkColorSpace : public SkNVRefCnt<SkColorSpace> {
+public:
+    /**
+     *  Create the sRGB color space.
+     */
+    static sk_sp<SkColorSpace> MakeSRGB();
+
+    /**
+     *  Colorspace with the sRGB primaries, but a linear (1.0) gamma. Commonly used for
+     *  half-float surfaces, and high precision individual colors (gradient stops, etc...)
+     */
+    static sk_sp<SkColorSpace> MakeSRGBLinear();
+
+    enum RenderTargetGamma : uint8_t {
+        kLinear_RenderTargetGamma,
+
+        /**
+         *  Transfer function is the canonical sRGB curve, which has a short linear segment
+         *  followed by a 2.4f exponential.
+         */
+        kSRGB_RenderTargetGamma,
+    };
+
+    enum Gamut {
+        kSRGB_Gamut,
+        kAdobeRGB_Gamut,
+        kDCIP3_D65_Gamut,
+        kRec2020_Gamut,
+    };
+
+    /**
+     *  Create an SkColorSpace from a transfer function and a color gamut.
+     *
+     *  Transfer function can be specified as an enum or as the coefficients to an equation.
+     *  Gamut can be specified as an enum or as the matrix transformation to XYZ D50.
+     */
+    static sk_sp<SkColorSpace> MakeRGB(RenderTargetGamma gamma, Gamut gamut);
+    static sk_sp<SkColorSpace> MakeRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50);
+    static sk_sp<SkColorSpace> MakeRGB(const SkColorSpaceTransferFn& coeffs, Gamut gamut);
+    static sk_sp<SkColorSpace> MakeRGB(const SkColorSpaceTransferFn& coeffs,
+                                       const SkMatrix44& toXYZD50);
+
+    static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
+
+    /**
+     *  Create an SkColorSpace from a parsed (skcms) ICC profile.
+     */
+    static sk_sp<SkColorSpace> Make(const skcms_ICCProfile&);
+
+    /**
+     *  Convert this color space to an skcms ICC profile struct.
+     */
+    void toProfile(skcms_ICCProfile*) const;
+
+    SkGammaNamed gammaNamed() const { return fGammaNamed; }
+
+    /**
+     *  Returns true if the color space gamma is near enough to be approximated as sRGB.
+     */
+    bool gammaCloseToSRGB() const { return kSRGB_SkGammaNamed == fGammaNamed; }
+
+    /**
+     *  Returns true if the color space gamma is linear.
+     */
+    bool gammaIsLinear() const { return kLinear_SkGammaNamed == fGammaNamed; }
+
+    /**
+     *  If the transfer function can be represented as coefficients to the standard
+     *  equation, returns true and sets |fn| to the proper values.
+     *
+     *  If not, returns false.
+     */
+    bool isNumericalTransferFn(SkColorSpaceTransferFn* fn) const;
+
+    /**
+     *  Returns true and sets |toXYZD50| if the color gamut can be described as a matrix.
+     *  Returns false otherwise.
+     */
+    bool toXYZD50(SkMatrix44* toXYZD50) const;
+
+    /**
+     *  Returns a hash of the gamut transformation to XYZ D50. Allows for fast equality checking
+     *  of gamuts, at the (very small) risk of collision.
+     */
+    uint32_t toXYZD50Hash() const { return fToXYZD50Hash; }
+
+    /**
+     *  Returns a color space with the same gamut as this one, but with a linear gamma.
+     *  For color spaces whose gamut can not be described in terms of XYZ D50, returns
+     *  linear sRGB.
+     */
+    sk_sp<SkColorSpace> makeLinearGamma() const;
+
+    /**
+     *  Returns a color space with the same gamut as this one, with with the sRGB transfer
+     *  function. For color spaces whose gamut can not be described in terms of XYZ D50, returns
+     *  sRGB.
+     */
+    sk_sp<SkColorSpace> makeSRGBGamma() const;
+
+    /**
+     *  Returns a color space with the same transfer function as this one, but with the primary
+     *  colors rotated. For any XYZ space, this produces a new color space that maps RGB to GBR
+     *  (when applied to a source), and maps RGB to BRG (when applied to a destination). For other
+     *  types of color spaces, returns nullptr.
+     *
+     *  This is used for testing, to construct color spaces that have severe and testable behavior.
+     */
+    sk_sp<SkColorSpace> makeColorSpin() const;
+
+    /**
+     *  Returns true if the color space is sRGB.
+     *  Returns false otherwise.
+     *
+     *  This allows a little bit of tolerance, given that we might see small numerical error
+     *  in some cases: converting ICC fixed point to float, converting white point to D50,
+     *  rounding decisions on transfer function and matrix.
+     *
+     *  This does not consider a 2.2f exponential transfer function to be sRGB.  While these
+     *  functions are similar (and it is sometimes useful to consider them together), this
+     *  function checks for logical equality.
+     */
+    bool isSRGB() const;
+
+    /**
+     *  Returns nullptr on failure.  Fails when we fallback to serializing ICC data and
+     *  the data is too large to serialize.
+     */
+    sk_sp<SkData> serialize() const;
+
+    /**
+     *  If |memory| is nullptr, returns the size required to serialize.
+     *  Otherwise, serializes into |memory| and returns the size.
+     */
+    size_t writeToMemory(void* memory) const;
+
+    static sk_sp<SkColorSpace> Deserialize(const void* data, size_t length);
+
+    /**
+     *  If both are null, we return true.  If one is null and the other is not, we return false.
+     *  If both are non-null, we do a deeper compare.
+     */
+    static bool Equals(const SkColorSpace*, const SkColorSpace*);
+
+    void       transferFn(float gabcdef[7]) const;
+    void    invTransferFn(float gabcdef[7]) const;
+    void gamutTransformTo(const SkColorSpace* dst, float src_to_dst_row_major[9]) const;
+
+    uint32_t transferFnHash() const { return fTransferFnHash; }
+    uint64_t           hash() const { return (uint64_t)fTransferFnHash << 32 | fToXYZD50Hash; }
+
+private:
+    friend class SkColorSpaceSingletonFactory;
+
+    SkColorSpace(SkGammaNamed gammaNamed,
+                 const float transferFn[7],
+                 const SkMatrix44& toXYZ);
+
+    void computeLazyDstFields() const;
+
+    SkGammaNamed                        fGammaNamed;         // TODO: 2-bit, pack tightly?  drop?
+    uint32_t                            fTransferFnHash;
+    uint32_t                            fToXYZD50Hash;
+
+    float                               fTransferFn[7];
+    float                               fToXYZD50_3x3[9];    // row-major
+
+    mutable float                       fInvTransferFn[7];
+    mutable float                       fFromXYZD50_3x3[9];  // row-major
+    mutable SkOnce                      fLazyDstFieldsOnce;
+};
+
+#endif

+ 20 - 0
skia/include/core/SkColorSpaceXformCanvas.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkColorSpaceXformCanvas_DEFINED
+#define SkColorSpaceXformCanvas_DEFINED
+
+#include <SkCanvas.h>
+#include <SkColorSpace.h>
+#include <memory>
+
+// Proxy SkCanvas calls to unowned target, transforming colors into targetCS as it goes.
+// May return nullptr if |targetCS| is unsupported.
+std::unique_ptr<SkCanvas> SK_API SkCreateColorSpaceXformCanvas(SkCanvas* target,
+                                                               sk_sp<SkColorSpace> targetCS);
+
+#endif  //SkColorSpaceXformCanvas_DEFINED

+ 30 - 0
skia/include/core/SkCoverageMode.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCoverageMode_DEFINED
+#define SkCoverageMode_DEFINED
+
+#include "SkTypes.h"
+
+/**
+ *  Describes geometric operations (ala SkRegion::Op) that can be applied to coverage bytes.
+ *  These can be thought of as variants of porter-duff (SkBlendMode) modes, but only applied
+ *  to the alpha channel.
+ *
+ *  See SkMaskFilter for ways to use these when combining two different masks.
+ */
+enum class SkCoverageMode {
+    kUnion,             // A ∪ B    A+B-A*B
+    kIntersect,         // A ∩ B    A*B
+    kDifference,        // A - B    A*(1-B)
+    kReverseDifference, // B - A    B*(1-A)
+    kXor,               // A ⊕ B    A+B-2*A*B
+
+    kLast = kXor,
+};
+
+#endif

+ 182 - 0
skia/include/core/SkData.h

@@ -0,0 +1,182 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkData_DEFINED
+#define SkData_DEFINED
+
+#include <stdio.h>
+
+#include "SkRefCnt.h"
+
+class SkStream;
+
+/**
+ *  SkData holds an immutable data buffer. Not only is the data immutable,
+ *  but the actual ptr that is returned (by data() or bytes()) is guaranteed
+ *  to always be the same for the life of this instance.
+ */
+class SK_API SkData final : public SkNVRefCnt<SkData> {
+public:
+    /**
+     *  Returns the number of bytes stored.
+     */
+    size_t size() const { return fSize; }
+
+    bool isEmpty() const { return 0 == fSize; }
+
+    /**
+     *  Returns the ptr to the data.
+     */
+    const void* data() const { return fPtr; }
+
+    /**
+     *  Like data(), returns a read-only ptr into the data, but in this case
+     *  it is cast to uint8_t*, to make it easy to add an offset to it.
+     */
+    const uint8_t* bytes() const {
+        return reinterpret_cast<const uint8_t*>(fPtr);
+    }
+
+    /**
+     *  USE WITH CAUTION.
+     *  This call will assert that the refcnt is 1, as a precaution against modifying the
+     *  contents when another client/thread has access to the data.
+     */
+    void* writable_data() {
+        if (fSize) {
+            // only assert we're unique if we're not empty
+            SkASSERT(this->unique());
+        }
+        return fPtr;
+    }
+
+    /**
+     *  Helper to copy a range of the data into a caller-provided buffer.
+     *  Returns the actual number of bytes copied, after clamping offset and
+     *  length to the size of the data. If buffer is NULL, it is ignored, and
+     *  only the computed number of bytes is returned.
+     */
+    size_t copyRange(size_t offset, size_t length, void* buffer) const;
+
+    /**
+     *  Returns true if these two objects have the same length and contents,
+     *  effectively returning 0 == memcmp(...)
+     */
+    bool equals(const SkData* other) const;
+
+    /**
+     *  Function that, if provided, will be called when the SkData goes out
+     *  of scope, allowing for custom allocation/freeing of the data's contents.
+     */
+    typedef void (*ReleaseProc)(const void* ptr, void* context);
+
+    /**
+     *  Create a new dataref by copying the specified data
+     */
+    static sk_sp<SkData> MakeWithCopy(const void* data, size_t length);
+
+
+    /**
+     *  Create a new data with uninitialized contents. The caller should call writable_data()
+     *  to write into the buffer, but this must be done before another ref() is made.
+     */
+    static sk_sp<SkData> MakeUninitialized(size_t length);
+
+    /**
+     *  Create a new dataref by copying the specified c-string
+     *  (a null-terminated array of bytes). The returned SkData will have size()
+     *  equal to strlen(cstr) + 1. If cstr is NULL, it will be treated the same
+     *  as "".
+     */
+    static sk_sp<SkData> MakeWithCString(const char cstr[]);
+
+    /**
+     *  Create a new dataref, taking the ptr as is, and using the
+     *  releaseproc to free it. The proc may be NULL.
+     */
+    static sk_sp<SkData> MakeWithProc(const void* ptr, size_t length, ReleaseProc proc, void* ctx);
+
+    /**
+     *  Call this when the data parameter is already const and will outlive the lifetime of the
+     *  SkData. Suitable for with const globals.
+     */
+    static sk_sp<SkData> MakeWithoutCopy(const void* data, size_t length) {
+        return MakeWithProc(data, length, DummyReleaseProc, nullptr);
+    }
+
+    /**
+     *  Create a new dataref from a pointer allocated by malloc. The Data object
+     *  takes ownership of that allocation, and will handling calling sk_free.
+     */
+    static sk_sp<SkData> MakeFromMalloc(const void* data, size_t length);
+
+    /**
+     *  Create a new dataref the file with the specified path.
+     *  If the file cannot be opened, this returns NULL.
+     */
+    static sk_sp<SkData> MakeFromFileName(const char path[]);
+
+    /**
+     *  Create a new dataref from a stdio FILE.
+     *  This does not take ownership of the FILE, nor close it.
+     *  The caller is free to close the FILE at its convenience.
+     *  The FILE must be open for reading only.
+     *  Returns NULL on failure.
+     */
+    static sk_sp<SkData> MakeFromFILE(FILE* f);
+
+    /**
+     *  Create a new dataref from a file descriptor.
+     *  This does not take ownership of the file descriptor, nor close it.
+     *  The caller is free to close the file descriptor at its convenience.
+     *  The file descriptor must be open for reading only.
+     *  Returns NULL on failure.
+     */
+    static sk_sp<SkData> MakeFromFD(int fd);
+
+    /**
+     *  Attempt to read size bytes into a SkData. If the read succeeds, return the data,
+     *  else return NULL. Either way the stream's cursor may have been changed as a result
+     *  of calling read().
+     */
+    static sk_sp<SkData> MakeFromStream(SkStream*, size_t size);
+
+    /**
+     *  Create a new dataref using a subset of the data in the specified
+     *  src dataref.
+     */
+    static sk_sp<SkData> MakeSubset(const SkData* src, size_t offset, size_t length);
+
+    /**
+     *  Returns a new empty dataref (or a reference to a shared empty dataref).
+     *  New or shared, the caller must see that unref() is eventually called.
+     */
+    static sk_sp<SkData> MakeEmpty();
+
+private:
+    friend class SkNVRefCnt<SkData>;
+    ReleaseProc fReleaseProc;
+    void*       fReleaseProcContext;
+    void*       fPtr;
+    size_t      fSize;
+
+    SkData(const void* ptr, size_t size, ReleaseProc, void* context);
+    explicit SkData(size_t size);   // inplace new/delete
+    ~SkData();
+
+    // Ensure the unsized delete is called.
+    void operator delete(void* p);
+
+    // shared internal factory
+    static sk_sp<SkData> PrivateNewWithCopy(const void* srcOrNull, size_t length);
+
+    static void DummyReleaseProc(const void*, void*); // {}
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 119 - 0
skia/include/core/SkDataTable.h

@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDataTable_DEFINED
+#define SkDataTable_DEFINED
+
+#include "../private/SkTDArray.h"
+#include "SkData.h"
+#include "SkString.h"
+
+/**
+ *  Like SkData, SkDataTable holds an immutable data buffer. The data buffer is
+ *  organized into a table of entries, each with a length, so the entries are
+ *  not required to all be the same size.
+ */
+class SK_API SkDataTable : public SkRefCnt {
+public:
+    /**
+     *  Returns true if the table is empty (i.e. has no entries).
+     */
+    bool isEmpty() const { return 0 == fCount; }
+
+    /**
+     *  Return the number of entries in the table. 0 for an empty table
+     */
+    int count() const { return fCount; }
+
+    /**
+     *  Return the size of the index'th entry in the table. The caller must
+     *  ensure that index is valid for this table.
+     */
+    size_t atSize(int index) const;
+
+    /**
+     *  Return a pointer to the data of the index'th entry in the table.
+     *  The caller must ensure that index is valid for this table.
+     *
+     *  @param size If non-null, this returns the byte size of this entry. This
+     *              will be the same value that atSize(index) would return.
+     */
+    const void* at(int index, size_t* size = nullptr) const;
+
+    template <typename T>
+    const T* atT(int index, size_t* size = nullptr) const {
+        return reinterpret_cast<const T*>(this->at(index, size));
+    }
+
+    /**
+     *  Returns the index'th entry as a c-string, and assumes that the trailing
+     *  null byte had been copied into the table as well.
+     */
+    const char* atStr(int index) const {
+        size_t size;
+        const char* str = this->atT<const char>(index, &size);
+        SkASSERT(strlen(str) + 1 == size);
+        return str;
+    }
+
+    typedef void (*FreeProc)(void* context);
+
+    static sk_sp<SkDataTable> MakeEmpty();
+
+    /**
+     *  Return a new DataTable that contains a copy of the data stored in each
+     *  "array".
+     *
+     *  @param ptrs array of points to each element to be copied into the table.
+     *  @param sizes array of byte-lengths for each entry in the corresponding
+     *               ptrs[] array.
+     *  @param count the number of array elements in ptrs[] and sizes[] to copy.
+     */
+    static sk_sp<SkDataTable> MakeCopyArrays(const void * const * ptrs,
+                                             const size_t sizes[], int count);
+
+    /**
+     *  Return a new table that contains a copy of the data in array.
+     *
+     *  @param array contiguous array of data for all elements to be copied.
+     *  @param elemSize byte-length for a given element.
+     *  @param count the number of entries to be copied out of array. The number
+     *               of bytes that will be copied is count * elemSize.
+     */
+    static sk_sp<SkDataTable> MakeCopyArray(const void* array, size_t elemSize, int count);
+
+    static sk_sp<SkDataTable> MakeArrayProc(const void* array, size_t elemSize, int count,
+                                            FreeProc proc, void* context);
+
+private:
+    struct Dir {
+        const void* fPtr;
+        uintptr_t   fSize;
+    };
+
+    int         fCount;
+    size_t      fElemSize;
+    union {
+        const Dir*  fDir;
+        const char* fElems;
+    } fU;
+
+    FreeProc    fFreeProc;
+    void*       fFreeProcContext;
+
+    SkDataTable();
+    SkDataTable(const void* array, size_t elemSize, int count,
+                FreeProc, void* context);
+    SkDataTable(const Dir*, int count, FreeProc, void* context);
+    virtual ~SkDataTable();
+
+    friend class SkDataTableBuilder;    // access to Dir
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 165 - 0
skia/include/core/SkDeferredDisplayListRecorder.h

@@ -0,0 +1,165 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDeferredDisplayListMaker_DEFINED
+#define SkDeferredDisplayListMaker_DEFINED
+
+#include "SkImageInfo.h"
+#include "SkRefCnt.h"
+#include "SkSurfaceCharacterization.h"
+#include "SkTypes.h"
+
+#include "../private/SkDeferredDisplayList.h"
+
+class GrBackendFormat;
+class GrBackendTexture;
+class GrContext;
+
+class SkCanvas;
+class SkImage;
+class SkSurface;
+struct SkYUVAIndex;
+struct SkYUVASizeInfo;
+
+/*
+ * This class is intended to be used as:
+ *   Get an SkSurfaceCharacterization representing the intended gpu-backed destination SkSurface
+ *   Create one of these (an SkDDLMaker) on the stack
+ *   Get the canvas and render into it
+ *   Snap off and hold on to an SkDeferredDisplayList
+ *   Once your app actually needs the pixels, call SkSurface::draw(SkDeferredDisplayList*)
+ *
+ * This class never accesses the GPU but performs all the cpu work it can. It
+ * is thread-safe (i.e., one can break a scene into tiles and perform their cpu-side
+ * work in parallel ahead of time).
+ */
+class SK_API SkDeferredDisplayListRecorder {
+public:
+    SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&);
+    ~SkDeferredDisplayListRecorder();
+
+    const SkSurfaceCharacterization& characterization() const {
+        return fCharacterization;
+    }
+
+    // The backing canvas will become invalid (and this entry point will return
+    // null) once 'detach' is called.
+    // Note: ownership of the SkCanvas is not transfered via this call.
+    SkCanvas* getCanvas();
+
+    std::unique_ptr<SkDeferredDisplayList> detach();
+
+    // Matches the defines in SkImage_GpuBase.h
+    typedef void* TextureContext;
+    typedef void (*TextureReleaseProc)(TextureContext textureContext);
+    typedef void (*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
+    typedef void (*PromiseDoneProc)(TextureContext textureContext);
+
+    /**
+        Create a new SkImage that is very similar to an SkImage created by MakeFromTexture. The main
+        difference is that the client doesn't have the backend texture on the gpu yet but they know
+        all the properties of the texture. So instead of passing in a GrBackendTexture the client
+        supplies a GrBackendFormat, width, height, and GrMipMapped state.
+
+        When we actually send the draw calls to the GPU, we will call the textureFulfillProc and
+        the client will return a GrBackendTexture to us. The properties of the GrBackendTexture must
+        match those set during the SkImage creation, and it must have a valid backend gpu texture.
+        The gpu texture supplied by the client must stay valid until we call the textureReleaseProc.
+
+        When we are done with the texture returned by the textureFulfillProc we will call the
+        textureReleaseProc passing in the textureContext. This is a signal to the client that they
+        are free to delete the underlying gpu texture. If future draws also use the same promise
+        image we will call the textureFulfillProc again if we've already called the
+        textureReleaseProc. We will always call textureFulfillProc and textureReleaseProc in pairs.
+        In other words we will never call textureFulfillProc or textureReleaseProc multiple times
+        for the same textureContext before calling the other.
+
+        We call the promiseDoneProc when we will no longer call the textureFulfillProc again. We
+        pass in the textureContext as a parameter to the promiseDoneProc. We also guarantee that
+        there will be no outstanding textureReleaseProcs that still need to be called when we call
+        the textureDoneProc. Thus when the textureDoneProc gets called the client is able to cleanup
+        all GPU objects and meta data needed for the textureFulfill call.
+
+        This call is only valid if the SkDeferredDisplayListRecorder is backed by a gpu context.
+
+        @param backendFormat       format of promised gpu texture
+        @param width               width of promised gpu texture
+        @param height              height of promised gpu texture
+        @param mipMapped           mip mapped state of promised gpu texture
+        @param origin              one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param colorType           one of: kUnknown_SkColorType, kAlpha_8_SkColorType,
+                                   kRGB_565_SkColorType, kARGB_4444_SkColorType,
+                                   kRGBA_8888_SkColorType, kBGRA_8888_SkColorType,
+                                   kGray_8_SkColorType, kRGBA_F16_SkColorType
+        @param alphaType           one of: kUnknown_SkAlphaType, kOpaque_SkAlphaType,
+                                   kPremul_SkAlphaType, kUnpremul_SkAlphaType
+        @param colorSpace          range of colors; may be nullptr
+        @param textureFulfillProc  function called to get actual gpu texture
+        @param textureReleaseProc  function called when texture can be released
+        @param promiseDoneProc     function called when we will no longer call textureFulfillProc
+        @param textureContext      state passed to textureFulfillProc and textureReleaseProc
+        @return                    created SkImage, or nullptr
+     */
+    sk_sp<SkImage> makePromiseTexture(const GrBackendFormat& backendFormat,
+                                      int width,
+                                      int height,
+                                      GrMipMapped mipMapped,
+                                      GrSurfaceOrigin origin,
+                                      SkColorType colorType,
+                                      SkAlphaType alphaType,
+                                      sk_sp<SkColorSpace> colorSpace,
+                                      TextureFulfillProc textureFulfillProc,
+                                      TextureReleaseProc textureReleaseProc,
+                                      PromiseDoneProc promiseDoneProc,
+                                      TextureContext textureContext);
+
+    /**
+        This entry point operates the same as 'makePromiseTexture' except that its
+        textureFulfillProc can be called up to four times to fetch the required YUVA
+        planes (passing a different textureContext to each call). So, if the 'yuvaIndices'
+        indicate that only the first two backend textures are used, 'textureFulfillProc' will
+        be called with the first two 'textureContexts'.
+     */
+    sk_sp<SkImage> makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,
+                                          const GrBackendFormat yuvaFormats[],
+                                          const SkISize yuvaSizes[],
+                                          const SkYUVAIndex yuvaIndices[4],
+                                          int imageWidth,
+                                          int imageHeight,
+                                          GrSurfaceOrigin imageOrigin,
+                                          sk_sp<SkColorSpace> imageColorSpace,
+                                          TextureFulfillProc textureFulfillProc,
+                                          TextureReleaseProc textureReleaseProc,
+                                          PromiseDoneProc promiseDoneProc,
+                                          TextureContext textureContexts[]);
+
+    // deprecated version that doesn't take yuvaSizeInfo
+    sk_sp<SkImage> makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,
+                                          const GrBackendFormat yuvaFormats[],
+                                          const SkYUVAIndex yuvaIndices[4],
+                                          int imageWidth,
+                                          int imageHeight,
+                                          GrSurfaceOrigin imageOrigin,
+                                          sk_sp<SkColorSpace> imageColorSpace,
+                                          TextureFulfillProc textureFulfillProc,
+                                          TextureReleaseProc textureReleaseProc,
+                                          PromiseDoneProc promiseDoneProc,
+                                          TextureContext textureContexts[]);
+
+private:
+    bool init();
+
+    const SkSurfaceCharacterization             fCharacterization;
+
+#if SK_SUPPORT_GPU
+    sk_sp<GrContext>                            fContext;
+    sk_sp<SkDeferredDisplayList::LazyProxyData> fLazyProxyData;
+    sk_sp<SkSurface>                            fSurface;
+#endif
+};
+
+#endif

+ 139 - 0
skia/include/core/SkDeque.h

@@ -0,0 +1,139 @@
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkDeque_DEFINED
+#define SkDeque_DEFINED
+
+#include "../private/SkNoncopyable.h"
+#include "SkTypes.h"
+
+/*
+ * The deque class works by blindly creating memory space of a specified element
+ * size. It manages the memory as a doubly linked list of blocks each of which
+ * can contain multiple elements. Pushes and pops add/remove blocks from the
+ * beginning/end of the list as necessary while each block tracks the used
+ * portion of its memory.
+ * One behavior to be aware of is that the pops do not immediately remove an
+ * empty block from the beginning/end of the list (Presumably so push/pop pairs
+ * on the block boundaries don't cause thrashing). This can result in the first/
+ * last element not residing in the first/last block.
+ */
+class SK_API SkDeque : SkNoncopyable {
+public:
+    /**
+     * elemSize specifies the size of each individual element in the deque
+     * allocCount specifies how many elements are to be allocated as a block
+     */
+    explicit SkDeque(size_t elemSize, int allocCount = 1);
+    SkDeque(size_t elemSize, void* storage, size_t storageSize, int allocCount = 1);
+    ~SkDeque();
+
+    bool    empty() const { return 0 == fCount; }
+    int     count() const { return fCount; }
+    size_t  elemSize() const { return fElemSize; }
+
+    const void* front() const { return fFront; }
+    const void* back() const  { return fBack; }
+
+    void* front() {
+        return (void*)((const SkDeque*)this)->front();
+    }
+
+    void* back() {
+        return (void*)((const SkDeque*)this)->back();
+    }
+
+    /**
+     * push_front and push_back return a pointer to the memory space
+     * for the new element
+     */
+    void* push_front();
+    void* push_back();
+
+    void pop_front();
+    void pop_back();
+
+private:
+    struct Block;
+
+public:
+    class Iter {
+    public:
+        enum IterStart {
+            kFront_IterStart,
+            kBack_IterStart,
+        };
+
+        /**
+         * Creates an uninitialized iterator. Must be reset()
+         */
+        Iter();
+
+        Iter(const SkDeque& d, IterStart startLoc);
+        void* next();
+        void* prev();
+
+        void reset(const SkDeque& d, IterStart startLoc);
+
+    private:
+        SkDeque::Block* fCurBlock;
+        char*           fPos;
+        size_t          fElemSize;
+    };
+
+    // Inherit privately from Iter to prevent access to reverse iteration
+    class F2BIter : private Iter {
+    public:
+        F2BIter() {}
+
+        /**
+         * Wrap Iter's 2 parameter ctor to force initialization to the
+         * beginning of the deque
+         */
+        F2BIter(const SkDeque& d) : INHERITED(d, kFront_IterStart) {}
+
+        using Iter::next;
+
+        /**
+         * Wrap Iter::reset to force initialization to the beginning of the
+         * deque
+         */
+        void reset(const SkDeque& d) {
+            this->INHERITED::reset(d, kFront_IterStart);
+        }
+
+    private:
+        typedef Iter INHERITED;
+    };
+
+private:
+    // allow unit test to call numBlocksAllocated
+    friend class DequeUnitTestHelper;
+
+    void*   fFront;
+    void*   fBack;
+
+    Block*  fFrontBlock;
+    Block*  fBackBlock;
+    size_t  fElemSize;
+    void*   fInitialStorage;
+    int     fCount;             // number of elements in the deque
+    int     fAllocCount;        // number of elements to allocate per block
+
+    Block*  allocateBlock(int allocCount);
+    void    freeBlock(Block* block);
+
+    /**
+     * This returns the number of chunk blocks allocated by the deque. It
+     * can be used to gauge the effectiveness of the selected allocCount.
+     */
+    int  numBlocksAllocated() const;
+};
+
+#endif

+ 91 - 0
skia/include/core/SkDocument.h

@@ -0,0 +1,91 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDocument_DEFINED
+#define SkDocument_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+
+class SkCanvas;
+class SkWStream;
+struct SkRect;
+
+/** SK_ScalarDefaultDPI is 72 dots per inch. */
+static constexpr SkScalar SK_ScalarDefaultRasterDPI = 72.0f;
+
+/**
+ *  High-level API for creating a document-based canvas. To use..
+ *
+ *  1. Create a document, specifying a stream to store the output.
+ *  2. For each "page" of content:
+ *      a. canvas = doc->beginPage(...)
+ *      b. draw_my_content(canvas);
+ *      c. doc->endPage();
+ *  3. Close the document with doc->close().
+ */
+class SK_API SkDocument : public SkRefCnt {
+public:
+
+    /**
+     *  Begin a new page for the document, returning the canvas that will draw
+     *  into the page. The document owns this canvas, and it will go out of
+     *  scope when endPage() or close() is called, or the document is deleted.
+     */
+    SkCanvas* beginPage(SkScalar width, SkScalar height, const SkRect* content = nullptr);
+
+    /**
+     *  Call endPage() when the content for the current page has been drawn
+     *  (into the canvas returned by beginPage()). After this call the canvas
+     *  returned by beginPage() will be out-of-scope.
+     */
+    void endPage();
+
+    /**
+     *  Call close() when all pages have been drawn. This will close the file
+     *  or stream holding the document's contents. After close() the document
+     *  can no longer add new pages. Deleting the document will automatically
+     *  call close() if need be.
+     */
+    void close();
+
+    /**
+     *  Call abort() to stop producing the document immediately.
+     *  The stream output must be ignored, and should not be trusted.
+     */
+    void abort();
+
+protected:
+    SkDocument(SkWStream*);
+
+    // note: subclasses must call close() in their destructor, as the base class
+    // cannot do this for them.
+    virtual ~SkDocument();
+
+    virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height) = 0;
+    virtual void onEndPage() = 0;
+    virtual void onClose(SkWStream*) = 0;
+    virtual void onAbort() = 0;
+
+    // Allows subclasses to write to the stream as pages are written.
+    SkWStream* getStream() { return fStream; }
+
+    enum State {
+        kBetweenPages_State,
+        kInPage_State,
+        kClosed_State
+    };
+    State getState() const { return fState; }
+
+private:
+    SkWStream* fStream;
+    State      fState;
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 129 - 0
skia/include/core/SkDrawLooper.h

@@ -0,0 +1,129 @@
+
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkDrawLooper_DEFINED
+#define SkDrawLooper_DEFINED
+
+#include "../private/SkNoncopyable.h"
+#include "SkBlurTypes.h"
+#include "SkFlattenable.h"
+#include "SkPoint.h"
+#include "SkColor.h"
+
+class  SkArenaAlloc;
+class  SkCanvas;
+class  SkColorSpaceXformer;
+class  SkPaint;
+struct SkRect;
+class  SkString;
+
+/** \class SkDrawLooper
+    Subclasses of SkDrawLooper can be attached to a SkPaint. Where they are,
+    and something is drawn to a canvas with that paint, the looper subclass will
+    be called, allowing it to modify the canvas and/or paint for that draw call.
+    More than that, via the next() method, the looper can modify the draw to be
+    invoked multiple times (hence the name loop-er), allow it to perform effects
+    like shadows or frame/fills, that require more than one pass.
+*/
+class SK_API SkDrawLooper : public SkFlattenable {
+public:
+    /**
+     *  Holds state during a draw. Users call next() until it returns false.
+     *
+     *  Subclasses of SkDrawLooper should create a subclass of this object to
+     *  hold state specific to their subclass.
+     */
+    class SK_API Context : ::SkNoncopyable {
+    public:
+        Context() {}
+        virtual ~Context() {}
+
+        /**
+         *  Called in a loop on objects returned by SkDrawLooper::createContext().
+         *  Each time true is returned, the object is drawn (possibly with a modified
+         *  canvas and/or paint). When false is finally returned, drawing for the object
+         *  stops.
+         *
+         *  On each call, the paint will be in its original state, but the
+         *  canvas will be as it was following the previous call to next() or
+         *  createContext().
+         *
+         *  The implementation must ensure that, when next() finally returns
+         *  false, the canvas has been restored to the state it was
+         *  initially, before createContext() was first called.
+         */
+        virtual bool next(SkCanvas* canvas, SkPaint* paint) = 0;
+    };
+
+    /**
+     *  Called right before something is being drawn. Returns a Context
+     *  whose next() method should be called until it returns false.
+     */
+    virtual Context* makeContext(SkCanvas*, SkArenaAlloc*) const = 0;
+
+    /**
+     * The fast bounds functions are used to enable the paint to be culled early
+     * in the drawing pipeline. If a subclass can support this feature it must
+     * return true for the canComputeFastBounds() function.  If that function
+     * returns false then computeFastBounds behavior is undefined otherwise it
+     * is expected to have the following behavior. Given the parent paint and
+     * the parent's bounding rect the subclass must fill in and return the
+     * storage rect, where the storage rect is with the union of the src rect
+     * and the looper's bounding rect.
+     */
+    bool canComputeFastBounds(const SkPaint& paint) const;
+    void computeFastBounds(const SkPaint& paint, const SkRect& src, SkRect* dst) const;
+
+    struct BlurShadowRec {
+        SkScalar        fSigma;
+        SkVector        fOffset;
+        SkColor         fColor;
+        SkBlurStyle     fStyle;
+    };
+    /**
+     *  If this looper can be interpreted as having two layers, such that
+     *      1. The first layer (bottom most) just has a blur and translate
+     *      2. The second layer has no modifications to either paint or canvas
+     *      3. No other layers.
+     *  then return true, and if not null, fill out the BlurShadowRec).
+     *
+     *  If any of the above are not met, return false and ignore the BlurShadowRec parameter.
+     */
+    virtual bool asABlurShadow(BlurShadowRec*) const;
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkDrawLooper_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkDrawLooper_Type;
+    }
+
+    static sk_sp<SkDrawLooper> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkDrawLooper>(static_cast<SkDrawLooper*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkDrawLooper_Type, data, size, procs).release()));
+    }
+
+protected:
+    sk_sp<SkDrawLooper> makeColorSpace(SkColorSpaceXformer* xformer) const {
+        return this->onMakeColorSpace(xformer);
+    }
+    virtual sk_sp<SkDrawLooper> onMakeColorSpace(SkColorSpaceXformer*) const = 0;
+
+    SkDrawLooper() {}
+
+private:
+    friend class SkColorSpaceXformer;
+
+    typedef SkFlattenable INHERITED;
+};
+
+#endif

+ 150 - 0
skia/include/core/SkDrawable.h

@@ -0,0 +1,150 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDrawable_DEFINED
+#define SkDrawable_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkScalar.h"
+
+class GrBackendDrawableInfo;
+class SkCanvas;
+class SkMatrix;
+class SkPicture;
+enum class GrBackendApi : unsigned;
+struct SkRect;
+
+/**
+ *  Base-class for objects that draw into SkCanvas.
+ *
+ *  The object has a generation ID, which is guaranteed to be unique across all drawables. To
+ *  allow for clients of the drawable that may want to cache the results, the drawable must
+ *  change its generation ID whenever its internal state changes such that it will draw differently.
+ */
+class SK_API SkDrawable : public SkFlattenable {
+public:
+    /**
+     *  Draws into the specified content. The drawing sequence will be balanced upon return
+     *  (i.e. the saveLevel() on the canvas will match what it was when draw() was called,
+     *  and the current matrix and clip settings will not be changed.
+     */
+    void draw(SkCanvas*, const SkMatrix* = nullptr);
+    void draw(SkCanvas*, SkScalar x, SkScalar y);
+
+    /**
+     *  When using the GPU backend it is possible for a drawable to execute using the underlying 3D
+     *  API rather than the SkCanvas API. It does so by creating a GpuDrawHandler. The GPU backend
+     *  is deferred so the handler will be given access to the 3D API at the correct point in the
+     *  drawing stream as the GPU backend flushes. Since the drawable may mutate, each time it is
+     *  drawn to a GPU-backed canvas a new handler is snapped, representing the drawable's state at
+     *  the time of the snap.
+     *
+     *  When the GPU backend flushes to the 3D API it will call the draw method on the
+     *  GpuDrawHandler. At this time the drawable may add commands to the stream of GPU commands for
+     *  the unerlying 3D API. The draw function takes a GrBackendDrawableInfo which contains
+     *  information about the current state of 3D API which the caller must respect. See
+     *  GrBackendDrawableInfo for more specific details on what information is sent and the
+     *  requirements for different 3D APIs.
+     *
+     *  Additionaly there may be a slight delay from when the drawable adds its commands to when
+     *  those commands are actually submitted to the GPU. Thus the drawable or GpuDrawHandler is
+     *  required to keep any resources that are used by its added commands alive and valid until
+     *  those commands are submitted to the GPU. The GpuDrawHandler will be kept alive and then
+     *  deleted once the commands are submitted to the GPU. The dtor of the GpuDrawHandler is the
+     *  signal to the drawable that the commands have all been submitted. Different 3D APIs may have
+     *  additional requirements for certain resources which require waiting for the GPU to finish
+     *  all work on those resources before reusing or deleting them. In this case, the drawable can
+     *  use the dtor call of the GpuDrawHandler to add a fence to the GPU to track when the GPU work
+     *  has completed.
+     *
+     *  Currently this is only supported for the GPU Vulkan backend.
+     */
+
+    class GpuDrawHandler {
+    public:
+        virtual ~GpuDrawHandler() {}
+
+        virtual void draw(const GrBackendDrawableInfo&) {}
+    };
+
+    /**
+     * Snaps off a GpuDrawHandler to represent the state of the SkDrawable at the time the snap is
+     * called. This is used for executing GPU backend specific draws intermixed with normal Skia GPU
+     * draws. The GPU API, which will be used for the draw, as well as the full matrix are passed in
+     * as inputs.
+     */
+    std::unique_ptr<GpuDrawHandler> snapGpuDrawHandler(GrBackendApi backendApi,
+                                                       const SkMatrix& matrix) {
+        return this->onSnapGpuDrawHandler(backendApi, matrix);
+    }
+
+    SkPicture* newPictureSnapshot();
+
+    /**
+     *  Return a unique value for this instance. If two calls to this return the same value,
+     *  it is presumed that calling the draw() method will render the same thing as well.
+     *
+     *  Subclasses that change their state should call notifyDrawingChanged() to ensure that
+     *  a new value will be returned the next time it is called.
+     */
+    uint32_t getGenerationID();
+
+    /**
+     *  Return the (conservative) bounds of what the drawable will draw. If the drawable can
+     *  change what it draws (e.g. animation or in response to some external change), then this
+     *  must return a bounds that is always valid for all possible states.
+     */
+    SkRect getBounds();
+
+    /**
+     *  Calling this invalidates the previous generation ID, and causes a new one to be computed
+     *  the next time getGenerationID() is called. Typically this is called by the object itself,
+     *  in response to its internal state changing.
+     */
+    void notifyDrawingChanged();
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkDrawable_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkDrawable_Type;
+    }
+
+    static sk_sp<SkDrawable> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkDrawable>(static_cast<SkDrawable*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkDrawable_Type, data, size, procs).release()));
+    }
+
+    Factory getFactory() const override { return nullptr; }
+    const char* getTypeName() const override { return nullptr; }
+
+protected:
+    SkDrawable();
+
+    virtual SkRect onGetBounds() = 0;
+    virtual void onDraw(SkCanvas*) = 0;
+
+    virtual std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi, const SkMatrix&) {
+        return nullptr;
+    }
+
+    /**
+     *  Default implementation calls onDraw() with a canvas that records into a picture. Subclasses
+     *  may override if they have a more efficient way to return a picture for the current state
+     *  of their drawable. Note: this picture must draw the same as what would be drawn from
+     *  onDraw().
+     */
+    virtual SkPicture* onNewPictureSnapshot();
+
+private:
+    int32_t fGenerationID;
+};
+
+#endif

+ 34 - 0
skia/include/core/SkEncodedImageFormat.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkEncodedImageFormat_DEFINED
+#define SkEncodedImageFormat_DEFINED
+
+#include <stdint.h>
+
+/**
+ *  Enum describing format of encoded data.
+ */
+enum class SkEncodedImageFormat {
+#ifdef SK_BUILD_FOR_GOOGLE3
+    kUnknown,
+#endif
+    kBMP,
+    kGIF,
+    kICO,
+    kJPEG,
+    kPNG,
+    kWBMP,
+    kWEBP,
+    kPKM,
+    kKTX,
+    kASTC,
+    kDNG,
+    kHEIF,
+};
+
+#endif  // SkEncodedImageFormat_DEFINED

+ 33 - 0
skia/include/core/SkExecutor.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkExecutor_DEFINED
+#define SkExecutor_DEFINED
+
+#include <functional>
+#include <memory>
+
+class SkExecutor {
+public:
+    virtual ~SkExecutor();
+
+    // Create a thread pool SkExecutor with a fixed thread count, by default the number of cores.
+    static std::unique_ptr<SkExecutor> MakeFIFOThreadPool(int threads = 0);
+    static std::unique_ptr<SkExecutor> MakeLIFOThreadPool(int threads = 0);
+
+    // There is always a default SkExecutor available by calling SkExecutor::GetDefault().
+    static SkExecutor& GetDefault();
+    static void SetDefault(SkExecutor*);  // Does not take ownership.  Not thread safe.
+
+    // Add work to execute.
+    virtual void add(std::function<void(void)>) = 0;
+
+    // If it makes sense for this executor, use this thread to execute work for a little while.
+    virtual void borrow() {}
+};
+
+#endif//SkExecutor_DEFINED

+ 26 - 0
skia/include/core/SkFilterQuality.h

@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFilterQuality_DEFINED
+#define SkFilterQuality_DEFINED
+
+#include "SkTypes.h"
+
+/**
+ *  Controls how much filtering to be done when scaling/transforming complex colors
+ *  e.g. images
+ */
+enum SkFilterQuality {
+    kNone_SkFilterQuality,      //!< fastest but lowest quality, typically nearest-neighbor
+    kLow_SkFilterQuality,       //!< typically bilerp
+    kMedium_SkFilterQuality,    //!< typically bilerp + mipmaps for down-scaling
+    kHigh_SkFilterQuality,      //!< slowest but highest quality, typically bicubic or better
+
+    kLast_SkFilterQuality = kHigh_SkFilterQuality,
+};
+
+#endif

+ 107 - 0
skia/include/core/SkFlattenable.h

@@ -0,0 +1,107 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFlattenable_DEFINED
+#define SkFlattenable_DEFINED
+
+#include "SkRefCnt.h"
+
+class SkData;
+class SkReadBuffer;
+class SkWriteBuffer;
+
+struct SkSerialProcs;
+struct SkDeserialProcs;
+
+/** \class SkFlattenable
+
+ SkFlattenable is the base class for objects that need to be flattened
+ into a data stream for either transport or as part of the key to the
+ font cache.
+ */
+class SK_API SkFlattenable : public SkRefCnt {
+public:
+    enum Type {
+        kSkColorFilter_Type,
+        kSkDrawable_Type,
+        kSkDrawLooper_Type,
+        kSkImageFilter_Type,
+        kSkMaskFilter_Type,
+        kSkPathEffect_Type,
+        kSkPixelRef_Type,
+        kSkUnused_Type4,    // used to be SkRasterizer
+        kSkShaderBase_Type,
+        kSkUnused_Type,     // used to be SkUnitMapper
+        kSkUnused_Type2,
+        kSkNormalSource_Type,
+    };
+
+    typedef sk_sp<SkFlattenable> (*Factory)(SkReadBuffer&);
+
+    SkFlattenable() {}
+
+    /** Implement this to return a factory function pointer that can be called
+     to recreate your class given a buffer (previously written to by your
+     override of flatten().
+     */
+    virtual Factory getFactory() const = 0;
+
+    /**
+     *  Returns the name of the object's class.
+     */
+    virtual const char* getTypeName() const = 0;
+
+    static Factory NameToFactory(const char name[]);
+    static const char* FactoryToName(Factory);
+
+    static void Register(const char name[], Factory);
+
+    /**
+     *  Override this if your subclass needs to record data that it will need to recreate itself
+     *  from its CreateProc (returned by getFactory()).
+     *
+     *  DEPRECATED public : will move to protected ... use serialize() instead
+     */
+    virtual void flatten(SkWriteBuffer&) const {}
+
+    virtual Type getFlattenableType() const = 0;
+
+    //
+    // public ways to serialize / deserialize
+    //
+    sk_sp<SkData> serialize(const SkSerialProcs* = nullptr) const;
+    size_t serialize(void* memory, size_t memory_size,
+                     const SkSerialProcs* = nullptr) const;
+    static sk_sp<SkFlattenable> Deserialize(Type, const void* data, size_t length,
+                                            const SkDeserialProcs* procs = nullptr);
+
+protected:
+    class PrivateInitializer {
+    public:
+        static void InitEffects();
+        static void InitImageFilters();
+    };
+
+private:
+    static void RegisterFlattenablesIfNeeded();
+    static void Finalize();
+
+    friend class SkGraphics;
+
+    typedef SkRefCnt INHERITED;
+};
+
+#define SK_REGISTER_FLATTENABLE(type) \
+    SkFlattenable::Register(#type, type::CreateProc);
+
+#define SK_FLATTENABLE_HOOKS(type)                                   \
+    static sk_sp<SkFlattenable> CreateProc(SkReadBuffer&);           \
+    friend class SkFlattenable::PrivateInitializer;                  \
+    Factory getFactory() const override { return type::CreateProc; } \
+    const char* getTypeName() const override { return #type; }
+
+#endif

+ 488 - 0
skia/include/core/SkFont.h

@@ -0,0 +1,488 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFont_DEFINED
+#define SkFont_DEFINED
+
+#include "SkFontTypes.h"
+#include "SkScalar.h"
+#include "SkTypeface.h"
+
+class SkMatrix;
+class SkPaint;
+class SkPath;
+struct SkFontMetrics;
+
+/** \class SkFont
+    SkFont controls options applied when drawing and measuring text.
+*/
+class SK_API SkFont {
+public:
+    /** Whether edge pixels draw opaque or with partial transparency.
+    */
+    enum class Edging {
+        kAlias,              //!< no transparent pixels on glyph edges
+        kAntiAlias,          //!< may have transparent pixels on glyph edges
+        kSubpixelAntiAlias,  //!< glyph positioned in pixel using transparency
+    };
+
+#ifdef SK_SUPPORT_LEGACY_NESTED_HINTINGENUM
+    /** Amount of font hinting applied to glyph outlines.
+    */
+    enum Hinting : uint8_t {
+        kNo_Hinting     = 0, //!< glyph outlines unchanged
+        kSlight_Hinting = 1, //!< minimal modification to improve constrast
+        kNormal_Hinting = 2, //!< glyph outlines modified to improve constrast
+        kFull_Hinting   = 3, //!< modifies glyph outlines for maximum constrast
+    };
+#endif
+
+    /** Constructs SkFont with default values.
+
+        @return  default initialized SkFont
+    */
+    SkFont();
+
+    /** Constructs SkFont with default values with SkTypeface and size in points.
+
+        @param typeface  font and style used to draw and measure text
+        @param size      typographic height of text
+        @return          initialized SkFont
+    */
+    SkFont(sk_sp<SkTypeface> typeface, SkScalar size);
+
+
+    /** Constructs SkFont with default values with SkTypeface and size in points,
+        horizontal scale, and horizontal skew. Horizontal scale emulates condensed
+        and expanded fonts. Horizontal skew emulates oblique fonts.
+
+        @param typeface  font and style used to draw and measure text
+        @param size      typographic height of text
+        @param scaleX    text horizontal scale
+        @param skewX     additional shear on x-axis relative to y-axis
+        @return          initialized SkFont
+    */
+    SkFont(sk_sp<SkTypeface> typeface, SkScalar size, SkScalar scaleX, SkScalar skewX);
+
+
+    /** Compares SkFont and font, and returns true if they are equivalent.
+        May return false if SkTypeface has identical contents but different pointers.
+
+        @param font  SkPaint to compare
+        @return      true if SkFont pair are equivalent
+    */
+    bool operator==(const SkFont& font) const;
+
+    /** If true, instructs the font manager to always hint glyphs.
+        Returned value is only meaningful if platform uses FreeType as the font manager.
+
+        @return  true if all glyphs are hinted
+    */
+    bool isForceAutoHinting() const { return SkToBool(fFlags & kForceAutoHinting_PrivFlag); }
+
+    /** Returns true if font engine may return glyphs from font bitmaps instead of from outlines.
+
+        @return  true if glyphs may be font bitmaps
+    */
+    bool isEmbeddedBitmaps() const { return SkToBool(fFlags & kEmbeddedBitmaps_PrivFlag); }
+
+    /** Returns true if glyphs at different sub-pixel positions may differ on pixel edge coverage.
+
+        @return  true if glyph positioned in pixel using transparency
+    */
+    bool isSubpixel() const { return SkToBool(fFlags & kSubpixel_PrivFlag); }
+
+    /** Returns true if text is converted to SkPath before drawing and measuring.
+
+        @return  true glyph hints are never applied
+    */
+    bool isLinearMetrics() const { return SkToBool(fFlags & kLinearMetrics_PrivFlag); }
+
+    /** Returns true if bold is approximated by increasing the stroke width when creating glyph
+        bitmaps from outlines.
+
+        @return  bold is approximated through stroke width
+    */
+    bool isEmbolden() const { return SkToBool(fFlags & kEmbolden_PrivFlag); }
+
+    /** Sets whether to always hint glyphs.
+        If forceAutoHinting is set, instructs the font manager to always hint glyphs.
+
+        Only affects platforms that use FreeType as the font manager.
+
+        @param forceAutoHinting  setting to always hint glyphs
+    */
+    void setForceAutoHinting(bool forceAutoHinting);
+
+    /** Requests, but does not require, to use bitmaps in fonts instead of outlines.
+
+        @param embeddedBitmaps  setting to use bitmaps in fonts
+    */
+    void setEmbeddedBitmaps(bool embeddedBitmaps);
+
+    /** Requests, but does not require, that glyphs respect sub-pixel positioning.
+
+        @param subpixel  setting for sub-pixel positioning
+    */
+    void setSubpixel(bool subpixel);
+
+    /** Requests, but does not require, that glyphs are converted to SkPath
+        before drawing and measuring.
+
+        @param linearMetrics  setting for converting glyphs to paths
+    */
+    void setLinearMetrics(bool linearMetrics);
+
+    /** Increases stroke width when creating glyph bitmaps to approximate a bold typeface.
+
+        @param embolden  setting for bold approximation
+    */
+    void setEmbolden(bool embolden);
+
+    /** Whether edge pixels draw opaque or with partial transparency.
+
+        @return  one of: Edging::kAlias, Edging::kAntiAlias, Edging::kSubpixelAntiAlias
+    */
+    Edging getEdging() const { return (Edging)fEdging; }
+
+    /** Requests, but does not require, that edge pixels draw opaque or with
+        partial transparency.
+
+        @param edging  one of: Edging::kAlias, Edging::kAntiAlias, Edging::kSubpixelAntiAlias
+    */
+    void setEdging(Edging edging);
+
+    /** Sets level of glyph outline adjustment.
+        Does not check for valid values of hintingLevel.
+
+        @param hintingLevel  one of: SkFontHinting::kNone, SkFontHinting::kSlight,
+                                     SkFontHinting::kNormal, SkFontHinting::kFull
+    */
+    void setHinting(SkFontHinting hintingLevel);
+
+    /** Returns level of glyph outline adjustment.
+
+        @return  one of: SkFontHinting::kNone, SkFontHinting::kSlight, SkFontHinting::kNormal,
+                         SkFontHinting::kFull
+     */
+    SkFontHinting getHinting() const { return (SkFontHinting)fHinting; }
+
+    /** Returns a font with the same attributes of this font, but with the specified size.
+        Returns nullptr if size is less than zero, infinite, or NaN.
+
+        @param size  typographic height of text
+        @return      initialized SkFont
+     */
+    SkFont makeWithSize(SkScalar size) const;
+
+    /** Returns SkTypeface if set, or nullptr.
+        Does not alter SkTypeface SkRefCnt.
+
+        @return  SkTypeface if previously set, nullptr otherwise
+    */
+    SkTypeface* getTypeface() const { return fTypeface.get(); }
+
+    /** Returns text size in points.
+
+        @return  typographic height of text
+    */
+    SkScalar    getSize() const { return fSize; }
+
+    /** Returns text scale on x-axis.
+        Default value is 1.
+
+        @return  text horizontal scale
+    */
+    SkScalar    getScaleX() const { return fScaleX; }
+
+    /** Returns text skew on x-axis.
+        Default value is zero.
+
+        @return  additional shear on x-axis relative to y-axis
+    */
+    SkScalar    getSkewX() const { return fSkewX; }
+
+    /** Increases SkTypeface SkRefCnt by one.
+
+        @return  SkTypeface if previously set, nullptr otherwise
+    */
+    sk_sp<SkTypeface> refTypeface() const { return fTypeface; }
+
+    /** Sets SkTypeface to typeface, decreasing SkRefCnt of the previous SkTypeface.
+        Pass nullptr to clear SkTypeface and use the default typeface. Increments
+        tf SkRefCnt by one.
+
+        @param tf  font and style used to draw text
+    */
+    void setTypeface(sk_sp<SkTypeface> tf) { fTypeface = tf; }
+
+    /** Sets text size in points.
+        Has no effect if textSize is not greater than or equal to zero.
+
+        @param textSize  typographic height of text
+    */
+    void setSize(SkScalar textSize);
+
+    /** Sets text scale on x-axis.
+        Default value is 1.
+
+        @param scaleX  text horizontal scale
+    */
+    void setScaleX(SkScalar scaleX);
+
+    /** Sets text skew on x-axis.
+        Default value is zero.
+
+        @param skewX  additional shear on x-axis relative to y-axis
+    */
+    void setSkewX(SkScalar skewX);
+
+    /** Converts text into glyph indices.
+        Returns the number of glyph indices represented by text.
+        SkTextEncoding specifies how text represents characters or glyphs.
+        glyphs may be nullptr, to compute the glyph count.
+
+        Does not check text for valid character codes or valid glyph indices.
+
+        If byteLength equals zero, returns zero.
+        If byteLength includes a partial character, the partial character is ignored.
+
+        If encoding is kUTF8_SkTextEncoding and text contains an invalid UTF-8 sequence,
+        zero is returned.
+
+        If maxGlyphCount is not sufficient to store all the glyphs, no glyphs are copied.
+        The total glyph count is returned for subsequent buffer reallocation.
+
+        @param text          character storage encoded with SkPaint::TextEncoding
+        @param byteLength    length of character storage in bytes
+        @param encoding      one of: kUTF8_SkTextEncoding, kUTF16_SkTextEncoding,
+                             kUTF32_SkTextEncoding, kGlyphID_SkTextEncoding
+        @param glyphs        storage for glyph indices; may be nullptr
+        @param maxGlyphCount storage capacity
+        @return              number of glyphs represented by text of length byteLength
+    */
+    int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding,
+                     SkGlyphID glyphs[], int maxGlyphCount) const;
+
+    /** Returns glyph index for Unicode character.
+
+        @param uni  Unicode character
+        @return     glyph index
+    */
+    uint16_t unicharToGlyph(SkUnichar uni) const {
+        return fTypeface->unicharToGlyph(uni);
+    }
+
+    /** Returns number of glyphs represented by text.
+
+        @param text          character storage encoded with SkPaint::TextEncoding
+        @param byteLength    length of character storage in bytes
+        @param encoding      one of: kUTF8_SkTextEncoding, kUTF16_SkTextEncoding,
+                             kUTF32_SkTextEncoding, kGlyphID_SkTextEncoding
+        @return              number of glyphs represented by text of length byteLength
+    */
+    int countText(const void* text, size_t byteLength, SkTextEncoding encoding) const {
+        return this->textToGlyphs(text, byteLength, encoding, nullptr, 0);
+    }
+
+    /** Returns true if all text corresponds to a non-zero glyph index.
+        Returns false if any characters in text are not supported in
+        SkTypeface.
+
+        If SkTextEncoding is kGlyphID_SkTextEncoding,
+        returns true if all glyph indices in text are non-zero;
+        does not check to see if text contains valid glyph indices for SkTypeface.
+
+        Returns true if byteLength is zero.
+
+        @param text        array of characters or glyphs
+        @param byteLength  number of bytes in text array
+        @param encoding    text encoding
+        @return            true if all text corresponds to a non-zero glyph index
+     */
+    bool containsText(const void* text, size_t byteLength, SkTextEncoding encoding) const;
+
+    /** Returns the advance width of text.
+        The advance is the normal distance to move before drawing additional text.
+        Returns the bounding box of text if bounds is not nullptr.
+
+        @param text        character storage encoded with SkPaint::TextEncoding
+        @param byteLength  length of character storage in bytes
+        @param encoding    one of: kUTF8_SkTextEncoding, kUTF16_SkTextEncoding,
+                           kUTF32_SkTextEncoding, kGlyphID_SkTextEncoding
+        @param bounds      returns bounding box relative to (0, 0) if not nullptr
+        @return            number of glyphs represented by text of length byteLength
+    */
+    SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding encoding,
+                         SkRect* bounds = nullptr) const;
+
+    /** DEPRECATED
+        Retrieves the advance and bounds for each glyph in glyphs.
+        Both widths and bounds may be nullptr.
+        If widths is not nullptr, widths must be an array of count entries.
+        if bounds is not nullptr, bounds must be an array of count entries.
+
+        @param glyphs      array of glyph indices to be measured
+        @param count       number of glyphs
+        @param widths      returns text advances for each glyph; may be nullptr
+        @param bounds      returns bounds for each glyph relative to (0, 0); may be nullptr
+    */
+    void getWidths(const uint16_t glyphs[], int count, SkScalar widths[], SkRect bounds[]) const {
+        this->getWidthsBounds(glyphs, count, widths, bounds, nullptr);
+    }
+
+    // DEPRECATED
+    void getWidths(const uint16_t glyphs[], int count, SkScalar widths[], std::nullptr_t) const {
+        this->getWidths(glyphs, count, widths);
+    }
+
+    /** Experimental
+        Retrieves the advance and bounds for each glyph in glyphs.
+        Both widths and bounds may be nullptr.
+        If widths is not nullptr, widths must be an array of count entries.
+        if bounds is not nullptr, bounds must be an array of count entries.
+
+        @param glyphs      array of glyph indices to be measured
+        @param count       number of glyphs
+        @param widths      returns text advances for each glyph
+     */
+    void getWidths(const uint16_t glyphs[], int count, SkScalar widths[]) const {
+        this->getWidthsBounds(glyphs, count, widths, nullptr, nullptr);
+    }
+
+    /** Experimental.
+        Retrieves the advance and bounds for each glyph in glyphs.
+        Both widths and bounds may be nullptr.
+        If widths is not nullptr, widths must be an array of count entries.
+        if bounds is not nullptr, bounds must be an array of count entries.
+
+        @param glyphs      array of glyph indices to be measured
+        @param count       number of glyphs
+        @param widths      returns text advances for each glyph; may be nullptr
+        @param bounds      returns bounds for each glyph relative to (0, 0); may be nullptr
+        @param paint       optional, specifies stroking, patheffect and maskfilter
+     */
+    void getWidthsBounds(const uint16_t glyphs[], int count, SkScalar widths[], SkRect bounds[],
+                         const SkPaint* paint) const;
+
+
+    /** Experimental.
+        Retrieves the bounds for each glyph in glyphs.
+        bounds must be an array of count entries.
+        If paint is not nullptr, its stroking, patheffect and maskfilter fields will be respected.
+
+        @param glyphs      array of glyph indices to be measured
+        @param count       number of glyphs
+        @param bounds      returns bounds for each glyph relative to (0, 0); may be nullptr
+        @param paint       optional, specifies stroking, patheffect and maskfilter
+     */
+    void getBounds(const uint16_t glyphs[], int count, SkRect bounds[], const SkPaint* paint) const {
+        this->getWidthsBounds(glyphs, count, nullptr, bounds, paint);
+    }
+
+    /** Experimental
+        Retrieves the positions for each glyph, beginning at the specified origin. The caller
+        must allocated at least count number of elements in the pos[] array.
+
+        @param glyphs   array of glyph indices to be positioned
+        @param count    number of glyphs
+        @param pos      returns glyphs positions
+        @param origin   location of the first glyph. Defaults to {0, 0}.
+     */
+    void getPos(const uint16_t glyphs[], int count, SkPoint pos[], SkPoint origin = {0, 0}) const;
+
+    /** Experimental
+        Retrieves the x-positions for each glyph, beginning at the specified origin. The caller
+        must allocated at least count number of elements in the xpos[] array.
+
+        @param glyphs   array of glyph indices to be positioned
+        @param count    number of glyphs
+        @param xpos     returns glyphs x-positions
+        @param origin   x-position of the first glyph. Defaults to 0.
+     */
+    void getXPos(const uint16_t glyphs[], int count, SkScalar xpos[], SkScalar origin = 0) const;
+
+    /** Returns path corresponding to glyph outline.
+        If glyph has an outline, copies outline to path and returns true.
+        path returned may be empty.
+        If glyph is described by a bitmap, returns false and ignores path parameter.
+
+        @param glyphID  index of glyph
+        @param path     pointer to existing SkPath
+        @return         true if glyphID is described by path
+     */
+    bool getPath(uint16_t glyphID, SkPath* path) const;
+
+    /** Returns path corresponding to glyph array.
+
+        @param glyphIDs      array of glyph indices
+        @param count         number of glyphs
+        @param glyphPathProc function returning one glyph description as path
+        @param ctx           function context
+   */
+    void getPaths(const uint16_t glyphIDs[], int count,
+                  void (*glyphPathProc)(const SkPath* pathOrNull, const SkMatrix& mx, void* ctx),
+                  void* ctx) const;
+
+    /** Returns SkFontMetrics associated with SkTypeface.
+        The return value is the recommended spacing between lines: the sum of metrics
+        descent, ascent, and leading.
+        If metrics is not nullptr, SkFontMetrics is copied to metrics.
+        Results are scaled by text size but does not take into account
+        dimensions required by text scale, text skew, fake bold,
+        style stroke, and SkPathEffect.
+
+        @param metrics  storage for SkFontMetrics; may be nullptr
+        @return         recommended spacing between lines
+    */
+    SkScalar getMetrics(SkFontMetrics* metrics) const;
+
+    /** Returns the recommended spacing between lines: the sum of metrics
+        descent, ascent, and leading.
+        Result is scaled by text size but does not take into account
+        dimensions required by stroking and SkPathEffect.
+        Returns the same result as getMetrics().
+
+        @return  recommended spacing between lines
+    */
+    SkScalar getSpacing() const { return this->getMetrics(nullptr); }
+
+    /** Deprecated.
+    */
+    void LEGACY_applyToPaint(SkPaint* paint) const;
+    /** Deprecated.
+     */
+    void LEGACY_applyPaintFlags(uint32_t paintFlags);
+    /** Deprecated.
+    */
+    static SkFont LEGACY_ExtractFromPaint(const SkPaint& paint);
+
+private:
+    enum PrivFlags {
+        kForceAutoHinting_PrivFlag      = 1 << 0,
+        kEmbeddedBitmaps_PrivFlag       = 1 << 1,
+        kSubpixel_PrivFlag              = 1 << 2,
+        kLinearMetrics_PrivFlag         = 1 << 3,
+        kEmbolden_PrivFlag              = 1 << 4,
+    };
+
+    static constexpr unsigned kAllFlags = 0x07F;
+
+    sk_sp<SkTypeface> fTypeface;
+    SkScalar    fSize;
+    SkScalar    fScaleX;
+    SkScalar    fSkewX;
+    uint8_t     fFlags;
+    uint8_t     fEdging;
+    uint8_t     fHinting;
+
+    SkScalar setupForAsPaths(SkPaint*);
+
+    friend class SkCanonicalizeFont;
+};
+
+#endif

+ 79 - 0
skia/include/core/SkFontArguments.h

@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontArguments_DEFINED
+#define SkFontArguments_DEFINED
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+/** Represents a set of actual arguments for a font. */
+struct SkFontArguments {
+    struct VariationPosition {
+        struct Coordinate {
+            SkFourByteTag axis;
+            float value;
+        };
+        const Coordinate* coordinates;
+        int coordinateCount;
+    };
+    // deprecated, use VariationPosition::Coordinate instead
+    struct Axis {
+       SkFourByteTag fTag;
+       float fStyleValue;
+    };
+
+    SkFontArguments() : fCollectionIndex(0), fVariationDesignPosition{nullptr, 0} {}
+
+    /** Specify the index of the desired font.
+     *
+     *  Font formats like ttc, dfont, cff, cid, pfr, t42, t1, and fon may actually be indexed
+     *  collections of fonts.
+     */
+    SkFontArguments& setCollectionIndex(int collectionIndex) {
+        fCollectionIndex = collectionIndex;
+        return *this;
+    }
+
+    // deprecated, use setVariationDesignPosition instead.
+    SkFontArguments& setAxes(const Axis* axes, int axisCount) {
+        fVariationDesignPosition.coordinates =
+                reinterpret_cast<const VariationPosition::Coordinate*>(axes);
+        fVariationDesignPosition.coordinateCount = axisCount;
+        return *this;
+    }
+
+    /** Specify a position in the variation design space.
+     *
+     *  Any axis not specified will use the default value.
+     *  Any specified axis not actually present in the font will be ignored.
+     *
+     *  @param position not copied. The value must remain valid for life of SkFontArguments.
+     */
+    SkFontArguments& setVariationDesignPosition(VariationPosition position) {
+        fVariationDesignPosition.coordinates = position.coordinates;
+        fVariationDesignPosition.coordinateCount = position.coordinateCount;
+        return *this;
+    }
+
+    int getCollectionIndex() const {
+        return fCollectionIndex;
+    }
+    // deprecated, use getVariationDesignPosition instead.
+    const Axis* getAxes(int* axisCount) const {
+        *axisCount = fVariationDesignPosition.coordinateCount;
+        return reinterpret_cast<const Axis*>(fVariationDesignPosition.coordinates);
+    }
+    VariationPosition getVariationDesignPosition() const {
+        return fVariationDesignPosition;
+    }
+private:
+    int fCollectionIndex;
+    VariationPosition fVariationDesignPosition;
+};
+
+#endif

+ 58 - 0
skia/include/core/SkFontLCDConfig.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontLCDConfig_DEFINED
+#define SkFontLCDConfig_DEFINED
+
+#include "SkTypes.h"
+
+class SK_API SkFontLCDConfig {
+public:
+    /** LCDs either have their color elements arranged horizontally or
+        vertically. When rendering subpixel glyphs we need to know which way
+        round they are.
+
+        Note, if you change this after startup, you'll need to flush the glyph
+        cache because it'll have the wrong type of masks cached.
+
+        @deprecated use SkPixelGeometry instead.
+    */
+    enum LCDOrientation {
+        kHorizontal_LCDOrientation = 0,    //!< this is the default
+        kVertical_LCDOrientation   = 1,
+    };
+
+    /** @deprecated set on Device creation. */
+    static void SetSubpixelOrientation(LCDOrientation orientation);
+    /** @deprecated get from Device. */
+    static LCDOrientation GetSubpixelOrientation();
+
+    /** LCD color elements can vary in order. For subpixel text we need to know
+        the order which the LCDs uses so that the color fringes are in the
+        correct place.
+
+        Note, if you change this after startup, you'll need to flush the glyph
+        cache because it'll have the wrong type of masks cached.
+
+        kNONE_LCDOrder means that the subpixel elements are not spatially
+        separated in any usable fashion.
+
+        @deprecated use SkPixelGeometry instead.
+     */
+    enum LCDOrder {
+        kRGB_LCDOrder = 0,    //!< this is the default
+        kBGR_LCDOrder = 1,
+        kNONE_LCDOrder = 2,
+    };
+
+    /** @deprecated set on Device creation. */
+    static void SetSubpixelOrder(LCDOrder order);
+    /** @deprecated get from Device. */
+    static LCDOrder GetSubpixelOrder();
+};
+
+#endif

+ 106 - 0
skia/include/core/SkFontMetrics.h

@@ -0,0 +1,106 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontMetrics_DEFINED
+#define SkFontMetrics_DEFINED
+
+#include "SkScalar.h"
+
+struct SK_API SkFontMetrics {
+
+    /** \enum FontMetricsFlags
+     FontMetricsFlags are set in fFlags when underline and strikeout metrics are valid;
+     the underline or strikeout metric may be valid and zero.
+     Fonts with embedded bitmaps may not have valid underline or strikeout metrics.
+     */
+    enum FontMetricsFlags {
+        kUnderlineThicknessIsValid_Flag = 1 << 0, //!< set if fUnderlineThickness is valid
+        kUnderlinePositionIsValid_Flag  = 1 << 1, //!< set if fUnderlinePosition is valid
+        kStrikeoutThicknessIsValid_Flag = 1 << 2, //!< set if fStrikeoutThickness is valid
+        kStrikeoutPositionIsValid_Flag  = 1 << 3, //!< set if fStrikeoutPosition is valid
+    };
+
+    uint32_t fFlags;              //!< is set to FontMetricsFlags when metrics are valid
+    SkScalar fTop;                //!< extent above baseline
+    SkScalar fAscent;             //!< distance to reserve above baseline
+    SkScalar fDescent;            //!< distance to reserve below baseline
+    SkScalar fBottom;             //!< extent below baseline
+    SkScalar fLeading;            //!< distance to add between lines
+    SkScalar fAvgCharWidth;       //!< average character width
+    SkScalar fMaxCharWidth;       //!< maximum character width
+    SkScalar fXMin;               //!< minimum x
+    SkScalar fXMax;               //!< maximum x
+    SkScalar fXHeight;            //!< height of lower-case 'x'
+    SkScalar fCapHeight;          //!< height of an upper-case letter
+    SkScalar fUnderlineThickness; //!< underline thickness
+    SkScalar fUnderlinePosition;  //!< underline position relative to baseline
+    SkScalar fStrikeoutThickness; //!< strikeout thickness
+    SkScalar fStrikeoutPosition;  //!< strikeout position relative to baseline
+
+    /** Returns true if SkFontMetrics has a valid underline thickness, and sets
+     thickness to that value. If the underline thickness is not valid,
+     return false, and ignore thickness.
+
+     @param thickness  storage for underline width
+     @return           true if font specifies underline width
+     */
+    bool hasUnderlineThickness(SkScalar* thickness) const {
+        if (SkToBool(fFlags & kUnderlineThicknessIsValid_Flag)) {
+            *thickness = fUnderlineThickness;
+            return true;
+        }
+        return false;
+    }
+
+    /** Returns true if SkFontMetrics has a valid underline position, and sets
+     position to that value. If the underline position is not valid,
+     return false, and ignore position.
+
+     @param position  storage for underline position
+     @return          true if font specifies underline position
+     */
+    bool hasUnderlinePosition(SkScalar* position) const {
+        if (SkToBool(fFlags & kUnderlinePositionIsValid_Flag)) {
+            *position = fUnderlinePosition;
+            return true;
+        }
+        return false;
+    }
+
+    /** Returns true if SkFontMetrics has a valid strikeout thickness, and sets
+     thickness to that value. If the underline thickness is not valid,
+     return false, and ignore thickness.
+
+     @param thickness  storage for strikeout width
+     @return           true if font specifies strikeout width
+     */
+    bool hasStrikeoutThickness(SkScalar* thickness) const {
+        if (SkToBool(fFlags & kStrikeoutThicknessIsValid_Flag)) {
+            *thickness = fStrikeoutThickness;
+            return true;
+        }
+        return false;
+    }
+
+    /** Returns true if SkFontMetrics has a valid strikeout position, and sets
+     position to that value. If the underline position is not valid,
+     return false, and ignore position.
+
+     @param position  storage for strikeout position
+     @return          true if font specifies strikeout position
+     */
+    bool hasStrikeoutPosition(SkScalar* position) const {
+        if (SkToBool(fFlags & kStrikeoutPositionIsValid_Flag)) {
+            *position = fStrikeoutPosition;
+            return true;
+        }
+        return false;
+    }
+
+};
+
+#endif

+ 163 - 0
skia/include/core/SkFontMgr.h

@@ -0,0 +1,163 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontMgr_DEFINED
+#define SkFontMgr_DEFINED
+
+#include "SkFontArguments.h"
+#include "SkFontStyle.h"
+#include "SkRefCnt.h"
+#include "SkTypes.h"
+
+class SkData;
+class SkFontData;
+class SkStreamAsset;
+class SkString;
+class SkTypeface;
+
+class SK_API SkFontStyleSet : public SkRefCnt {
+public:
+    virtual int count() = 0;
+    virtual void getStyle(int index, SkFontStyle*, SkString* style) = 0;
+    virtual SkTypeface* createTypeface(int index) = 0;
+    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) = 0;
+
+    static SkFontStyleSet* CreateEmpty();
+
+protected:
+    SkTypeface* matchStyleCSS3(const SkFontStyle& pattern);
+
+private:
+    typedef SkRefCnt INHERITED;
+};
+
+class SK_API SkFontMgr : public SkRefCnt {
+public:
+    int countFamilies() const;
+    void getFamilyName(int index, SkString* familyName) const;
+    SkFontStyleSet* createStyleSet(int index) const;
+
+    /**
+     *  The caller must call unref() on the returned object.
+     *  Never returns NULL; will return an empty set if the name is not found.
+     *
+     *  Passing nullptr as the parameter will return the default system family.
+     *  Note that most systems don't have a default system family, so passing nullptr will often
+     *  result in the empty set.
+     *
+     *  It is possible that this will return a style set not accessible from
+     *  createStyleSet(int) due to hidden or auto-activated fonts.
+     */
+    SkFontStyleSet* matchFamily(const char familyName[]) const;
+
+    /**
+     *  Find the closest matching typeface to the specified familyName and style
+     *  and return a ref to it. The caller must call unref() on the returned
+     *  object. Will return nullptr if no 'good' match is found.
+     *
+     *  Passing |nullptr| as the parameter for |familyName| will return the
+     *  default system font.
+     *
+     *  It is possible that this will return a style set not accessible from
+     *  createStyleSet(int) or matchFamily(const char[]) due to hidden or
+     *  auto-activated fonts.
+     */
+    SkTypeface* matchFamilyStyle(const char familyName[], const SkFontStyle&) const;
+
+    /**
+     *  Use the system fallback to find a typeface for the given character.
+     *  Note that bcp47 is a combination of ISO 639, 15924, and 3166-1 codes,
+     *  so it is fine to just pass a ISO 639 here.
+     *
+     *  Will return NULL if no family can be found for the character
+     *  in the system fallback.
+     *
+     *  Passing |nullptr| as the parameter for |familyName| will return the
+     *  default system font.
+     *
+     *  bcp47[0] is the least significant fallback, bcp47[bcp47Count-1] is the
+     *  most significant. If no specified bcp47 codes match, any font with the
+     *  requested character will be matched.
+     */
+    SkTypeface* matchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
+                                          const char* bcp47[], int bcp47Count,
+                                          SkUnichar character) const;
+
+    SkTypeface* matchFaceStyle(const SkTypeface*, const SkFontStyle&) const;
+
+    /**
+     *  Create a typeface for the specified data and TTC index (pass 0 for none)
+     *  or NULL if the data is not recognized. The caller must call unref() on
+     *  the returned object if it is not null.
+     */
+    sk_sp<SkTypeface> makeFromData(sk_sp<SkData>, int ttcIndex = 0) const;
+
+    /**
+     *  Create a typeface for the specified stream and TTC index
+     *  (pass 0 for none) or NULL if the stream is not recognized. The caller
+     *  must call unref() on the returned object if it is not null.
+     */
+    sk_sp<SkTypeface> makeFromStream(std::unique_ptr<SkStreamAsset>, int ttcIndex = 0) const;
+
+    /* Experimental, API subject to change. */
+    sk_sp<SkTypeface> makeFromStream(std::unique_ptr<SkStreamAsset>, const SkFontArguments&) const;
+
+    /**
+     *  Create a typeface from the specified font data.
+     *  Will return NULL if the typeface could not be created.
+     *  The caller must call unref() on the returned object if it is not null.
+     */
+    sk_sp<SkTypeface> makeFromFontData(std::unique_ptr<SkFontData>) const;
+
+    /**
+     *  Create a typeface for the specified fileName and TTC index
+     *  (pass 0 for none) or NULL if the file is not found, or its contents are
+     *  not recognized. The caller must call unref() on the returned object
+     *  if it is not null.
+     */
+    sk_sp<SkTypeface> makeFromFile(const char path[], int ttcIndex = 0) const;
+
+    sk_sp<SkTypeface> legacyMakeTypeface(const char familyName[], SkFontStyle style) const;
+
+    /** Return the default fontmgr. */
+    static sk_sp<SkFontMgr> RefDefault();
+
+protected:
+    virtual int onCountFamilies() const = 0;
+    virtual void onGetFamilyName(int index, SkString* familyName) const = 0;
+    virtual SkFontStyleSet* onCreateStyleSet(int index)const  = 0;
+
+    /** May return NULL if the name is not found. */
+    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const = 0;
+
+    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
+                                           const SkFontStyle&) const = 0;
+    virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
+                                                    const char* bcp47[], int bcp47Count,
+                                                    SkUnichar character) const = 0;
+    virtual SkTypeface* onMatchFaceStyle(const SkTypeface*,
+                                         const SkFontStyle&) const = 0;
+
+    virtual sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData>, int ttcIndex) const = 0;
+    virtual sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset>,
+                                                    int ttcIndex) const = 0;
+    virtual sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset>,
+                                                   const SkFontArguments&) const;
+    virtual sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData>) const;
+    virtual sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const = 0;
+
+    virtual sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle) const = 0;
+
+private:
+
+    /** Implemented by porting layer to return the default factory. */
+    static sk_sp<SkFontMgr> Factory();
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 38 - 0
skia/include/core/SkFontParameters.h

@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontParameters_DEFINED
+#define SkFontParameters_DEFINED
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+struct SkFontParameters {
+    struct Variation {
+        // Parameters in a variation font axis.
+        struct Axis {
+            // Four character identifier of the font axis (weight, width, slant, italic...).
+            SkFourByteTag tag;
+            // Minimum value supported by this axis.
+            float min;
+            // Default value set by this axis.
+            float def;
+            // Maximum value supported by this axis. The maximum can equal the minimum.
+            float max;
+            // Return whether this axis is recommended to be remain hidden in user interfaces.
+            bool isHidden() const { return flags & HIDDEN; }
+            // Set this axis to be remain hidden in user interfaces.
+            void setHidden(bool hidden) { flags = hidden ? (flags | HIDDEN) : (flags & ~HIDDEN); }
+        private:
+            static constexpr uint16_t HIDDEN = 0x0001;
+            // Attributes for a font axis.
+            uint16_t flags;
+        };
+    };
+};
+
+#endif

+ 80 - 0
skia/include/core/SkFontStyle.h

@@ -0,0 +1,80 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontStyle_DEFINED
+#define SkFontStyle_DEFINED
+
+#include "SkTypes.h"
+
+class SK_API SkFontStyle {
+public:
+    enum Weight {
+        kInvisible_Weight   =    0,
+        kThin_Weight        =  100,
+        kExtraLight_Weight  =  200,
+        kLight_Weight       =  300,
+        kNormal_Weight      =  400,
+        kMedium_Weight      =  500,
+        kSemiBold_Weight    =  600,
+        kBold_Weight        =  700,
+        kExtraBold_Weight   =  800,
+        kBlack_Weight       =  900,
+        kExtraBlack_Weight  = 1000,
+    };
+
+    enum Width {
+        kUltraCondensed_Width   = 1,
+        kExtraCondensed_Width   = 2,
+        kCondensed_Width        = 3,
+        kSemiCondensed_Width    = 4,
+        kNormal_Width           = 5,
+        kSemiExpanded_Width     = 6,
+        kExpanded_Width         = 7,
+        kExtraExpanded_Width    = 8,
+        kUltraExpanded_Width    = 9,
+    };
+
+    enum Slant {
+        kUpright_Slant,
+        kItalic_Slant,
+        kOblique_Slant,
+    };
+
+    constexpr SkFontStyle(int weight, int width, Slant slant) : fValue(
+        (SkTPin<int>(weight, kInvisible_Weight, kExtraBlack_Weight)) +
+        (SkTPin<int>(width, kUltraCondensed_Width, kUltraExpanded_Width) << 16) +
+        (SkTPin<int>(slant, kUpright_Slant, kOblique_Slant) << 24)
+     ) { }
+
+    constexpr SkFontStyle() : SkFontStyle{kNormal_Weight, kNormal_Width, kUpright_Slant} { }
+
+    bool operator==(const SkFontStyle& rhs) const {
+        return fValue == rhs.fValue;
+    }
+
+    int weight() const { return fValue & 0xFFFF; }
+    int width() const { return (fValue >> 16) & 0xFF; }
+    Slant slant() const { return (Slant)((fValue >> 24) & 0xFF); }
+
+    static constexpr SkFontStyle Normal() {
+        return SkFontStyle(kNormal_Weight, kNormal_Width, kUpright_Slant);
+    }
+    static constexpr SkFontStyle Bold() {
+        return SkFontStyle(kBold_Weight,   kNormal_Width, kUpright_Slant);
+    }
+    static constexpr SkFontStyle Italic() {
+        return SkFontStyle(kNormal_Weight, kNormal_Width, kItalic_Slant );
+    }
+    static constexpr SkFontStyle BoldItalic() {
+        return SkFontStyle(kBold_Weight,   kNormal_Width, kItalic_Slant );
+    }
+
+private:
+    uint32_t fValue;
+};
+
+#endif

+ 49 - 0
skia/include/core/SkFontTypes.h

@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkFontTypes_DEFINED
+#define SkFontTypes_DEFINED
+
+#include "SkScalar.h"
+#include "SkTypeface.h"
+
+// TODO: add to clients, and then remove from here.
+#define SK_SUPPORT_LEGACY_TEXTENCODINGENUM
+
+#ifdef SK_SUPPORT_LEGACY_TEXTENCODINGENUM
+enum SkTextEncoding : uint8_t {
+    kUTF8_SkTextEncoding,
+    kUTF16_SkTextEncoding,
+    kUTF32_SkTextEncoding,
+    kGlyphID_SkTextEncoding,
+};
+#else
+enum class SkTextEncoding {
+    kUTF8,
+    kUTF16,
+    kUTF32,
+    kGlyphID,
+};
+#define kUTF8_SkTextEncoding    SkTextEncoding::kUTF8
+#define kUTF16_SkTextEncoding   SkTextEncoding::kUTF16
+#define kUTF32_SkTextEncoding   SkTextEncoding::kUTF32
+#define kGlyphID_SkTextEncoding SkTextEncoding::kGlyphID
+#endif
+
+enum class SkFontHinting {
+    kNone,      //!< glyph outlines unchanged
+    kSlight,    //!< minimal modification to improve constrast
+    kNormal,    //!< glyph outlines modified to improve constrast
+    kFull,      //!< modifies glyph outlines for maximum constrast
+};
+
+#define kNo_SkFontHinting       SkFontHinting::kNone
+#define kSlight_SkFontHinting   SkFontHinting::kSlight
+#define kNormal_SkFontHinting   SkFontHinting::kNormal
+#define kFull_SkFontHinting     SkFontHinting::kFull
+
+#endif

+ 185 - 0
skia/include/core/SkGraphics.h

@@ -0,0 +1,185 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkGraphics_DEFINED
+#define SkGraphics_DEFINED
+
+#include "SkRefCnt.h"
+
+class SkData;
+class SkImageGenerator;
+class SkTraceMemoryDump;
+
+class SK_API SkGraphics {
+public:
+    /**
+     *  Call this at process initialization time if your environment does not
+     *  permit static global initializers that execute code.
+     *  Init() is thread-safe and idempotent.
+     */
+    static void Init();
+
+    // We're in the middle of cleaning this up.
+    static void Term() {}
+
+    /**
+     *  Return the version numbers for the library. If the parameter is not
+     *  null, it is set to the version number.
+     */
+    static void GetVersion(int32_t* major, int32_t* minor, int32_t* patch);
+
+    /**
+     *  Return the max number of bytes that should be used by the font cache.
+     *  If the cache needs to allocate more, it will purge previous entries.
+     *  This max can be changed by calling SetFontCacheLimit().
+     */
+    static size_t GetFontCacheLimit();
+
+    /**
+     *  Specify the max number of bytes that should be used by the font cache.
+     *  If the cache needs to allocate more, it will purge previous entries.
+     *
+     *  This function returns the previous setting, as if GetFontCacheLimit()
+     *  had be called before the new limit was set.
+     */
+    static size_t SetFontCacheLimit(size_t bytes);
+
+    /**
+     *  Return the number of bytes currently used by the font cache.
+     */
+    static size_t GetFontCacheUsed();
+
+    /**
+     *  Return the number of entries in the font cache.
+     *  A cache "entry" is associated with each typeface + pointSize + matrix.
+     */
+    static int GetFontCacheCountUsed();
+
+    /**
+     *  Return the current limit to the number of entries in the font cache.
+     *  A cache "entry" is associated with each typeface + pointSize + matrix.
+     */
+    static int GetFontCacheCountLimit();
+
+    /**
+     *  Set the limit to the number of entries in the font cache, and return
+     *  the previous value. If this new value is lower than the previous,
+     *  it will automatically try to purge entries to meet the new limit.
+     */
+    static int SetFontCacheCountLimit(int count);
+
+    /*
+     *  Returns the maximum point size for text that may be cached.
+     *
+     *  Sizes above this will be drawn directly from the font's outline.
+     *  Setting this to a large value may speed up drawing larger text (repeatedly),
+     *  but could cause the cache to purge other sizes more often.
+     *
+     *  This value is a hint to the font engine, and the actual limit may be different due to
+     *  implementation specific details.
+     */
+    static int GetFontCachePointSizeLimit();
+
+    /*
+     *  Set the maximum point size for text that may be cached, returning the previous value.
+     *
+     *  Sizes above this will be drawn directly from the font's outline.
+     *  Setting this to a large value may speed up drawing larger text (repeatedly),
+     *  but could cause the cache to purge other sizes more often.
+     *
+     *  This value is a hint to the font engine, and the actual limit may be different due to
+     *  implementation specific details.
+     */
+    static int SetFontCachePointSizeLimit(int maxPointSize);
+
+    /**
+     *  For debugging purposes, this will attempt to purge the font cache. It
+     *  does not change the limit, but will cause subsequent font measures and
+     *  draws to be recreated, since they will no longer be in the cache.
+     */
+    static void PurgeFontCache();
+
+    /**
+     *  Scaling bitmaps with the kHigh_SkFilterQuality setting is
+     *  expensive, so the result is saved in the global Scaled Image
+     *  Cache.
+     *
+     *  This function returns the memory usage of the Scaled Image Cache.
+     */
+    static size_t GetResourceCacheTotalBytesUsed();
+
+    /**
+     *  These functions get/set the memory usage limit for the resource cache, used for temporary
+     *  bitmaps and other resources. Entries are purged from the cache when the memory useage
+     *  exceeds this limit.
+     */
+    static size_t GetResourceCacheTotalByteLimit();
+    static size_t SetResourceCacheTotalByteLimit(size_t newLimit);
+
+    /**
+     *  For debugging purposes, this will attempt to purge the resource cache. It
+     *  does not change the limit.
+     */
+    static void PurgeResourceCache();
+
+    /**
+     *  When the cachable entry is very lage (e.g. a large scaled bitmap), adding it to the cache
+     *  can cause most/all of the existing entries to be purged. To avoid the, the client can set
+     *  a limit for a single allocation. If a cacheable entry would have been cached, but its size
+     *  exceeds this limit, then we do not attempt to cache it at all.
+     *
+     *  Zero is the default value, meaning we always attempt to cache entries.
+     */
+    static size_t GetResourceCacheSingleAllocationByteLimit();
+    static size_t SetResourceCacheSingleAllocationByteLimit(size_t newLimit);
+
+    /**
+     *  Dumps memory usage of caches using the SkTraceMemoryDump interface. See SkTraceMemoryDump
+     *  for usage of this method.
+     */
+    static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
+
+    /**
+     *  Free as much globally cached memory as possible. This will purge all private caches in Skia,
+     *  including font and image caches.
+     *
+     *  If there are caches associated with GPU context, those will not be affected by this call.
+     */
+    static void PurgeAllCaches();
+
+    /**
+     *  Applications with command line options may pass optional state, such
+     *  as cache sizes, here, for instance:
+     *  font-cache-limit=12345678
+     *
+     *  The flags format is name=value[;name=value...] with no spaces.
+     *  This format is subject to change.
+     */
+    static void SetFlags(const char* flags);
+
+    typedef std::unique_ptr<SkImageGenerator>
+                                            (*ImageGeneratorFromEncodedDataFactory)(sk_sp<SkData>);
+
+    /**
+     *  To instantiate images from encoded data, first looks at this runtime function-ptr. If it
+     *  exists, it is called to create an SkImageGenerator from SkData. If there is no function-ptr
+     *  or there is, but it returns NULL, then skia will call its internal default implementation.
+     *
+     *  Returns the previous factory (which could be NULL).
+     */
+    static ImageGeneratorFromEncodedDataFactory
+                    SetImageGeneratorFromEncodedDataFactory(ImageGeneratorFromEncodedDataFactory);
+};
+
+class SkAutoGraphics {
+public:
+    SkAutoGraphics() {
+        SkGraphics::Init();
+    }
+};
+
+#endif

+ 23 - 0
skia/include/core/SkICC.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkICC_DEFINED
+#define SkICC_DEFINED
+
+#include "SkData.h"
+#include "SkMatrix44.h"
+#include "SkRefCnt.h"
+
+struct SkColorSpaceTransferFn;
+
+SK_API sk_sp<SkData> SkWriteICCProfile(const SkColorSpaceTransferFn&, const float toXYZD50[9]);
+
+namespace SkICC {
+    SK_API sk_sp<SkData> WriteToICC(const SkColorSpaceTransferFn&, const SkMatrix44&);
+}
+
+#endif//SkICC_DEFINED

+ 1026 - 0
skia/include/core/SkImage.h

@@ -0,0 +1,1026 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkImage.h and docs/SkImage_Reference.bmh
+   on 2018-09-18 07:26:44. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkImage_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkImage_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkImage.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkImage_DEFINED
+#define SkImage_DEFINED
+
+#include "GrTypes.h"
+#include "SkFilterQuality.h"
+#include "SkImageInfo.h"
+#include "SkImageEncoder.h"
+#include "SkRefCnt.h"
+#include "SkScalar.h"
+#include "SkShader.h"
+
+#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
+#include <android/hardware_buffer.h>
+#endif
+
+class SkData;
+class SkCanvas;
+class SkImageFilter;
+class SkImageGenerator;
+class SkPaint;
+class SkPicture;
+class SkString;
+class SkSurface;
+class GrBackendTexture;
+class GrContext;
+class GrContextThreadSafeProxy;
+class GrTexture;
+
+struct SkYUVAIndex;
+
+/** \class SkImage
+    SkImage describes a two dimensional array of pixels to draw. The pixels may be
+    decoded in a raster bitmap, encoded in a SkPicture or compressed data stream,
+    or located in GPU memory as a GPU texture.
+
+    SkImage cannot be modified after it is created. SkImage may allocate additional
+    storage as needed; for instance, an encoded SkImage may decode when drawn.
+
+    SkImage width and height are greater than zero. Creating an SkImage with zero width
+    or height returns SkImage equal to nullptr.
+
+    SkImage may be created from SkBitmap, SkPixmap, SkSurface, SkPicture, encoded streams,
+    GPU texture, YUV_ColorSpace data, or hardware buffer. Encoded streams supported
+    include BMP, GIF, HEIF, ICO, JPEG, PNG, WBMP, WebP. Supported encoding details
+    vary with platform.
+*/
+class SK_API SkImage : public SkRefCnt {
+public:
+
+    /** Caller data passed to RasterReleaseProc; may be nullptr.
+    */
+    typedef void* ReleaseContext;
+
+    /** Creates SkImage from SkPixmap and copy of pixels. Since pixels are copied, SkPixmap
+        pixels may be modified or deleted without affecting SkImage.
+
+        SkImage is returned if SkPixmap is valid. Valid SkPixmap parameters include:
+        dimensions are greater than zero;
+        each dimension fits in 29 bits;
+        SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
+        row bytes are large enough to hold one row of pixels;
+        pixel address is not nullptr.
+
+        @param pixmap  SkImageInfo, pixel address, and row bytes
+        @return        copy of SkPixmap pixels, or nullptr
+    */
+    static sk_sp<SkImage> MakeRasterCopy(const SkPixmap& pixmap);
+
+    /** Creates SkImage from SkImageInfo, sharing pixels.
+
+        SkImage is returned if SkImageInfo is valid. Valid SkImageInfo parameters include:
+        dimensions are greater than zero;
+        each dimension fits in 29 bits;
+        SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
+        rowBytes are large enough to hold one row of pixels;
+        pixels is not nullptr, and contains enough data for SkImage.
+
+        @param info      contains width, height, SkAlphaType, SkColorType, SkColorSpace
+        @param pixels    address or pixel storage
+        @param rowBytes  size of pixel row or larger
+        @return          SkImage sharing pixels, or nullptr
+    */
+    static sk_sp<SkImage> MakeRasterData(const SkImageInfo& info, sk_sp<SkData> pixels,
+                                         size_t rowBytes);
+
+    /** Function called when SkImage no longer shares pixels. ReleaseContext is
+        provided by caller when SkImage is created, and may be nullptr.
+    */
+    typedef void (*RasterReleaseProc)(const void* pixels, ReleaseContext);
+
+    /** Creates SkImage from pixmap, sharing SkPixmap pixels. Pixels must remain valid and
+        unchanged until rasterReleaseProc is called. rasterReleaseProc is passed
+        releaseContext when SkImage is deleted or no longer refers to pixmap pixels.
+
+        Pass nullptr for rasterReleaseProc to share SkPixmap without requiring a callback
+        when SkImage is released. Pass nullptr for releaseContext if rasterReleaseProc
+        does not require state.
+
+        SkImage is returned if pixmap is valid. Valid SkPixmap parameters include:
+        dimensions are greater than zero;
+        each dimension fits in 29 bits;
+        SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
+        row bytes are large enough to hold one row of pixels;
+        pixel address is not nullptr.
+
+        @param pixmap             SkImageInfo, pixel address, and row bytes
+        @param rasterReleaseProc  function called when pixels can be released; or nullptr
+        @param releaseContext     state passed to rasterReleaseProc; or nullptr
+        @return                   SkImage sharing pixmap
+    */
+    static sk_sp<SkImage> MakeFromRaster(const SkPixmap& pixmap,
+                                         RasterReleaseProc rasterReleaseProc,
+                                         ReleaseContext releaseContext);
+
+    /** Creates SkImage from bitmap, sharing or copying bitmap pixels. If the bitmap
+        is marked immutable, and its pixel memory is shareable, it may be shared
+        instead of copied.
+
+        SkImage is returned if bitmap is valid. Valid SkBitmap parameters include:
+        dimensions are greater than zero;
+        each dimension fits in 29 bits;
+        SkColorType and SkAlphaType are valid, and SkColorType is not kUnknown_SkColorType;
+        row bytes are large enough to hold one row of pixels;
+        pixel address is not nullptr.
+
+        @param bitmap  SkImageInfo, row bytes, and pixels
+        @return        created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromBitmap(const SkBitmap& bitmap);
+
+    /** Creates SkImage from data returned by imageGenerator. Generated data is owned by SkImage and
+        may not be shared or accessed.
+
+        subset allows selecting a portion of the full image. Pass nullptr to select the entire
+        image; otherwise, subset must be contained by image bounds.
+
+        SkImage is returned if generator data is valid. Valid data parameters vary by type of data
+        and platform.
+
+        imageGenerator may wrap SkPicture data, codec data, or custom data.
+
+        @param imageGenerator  stock or custom routines to retrieve SkImage
+        @param subset          bounds of returned SkImage; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromGenerator(std::unique_ptr<SkImageGenerator> imageGenerator,
+                                            const SkIRect* subset = nullptr);
+
+    /** Creates SkImage from encoded data.
+        subset allows selecting a portion of the full image. Pass nullptr to select the entire
+        image; otherwise, subset must be contained by image bounds.
+
+        SkImage is returned if format of the encoded data is recognized and supported.
+        Recognized formats vary by platform.
+
+        @param encoded  data of SkImage to decode
+        @param subset   bounds of returned SkImage; may be nullptr
+        @return         created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset = nullptr);
+
+    /** User function called when supplied texture may be deleted.
+    */
+    typedef void (*TextureReleaseProc)(ReleaseContext releaseContext);
+
+    /** Creates SkImage from GPU texture associated with context. Caller is responsible for
+        managing the lifetime of GPU texture.
+
+        SkImage is returned if format of backendTexture is recognized and supported.
+        Recognized formats vary by GPU back-end.
+
+        @param context         GPU context
+        @param backendTexture  texture residing on GPU
+        @param origin          one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param colorType       one of:
+                               kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+                               kARGB_4444_SkColorType, kRGBA_8888_SkColorType,
+                               kRGB_888x_SkColorType, kBGRA_8888_SkColorType,
+                               kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+                               kGray_8_SkColorType, kRGBA_F16_SkColorType
+        @param alphaType       one of:
+                               kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                               kUnpremul_SkAlphaType
+        @param colorSpace      range of colors; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromTexture(GrContext* context,
+                                          const GrBackendTexture& backendTexture,
+                                          GrSurfaceOrigin origin,
+                                          SkColorType colorType,
+                                          SkAlphaType alphaType,
+                                          sk_sp<SkColorSpace> colorSpace) {
+        return MakeFromTexture(context, backendTexture, origin, colorType, alphaType, colorSpace,
+                               nullptr, nullptr);
+    }
+
+    /** Creates SkImage from GPU texture associated with context. GPU texture must stay
+        valid and unchanged until textureReleaseProc is called. textureReleaseProc is
+        passed releaseContext when SkImage is deleted or no longer refers to texture.
+
+        SkImage is returned if format of backendTexture is recognized and supported.
+        Recognized formats vary by GPU back-end.
+
+        @param context             GPU context
+        @param backendTexture      texture residing on GPU
+        @param origin              one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param colorType           one of:
+                                   kUnknown_SkColorType, kAlpha_8_SkColorType,
+                                   kRGB_565_SkColorType, kARGB_4444_SkColorType,
+                                   kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+                                   kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType,
+                                   kRGB_101010x_SkColorType, kGray_8_SkColorType,
+                                   kRGBA_F16_SkColorType
+        @param alphaType           one of:
+                                   kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                                   kUnpremul_SkAlphaType
+        @param colorSpace          range of colors; may be nullptr
+        @param textureReleaseProc  function called when texture can be released
+        @param releaseContext      state passed to textureReleaseProc
+        @return                    created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromTexture(GrContext* context,
+                                          const GrBackendTexture& backendTexture,
+                                          GrSurfaceOrigin origin,
+                                          SkColorType colorType,
+                                          SkAlphaType alphaType,
+                                          sk_sp<SkColorSpace> colorSpace,
+                                          TextureReleaseProc textureReleaseProc,
+                                          ReleaseContext releaseContext);
+
+    /** Creates SkImage from encoded data. SkImage is uploaded to GPU back-end using context.
+
+        Created SkImage is available to other GPU contexts, and is available across thread
+        boundaries. All contexts must be in the same GPU share group, or otherwise
+        share resources.
+
+        When SkImage is no longer referenced, context releases texture memory
+        asynchronously.
+
+        GrBackendTexture decoded from data is uploaded to match SkSurface created with
+        dstColorSpace. SkColorSpace of SkImage is determined by encoded data.
+
+        SkImage is returned if format of data is recognized and supported, and if context
+        supports moving resources. Recognized formats vary by platform and GPU back-end.
+
+        SkImage is returned using MakeFromEncoded() if context is nullptr or does not support
+        moving resources between contexts.
+
+        @param context                GPU context
+        @param data                   SkImage to decode
+        @param buildMips              create SkImage as mip map if true
+        @param dstColorSpace          range of colors of matching SkSurface on GPU
+        @param limitToMaxTextureSize  downscale image to GPU maximum texture size, if necessary
+        @return                       created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeCrossContextFromEncoded(GrContext* context, sk_sp<SkData> data,
+                                                      bool buildMips, SkColorSpace* dstColorSpace,
+                                                      bool limitToMaxTextureSize = false);
+
+    /** Creates SkImage from pixmap. SkImage is uploaded to GPU back-end using context.
+
+        Created SkImage is available to other GPU contexts, and is available across thread
+        boundaries. All contexts must be in the same GPU share group, or otherwise
+        share resources.
+
+        When SkImage is no longer referenced, context releases texture memory
+        asynchronously.
+
+        GrBackendTexture created from pixmap is uploaded to match SkSurface created with
+        dstColorSpace. SkColorSpace of SkImage is determined by pixmap.colorSpace().
+
+        SkImage is returned referring to GPU back-end if context is not nullptr,
+        format of data is recognized and supported, and if context supports moving
+        resources between contexts. Otherwise, pixmap pixel data is copied and SkImage
+        as returned in raster format if possible; nullptr may be returned.
+        Recognized GPU formats vary by platform and GPU back-end.
+
+        @param context                GPU context
+        @param pixmap                 SkImageInfo, pixel address, and row bytes
+        @param buildMips              create SkImage as mip map if true
+        @param dstColorSpace          range of colors of matching SkSurface on GPU
+        @param limitToMaxTextureSize  downscale image to GPU maximum texture size, if necessary
+        @return                       created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeCrossContextFromPixmap(GrContext* context, const SkPixmap& pixmap,
+                                                     bool buildMips, SkColorSpace* dstColorSpace,
+                                                     bool limitToMaxTextureSize = false);
+
+    /** Creates SkImage from backendTexture associated with context. backendTexture and
+        returned SkImage are managed internally, and are released when no longer needed.
+
+        SkImage is returned if format of backendTexture is recognized and supported.
+        Recognized formats vary by GPU back-end.
+
+        @param context         GPU context
+        @param backendTexture  texture residing on GPU
+        @param surfaceOrigin   one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param colorType       one of:
+                               kUnknown_SkColorType, kAlpha_8_SkColorType,
+                               kRGB_565_SkColorType, kARGB_4444_SkColorType,
+                               kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+                               kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType,
+                               kRGB_101010x_SkColorType, kGray_8_SkColorType,
+                               kRGBA_F16_SkColorType
+        @param alphaType       one of:
+                               kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                               kUnpremul_SkAlphaType
+        @param colorSpace      range of colors; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromAdoptedTexture(GrContext* context,
+                                                 const GrBackendTexture& backendTexture,
+                                                 GrSurfaceOrigin surfaceOrigin,
+                                                 SkColorType colorType,
+                                                 SkAlphaType alphaType = kPremul_SkAlphaType,
+                                                 sk_sp<SkColorSpace> colorSpace = nullptr);
+
+    /** Creates an SkImage by flattening the specified YUVA planes into a single, interleaved RGBA
+        image.
+
+        @param context         GPU context
+        @param yuvColorSpace   How the YUV values are converted to RGB. One of:
+                                           kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                                           kRec709_SkYUVColorSpace
+        @param yuvaTextures    array of (up to four) YUVA textures on GPU which contain the,
+                               possibly interleaved, YUVA planes
+        @param yuvaIndices     array indicating which texture in yuvaTextures, and channel
+                               in that texture, maps to each component of YUVA.
+        @param imageSize       size of the resulting image
+        @param imageOrigin     origin of the resulting image. One of: kBottomLeft_GrSurfaceOrigin,
+                               kTopLeft_GrSurfaceOrigin
+        @param imageColorSpace range of colors of the resulting image; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromYUVATexturesCopy(GrContext* context,
+                                                   SkYUVColorSpace yuvColorSpace,
+                                                   const GrBackendTexture yuvaTextures[],
+                                                   const SkYUVAIndex yuvaIndices[4],
+                                                   SkISize imageSize,
+                                                   GrSurfaceOrigin imageOrigin,
+                                                   sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** Creates an SkImage by flattening the specified YUVA planes into a single, interleaved RGBA
+        image. 'backendTexture' is used to store the result of the flattening.
+
+        @param context         GPU context
+        @param yuvColorSpace   How the YUV values are converted to RGB. One of:
+                                           kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                                           kRec709_SkYUVColorSpace
+        @param yuvaTextures    array of (up to four) YUVA textures on GPU which contain the,
+                               possibly interleaved, YUVA planes
+        @param yuvaIndices     array indicating which texture in yuvaTextures, and channel
+                               in that texture, maps to each component of YUVA.
+        @param imageSize       size of the resulting image
+        @param imageOrigin     origin of the resulting image. One of: kBottomLeft_GrSurfaceOrigin,
+                               kTopLeft_GrSurfaceOrigin
+        @param backendTexture  the resource that stores the final pixels
+        @param imageColorSpace range of colors of the resulting image; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromYUVATexturesCopyWithExternalBackend(
+            GrContext* context,
+            SkYUVColorSpace yuvColorSpace,
+            const GrBackendTexture yuvaTextures[],
+            const SkYUVAIndex yuvaIndices[4],
+            SkISize imageSize,
+            GrSurfaceOrigin imageOrigin,
+            const GrBackendTexture& backendTexture,
+            sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** Creates an SkImage by storing the specified YUVA planes into an image, to be rendered
+        via multitexturing.
+
+        @param context         GPU context
+        @param yuvColorSpace   How the YUV values are converted to RGB. One of:
+                                           kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                                           kRec709_SkYUVColorSpace
+        @param yuvaTextures    array of (up to four) YUVA textures on GPU which contain the,
+                               possibly interleaved, YUVA planes
+        @param yuvaIndices     array indicating which texture in yuvaTextures, and channel
+                               in that texture, maps to each component of YUVA.
+        @param imageSize       size of the resulting image
+        @param imageOrigin     origin of the resulting image. One of: kBottomLeft_GrSurfaceOrigin,
+                               kTopLeft_GrSurfaceOrigin
+        @param imageColorSpace range of colors of the resulting image; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromYUVATextures(GrContext* context,
+                                               SkYUVColorSpace yuvColorSpace,
+                                               const GrBackendTexture yuvaTextures[],
+                                               const SkYUVAIndex yuvaIndices[4],
+                                               SkISize imageSize,
+                                               GrSurfaceOrigin imageOrigin,
+                                               sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** Creates SkImage from pixmap array representing YUVA data.
+        SkImage is uploaded to GPU back-end using context.
+
+        Each GrBackendTexture created from yuvaPixmaps array is uploaded to match SkSurface
+        using SkColorSpace of SkPixmap. SkColorSpace of SkImage is determined by imageColorSpace.
+
+        SkImage is returned referring to GPU back-end if context is not nullptr and
+        format of data is recognized and supported. Otherwise, nullptr is returned.
+        Recognized GPU formats vary by platform and GPU back-end.
+
+        @param context                GPU context
+        @param yuvColorSpace          How the YUV values are converted to RGB. One of:
+                                            kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                                            kRec709_SkYUVColorSpace
+        @param yuvaPixmaps            array of (up to four) SkPixmap which contain the,
+                                      possibly interleaved, YUVA planes
+        @param yuvaIndices            array indicating which pixmap in yuvaPixmaps, and channel
+                                      in that pixmap, maps to each component of YUVA.
+        @param imageSize              size of the resulting image
+        @param imageOrigin            origin of the resulting image. One of:
+                                            kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param buildMips              create internal YUVA textures as mip map if true
+        @param limitToMaxTextureSize  downscale image to GPU maximum texture size, if necessary
+        @param imageColorSpace        range of colors of the resulting image; may be nullptr
+        @return                       created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromYUVAPixmaps(
+            GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[],
+            const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin,
+            bool buildMips, bool limitToMaxTextureSize = false,
+            sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** To be deprecated.
+    */
+    static sk_sp<SkImage> MakeFromYUVTexturesCopy(GrContext* context, SkYUVColorSpace yuvColorSpace,
+                                                  const GrBackendTexture yuvTextures[3],
+                                                  GrSurfaceOrigin imageOrigin,
+                                                  sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** To be deprecated.
+    */
+    static sk_sp<SkImage> MakeFromYUVTexturesCopyWithExternalBackend(
+            GrContext* context, SkYUVColorSpace yuvColorSpace,
+            const GrBackendTexture yuvTextures[3], GrSurfaceOrigin imageOrigin,
+            const GrBackendTexture& backendTexture, sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** Creates SkImage from copy of nv12Textures, an array of textures on GPU.
+        nv12Textures[0] contains pixels for YUV component y plane.
+        nv12Textures[1] contains pixels for YUV component u plane,
+        followed by pixels for YUV component v plane.
+        Returned SkImage has the dimensions nv12Textures[2].
+        yuvColorSpace describes how YUV colors convert to RGB colors.
+
+        @param context         GPU context
+        @param yuvColorSpace   one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                               kRec709_SkYUVColorSpace
+        @param nv12Textures    array of YUV textures on GPU
+        @param imageOrigin     one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param imageColorSpace range of colors; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromNV12TexturesCopy(GrContext* context,
+                                                   SkYUVColorSpace yuvColorSpace,
+                                                   const GrBackendTexture nv12Textures[2],
+                                                   GrSurfaceOrigin imageOrigin,
+                                                   sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    /** Creates SkImage from copy of nv12Textures, an array of textures on GPU.
+        nv12Textures[0] contains pixels for YUV component y plane.
+        nv12Textures[1] contains pixels for YUV component u plane,
+        followed by pixels for YUV component v plane.
+        Returned SkImage has the dimensions nv12Textures[2] and stores pixels in backendTexture.
+        yuvColorSpace describes how YUV colors convert to RGB colors.
+
+        @param context         GPU context
+        @param yuvColorSpace   one of: kJPEG_SkYUVColorSpace, kRec601_SkYUVColorSpace,
+                               kRec709_SkYUVColorSpace
+        @param nv12Textures    array of YUV textures on GPU
+        @param imageOrigin     one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @param backendTexture  the resource that stores the final pixels
+        @param imageColorSpace range of colors; may be nullptr
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromNV12TexturesCopyWithExternalBackend(
+            GrContext* context,
+            SkYUVColorSpace yuvColorSpace,
+            const GrBackendTexture nv12Textures[2],
+            GrSurfaceOrigin imageOrigin,
+            const GrBackendTexture& backendTexture,
+            sk_sp<SkColorSpace> imageColorSpace = nullptr);
+
+    enum class BitDepth {
+        kU8,  //!< uses 8-bit unsigned int per color component
+        kF16, //!< uses 16-bit float per color component
+    };
+
+    /** Creates SkImage from picture. Returned SkImage width and height are set by dimensions.
+        SkImage draws picture with matrix and paint, set to bitDepth and colorSpace.
+
+        If matrix is nullptr, draws with identity SkMatrix. If paint is nullptr, draws
+        with default SkPaint. colorSpace may be nullptr.
+
+        @param picture     stream of drawing commands
+        @param dimensions  width and height
+        @param matrix      SkMatrix to rotate, scale, translate, and so on; may be nullptr
+        @param paint       SkPaint to apply transparency, filtering, and so on; may be nullptr
+        @param bitDepth    8-bit integer or 16-bit float: per component
+        @param colorSpace  range of colors; may be nullptr
+        @return            created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
+                                          const SkMatrix* matrix, const SkPaint* paint,
+                                          BitDepth bitDepth,
+                                          sk_sp<SkColorSpace> colorSpace);
+
+#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
+    /** (See Skia bug 7447)
+        Creates SkImage from Android hardware buffer.
+        Returned SkImage takes a reference on the buffer.
+
+        Only available on Android, when __ANDROID_API__ is defined to be 26 or greater.
+
+        @param hardwareBuffer  AHardwareBuffer Android hardware buffer
+        @param alphaType       one of:
+                               kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                               kUnpremul_SkAlphaType
+        @param colorSpace      range of colors; may be nullptr
+        @param surfaceOrigin   one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin
+        @return                created SkImage, or nullptr
+    */
+    static sk_sp<SkImage> MakeFromAHardwareBuffer(
+            AHardwareBuffer* hardwareBuffer,
+            SkAlphaType alphaType = kPremul_SkAlphaType,
+            sk_sp<SkColorSpace> colorSpace = nullptr,
+            GrSurfaceOrigin surfaceOrigin = kTopLeft_GrSurfaceOrigin);
+#endif
+
+    /** Returns pixel count in each row.
+
+        @return  pixel width in SkImage
+    */
+    int width() const { return fWidth; }
+
+    /** Returns pixel row count.
+
+        @return  pixel height in SkImage
+    */
+    int height() const { return fHeight; }
+
+    /** Returns SkISize { width(), height() }.
+
+        @return  integral size of width() and height()
+    */
+    SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); }
+
+    /** Returns SkIRect { 0, 0, width(), height() }.
+
+        @return  integral rectangle from origin to width() and height()
+    */
+    SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); }
+
+    /** Returns value unique to image. SkImage contents cannot change after SkImage is
+        created. Any operation to create a new SkImage will receive generate a new
+        unique number.
+
+        @return  unique identifier
+    */
+    uint32_t uniqueID() const { return fUniqueID; }
+
+    /** Returns SkAlphaType, one of:
+        kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+        kUnpremul_SkAlphaType.
+
+        SkAlphaType returned was a parameter to an SkImage constructor,
+        or was parsed from encoded data.
+
+        @return  SkAlphaType in SkImage
+    */
+    SkAlphaType alphaType() const;
+
+    /** Returns SkColorType if known; otherwise, returns kUnknown_SkColorType.
+
+        @return  SkColorType of SkImage
+    */
+    SkColorType colorType() const;
+
+    /** Returns SkColorSpace, the range of colors, associated with SkImage.  The
+        reference count of SkColorSpace is unchanged. The returned SkColorSpace is
+        immutable.
+
+        SkColorSpace returned was passed to an SkImage constructor,
+        or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage
+        is drawn, depending on the capabilities of the SkSurface receiving the drawing.
+
+        @return  SkColorSpace in SkImage, or nullptr
+    */
+    SkColorSpace* colorSpace() const;
+
+    /** Returns a smart pointer to SkColorSpace, the range of colors, associated with
+        SkImage.  The smart pointer tracks the number of objects sharing this
+        SkColorSpace reference so the memory is released when the owners destruct.
+
+        The returned SkColorSpace is immutable.
+
+        SkColorSpace returned was passed to an SkImage constructor,
+        or was parsed from encoded data. SkColorSpace returned may be ignored when SkImage
+        is drawn, depending on the capabilities of the SkSurface receiving the drawing.
+
+        @return  SkColorSpace in SkImage, or nullptr, wrapped in a smart pointer
+    */
+    sk_sp<SkColorSpace> refColorSpace() const;
+
+    /** Returns true if SkImage pixels represent transparency only. If true, each pixel
+        is packed in 8 bits as defined by kAlpha_8_SkColorType.
+
+        @return  true if pixels represent a transparency mask
+    */
+    bool isAlphaOnly() const;
+
+    /** Returns true if pixels ignore their alpha value and are treated as fully opaque.
+
+        @return  true if SkAlphaType is kOpaque_SkAlphaType
+    */
+    bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); }
+
+    /** Creates SkShader from SkImage. SkShader dimensions are taken from SkImage. SkShader uses
+        SkShader::TileMode rules to fill drawn area outside SkImage. localMatrix permits
+        transforming SkImage before SkCanvas matrix is applied.
+
+        @param tileMode1    tiling on x-axis, one of: SkShader::kClamp_TileMode,
+                            SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode
+        @param tileMode2    tiling on y-axis, one of: SkShader::kClamp_TileMode,
+                            SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode
+        @param localMatrix  SkImage transformation, or nullptr
+        @return             SkShader containing SkImage
+    */
+    sk_sp<SkShader> makeShader(SkShader::TileMode tileMode1, SkShader::TileMode tileMode2,
+                               const SkMatrix* localMatrix = nullptr) const;
+
+    /** Creates SkShader from SkImage. SkShader dimensions are taken from SkImage. SkShader uses
+        SkShader::kClamp_TileMode to fill drawn area outside SkImage. localMatrix permits
+        transforming SkImage before SkCanvas matrix is applied.
+
+        @param localMatrix  SkImage transformation, or nullptr
+        @return             SkShader containing SkImage
+    */
+    sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const {
+        return this->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, localMatrix);
+    }
+
+    /** Copies SkImage pixel address, row bytes, and SkImageInfo to pixmap, if address
+        is available, and returns true. If pixel address is not available, return
+        false and leave pixmap unchanged.
+
+        @param pixmap  storage for pixel state if pixels are readable; otherwise, ignored
+        @return        true if SkImage has direct access to pixels
+    */
+    bool peekPixels(SkPixmap* pixmap) const;
+
+    /** Deprecated.
+    */
+    GrTexture* getTexture() const;
+
+    /** Returns true the contents of SkImage was created on or uploaded to GPU memory,
+        and is available as a GPU texture.
+
+        @return  true if SkImage is a GPU texture
+    */
+    bool isTextureBacked() const;
+
+    /** Returns true if SkImage can be drawn on either raster surface or GPU surface.
+        If context is nullptr, tests if SkImage draws on raster surface;
+        otherwise, tests if SkImage draws on GPU surface associated with context.
+
+        SkImage backed by GPU texture may become invalid if associated GrContext is
+        invalid. lazy image may be invalid and may not draw to raster surface or
+        GPU surface or both.
+
+        @param context  GPU context
+        @return         true if SkImage can be drawn
+    */
+    bool isValid(GrContext* context) const;
+
+    /** Retrieves the back-end texture. If SkImage has no back-end texture, an invalid
+        object is returned. Call GrBackendTexture::isValid to determine if the result
+        is valid.
+
+        If flushPendingGrContextIO is true, completes deferred I/O operations.
+
+        If origin in not nullptr, copies location of content drawn into SkImage.
+
+        @param flushPendingGrContextIO  flag to flush outstanding requests
+        @param origin                   storage for one of: kTopLeft_GrSurfaceOrigin,
+                                        kBottomLeft_GrSurfaceOrigin; or nullptr
+        @return                         back-end API texture handle; invalid on failure
+    */
+    GrBackendTexture getBackendTexture(bool flushPendingGrContextIO,
+                                       GrSurfaceOrigin* origin = nullptr) const;
+
+    /** \enum SkImage::CachingHint
+        CachingHint selects whether Skia may internally cache SkBitmap generated by
+        decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior
+        allows caching SkBitmap.
+
+        Choose kDisallow_CachingHint if SkImage pixels are to be used only once, or
+        if SkImage pixels reside in a cache outside of Skia, or to reduce memory pressure.
+
+        Choosing kAllow_CachingHint does not ensure that pixels will be cached.
+        SkImage pixels may not be cached if memory requirements are too large or
+        pixels are not accessible.
+    */
+    enum CachingHint {
+        kAllow_CachingHint,    //!< allows internally caching decoded and copied pixels
+        kDisallow_CachingHint, //!< disallows internally caching decoded and copied pixels
+    };
+
+    /** Copies SkRect of pixels from SkImage to dstPixels. Copy starts at offset (srcX, srcY),
+        and does not exceed SkImage (width(), height()).
+
+        dstInfo specifies width, height, SkColorType, SkAlphaType, and SkColorSpace of
+        destination. dstRowBytes specifics the gap from one destination row to the next.
+        Returns true if pixels are copied. Returns false if:
+        - dstInfo.addr() equals nullptr
+        - dstRowBytes is less than dstInfo.minRowBytes()
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
+        If SkImage SkColorType is kGray_8_SkColorType, dstInfo.colorSpace() must match.
+        If SkImage SkAlphaType is kOpaque_SkAlphaType, dstInfo.alphaType() must
+        match. If SkImage SkColorSpace is nullptr, dstInfo.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false if width() or height() is zero or negative.
+        Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height().
+
+        If cachingHint is kAllow_CachingHint, pixels may be retained locally.
+        If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
+
+        @param dstInfo      destination width, height, SkColorType, SkAlphaType, SkColorSpace
+        @param dstPixels    destination pixel storage
+        @param dstRowBytes  destination row length
+        @param srcX         column index whose absolute value is less than width()
+        @param srcY         row index whose absolute value is less than height()
+        @param cachingHint  one of: kAllow_CachingHint, kDisallow_CachingHint
+        @return             true if pixels are copied to dstPixels
+    */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
+                    int srcX, int srcY, CachingHint cachingHint = kAllow_CachingHint) const;
+
+    /** Copies a SkRect of pixels from SkImage to dst. Copy starts at (srcX, srcY), and
+        does not exceed SkImage (width(), height()).
+
+        dst specifies width, height, SkColorType, SkAlphaType, SkColorSpace, pixel storage,
+        and row bytes of destination. dst.rowBytes() specifics the gap from one destination
+        row to the next. Returns true if pixels are copied. Returns false if:
+        - dst pixel storage equals nullptr
+        - dst.rowBytes is less than SkImageInfo::minRowBytes
+        - SkPixelRef is nullptr
+
+        Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match.
+        If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match.
+        If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must
+        match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false if width() or height() is zero or negative.
+        Returns false if abs(srcX) >= Image width(), or if abs(srcY) >= Image height().
+
+        If cachingHint is kAllow_CachingHint, pixels may be retained locally.
+        If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
+
+        @param dst          destination SkPixmap: SkImageInfo, pixels, row bytes
+        @param srcX         column index whose absolute value is less than width()
+        @param srcY         row index whose absolute value is less than height()
+        @param cachingHint  one of: kAllow_CachingHint, kDisallow_CachingHint
+        @return             true if pixels are copied to dst
+    */
+    bool readPixels(const SkPixmap& dst, int srcX, int srcY,
+                    CachingHint cachingHint = kAllow_CachingHint) const;
+
+    /** Copies SkImage to dst, scaling pixels to fit dst.width() and dst.height(), and
+        converting pixels to match dst.colorType() and dst.alphaType(). Returns true if
+        pixels are copied. Returns false if dst.addr() is nullptr, or dst.rowBytes() is
+        less than dst SkImageInfo::minRowBytes.
+
+        Pixels are copied only if pixel conversion is possible. If SkImage SkColorType is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.colorType() must match.
+        If SkImage SkColorType is kGray_8_SkColorType, dst.colorSpace() must match.
+        If SkImage SkAlphaType is kOpaque_SkAlphaType, dst.alphaType() must
+        match. If SkImage SkColorSpace is nullptr, dst.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        Scales the image, with filterQuality, to match dst.width() and dst.height().
+        filterQuality kNone_SkFilterQuality is fastest, typically implemented with
+        nearest neighbor filter. kLow_SkFilterQuality is typically implemented with
+        bilerp filter. kMedium_SkFilterQuality is typically implemented with
+        bilerp filter, and mip-map filter when size is reduced.
+        kHigh_SkFilterQuality is slowest, typically implemented with bicubic filter.
+
+        If cachingHint is kAllow_CachingHint, pixels may be retained locally.
+        If cachingHint is kDisallow_CachingHint, pixels are not added to the local cache.
+
+        @param dst            destination SkPixmap: SkImageInfo, pixels, row bytes
+        @param filterQuality  one of: kNone_SkFilterQuality, kLow_SkFilterQuality,
+                              kMedium_SkFilterQuality, kHigh_SkFilterQuality
+        @param cachingHint    one of: kAllow_CachingHint, kDisallow_CachingHint
+        @return               true if pixels are scaled to fit dst
+    */
+    bool scalePixels(const SkPixmap& dst, SkFilterQuality filterQuality,
+                     CachingHint cachingHint = kAllow_CachingHint) const;
+
+    /** Encodes SkImage pixels, returning result as SkData.
+
+        Returns nullptr if encoding fails, or if encodedImageFormat is not supported.
+
+        SkImage encoding in a format requires both building with one or more of:
+        SK_HAS_JPEG_LIBRARY, SK_HAS_PNG_LIBRARY, SK_HAS_WEBP_LIBRARY; and platform support
+        for the encoded format.
+
+        If SK_BUILD_FOR_MAC or SK_BUILD_FOR_IOS is defined, encodedImageFormat can
+        additionally be one of: SkEncodedImageFormat::kICO, SkEncodedImageFormat::kBMP,
+        SkEncodedImageFormat::kGIF.
+
+        quality is a platform and format specific metric trading off size and encoding
+        error. When used, quality equaling 100 encodes with the least error. quality may
+        be ignored by the encoder.
+
+        @param encodedImageFormat  one of: SkEncodedImageFormat::kJPEG, SkEncodedImageFormat::kPNG,
+                                   SkEncodedImageFormat::kWEBP
+        @param quality             encoder specific metric with 100 equaling best
+        @return                    encoded SkImage, or nullptr
+    */
+    sk_sp<SkData> encodeToData(SkEncodedImageFormat encodedImageFormat, int quality) const;
+
+    /** Encodes SkImage pixels, returning result as SkData. Returns existing encoded data
+        if present; otherwise, SkImage is encoded with SkEncodedImageFormat::kPNG. Skia
+        must be built with SK_HAS_PNG_LIBRARY to encode SkImage.
+
+        Returns nullptr if existing encoded data is missing or invalid, and
+        encoding fails.
+
+        @return  encoded SkImage, or nullptr
+    */
+    sk_sp<SkData> encodeToData() const;
+
+    /** Returns encoded SkImage pixels as SkData, if SkImage was created from supported
+        encoded stream format. Platform support for formats vary and may require building
+        with one or more of: SK_HAS_JPEG_LIBRARY, SK_HAS_PNG_LIBRARY, SK_HAS_WEBP_LIBRARY.
+
+        Returns nullptr if SkImage contents are not encoded.
+
+        @return  encoded SkImage, or nullptr
+    */
+    sk_sp<SkData> refEncodedData() const;
+
+    /** Returns subset of SkImage. subset must be fully contained by SkImage dimensions().
+        The implementation may share pixels, or may copy them.
+
+        Returns nullptr if subset is empty, or subset is not contained by bounds, or
+        pixels in SkImage could not be read or copied.
+
+        @param subset  bounds of returned SkImage
+        @return        partial or full SkImage, or nullptr
+    */
+    sk_sp<SkImage> makeSubset(const SkIRect& subset) const;
+
+    /** Returns SkImage backed by GPU texture associated with context. Returned SkImage is
+        compatible with SkSurface created with dstColorSpace. The returned SkImage respects
+        mipMapped setting; if mipMapped equals GrMipMapped::kYes, the backing texture
+        allocates mip map levels. Returns original SkImage if context
+        and dstColorSpace match and mipMapped is compatible with backing GPU texture.
+
+        Returns nullptr if context is nullptr, or if SkImage was created with another
+        GrContext.
+
+        @param context        GPU context
+        @param dstColorSpace  range of colors of matching SkSurface on GPU
+        @param mipMapped      whether created SkImage texture must allocate mip map levels
+        @return               created SkImage, or nullptr
+    */
+    sk_sp<SkImage> makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace,
+                                    GrMipMapped mipMapped = GrMipMapped::kNo) const;
+
+    /** Returns raster image or lazy image. Copies SkImage backed by GPU texture into
+        CPU memory if needed. Returns original SkImage if decoded in raster bitmap,
+        or if encoded in a stream.
+
+        Returns nullptr if backed by GPU texture and copy fails.
+
+        @return  raster image, lazy image, or nullptr
+    */
+    sk_sp<SkImage> makeNonTextureImage() const;
+
+    /** Returns raster image. Copies SkImage backed by GPU texture into CPU memory,
+        or decodes SkImage from lazy image. Returns original SkImage if decoded in
+        raster bitmap.
+
+        Returns nullptr if copy, decode, or pixel read fails.
+
+        @return  raster image, or nullptr
+    */
+    sk_sp<SkImage> makeRasterImage() const;
+
+    /** Creates filtered SkImage. filter processes original SkImage, potentially changing
+        color, position, and size. subset is the bounds of original SkImage processed
+        by filter. clipBounds is the expected bounds of the filtered SkImage. outSubset
+        is required storage for the actual bounds of the filtered SkImage. offset is
+        required storage for translation of returned SkImage.
+
+        Returns nullptr if SkImage could not be created. If nullptr is returned, outSubset
+        and offset are undefined.
+
+        Useful for animation of SkImageFilter that varies size from frame to frame.
+        Returned SkImage is created larger than required by filter so that GPU texture
+        can be reused with different sized effects. outSubset describes the valid bounds
+        of GPU texture returned. offset translates the returned SkImage to keep subsequent
+        animation frames aligned with respect to each other.
+
+        @param filter      how SkImage is sampled when transformed
+        @param subset      bounds of SkImage processed by filter
+        @param clipBounds  expected bounds of filtered SkImage
+        @param outSubset   storage for returned SkImage bounds
+        @param offset      storage for returned SkImage translation
+        @return            filtered SkImage, or nullptr
+    */
+    sk_sp<SkImage> makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
+                                  const SkIRect& clipBounds, SkIRect* outSubset,
+                                  SkIPoint* offset) const;
+
+    /** Defines a callback function, taking one parameter of type GrBackendTexture with
+        no return value. Function is called when back-end texture is to be released.
+    */
+    typedef std::function<void(GrBackendTexture)> BackendTextureReleaseProc;
+
+    /** Creates a GrBackendTexture from the provided SkImage. Returns true and
+        stores result in backendTexture and backendTextureReleaseProc if
+        texture is created; otherwise, returns false and leaves
+        backendTexture and backendTextureReleaseProc unmodified.
+
+        Call backendTextureReleaseProc after deleting backendTexture.
+        backendTextureReleaseProc cleans up auxiliary data related to returned
+        backendTexture. The caller must delete returned backendTexture after use.
+
+        If SkImage is both texture backed and singly referenced, image is returned in
+        backendTexture without conversion or making a copy. SkImage is singly referenced
+        if its was transferred solely using std::move().
+
+        If SkImage is not texture backed, returns texture with SkImage contents.
+
+        @param context                    GPU context
+        @param image                      SkImage used for texture
+        @param backendTexture             storage for back-end texture
+        @param backendTextureReleaseProc  storage for clean up function
+        @return                           true if back-end texture was created
+    */
+    static bool MakeBackendTextureFromSkImage(GrContext* context,
+                                              sk_sp<SkImage> image,
+                                              GrBackendTexture* backendTexture,
+                                              BackendTextureReleaseProc* backendTextureReleaseProc);
+
+    /** Deprecated.
+     */
+    enum LegacyBitmapMode {
+        kRO_LegacyBitmapMode, //!< returned bitmap is read-only and immutable
+    };
+
+    /** Deprecated.
+        Creates raster SkBitmap with same pixels as SkImage. If legacyBitmapMode is
+        kRO_LegacyBitmapMode, returned bitmap is read-only and immutable.
+        Returns true if SkBitmap is stored in bitmap. Returns false and resets bitmap if
+        SkBitmap write did not succeed.
+
+        @param bitmap            storage for legacy SkBitmap
+        @param legacyBitmapMode  bitmap is read-only and immutable
+        @return                  true if SkBitmap was created
+    */
+    bool asLegacyBitmap(SkBitmap* bitmap,
+                        LegacyBitmapMode legacyBitmapMode = kRO_LegacyBitmapMode) const;
+
+    /** Returns true if SkImage is backed by an image-generator or other service that creates
+        and caches its pixels or texture on-demand.
+
+        @return  true if SkImage is created as needed
+    */
+    bool isLazyGenerated() const;
+
+    /** Creates SkImage in target SkColorSpace.
+        Returns nullptr if SkImage could not be created.
+
+        Returns original SkImage if it is in target SkColorSpace.
+        Otherwise, converts pixels from SkImage SkColorSpace to target SkColorSpace.
+        If SkImage colorSpace() returns nullptr, SkImage SkColorSpace is assumed to be sRGB.
+
+        @param target  SkColorSpace describing color range of returned SkImage
+        @return        created SkImage in target SkColorSpace
+    */
+    sk_sp<SkImage> makeColorSpace(sk_sp<SkColorSpace> target) const;
+
+private:
+    SkImage(int width, int height, uint32_t uniqueID);
+    friend class SkImage_Base;
+
+    const int       fWidth;
+    const int       fHeight;
+    const uint32_t  fUniqueID;
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 68 - 0
skia/include/core/SkImageEncoder.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImageEncoder_DEFINED
+#define SkImageEncoder_DEFINED
+
+#include "SkBitmap.h"
+#include "SkData.h"
+#include "SkEncodedImageFormat.h"
+#include "SkStream.h"
+
+/**
+ * Encode SkPixmap in the given binary image format.
+ *
+ * @param  dst     results are written to this stream.
+ * @param  src     source pixels.
+ * @param  format  image format, not all formats are supported.
+ * @param  quality range from 0-100, this is supported by jpeg and webp.
+ *                 higher values correspond to improved visual quality, but less compression.
+ *
+ * @return false iff input is bad or format is unsupported.
+ *
+ * Will always return false if Skia is compiled without image
+ * encoders.
+ *
+ * Note that webp encodes will use webp lossy compression.
+ *
+ * For examples of encoding an image to a file or to a block of memory,
+ * see tools/sk_tool_utils.h.
+ */
+SK_API bool SkEncodeImage(SkWStream* dst, const SkPixmap& src,
+                          SkEncodedImageFormat format, int quality);
+
+/**
+ * The following helper function wraps SkEncodeImage().
+ */
+inline bool SkEncodeImage(SkWStream* dst, const SkBitmap& src, SkEncodedImageFormat f, int q) {
+    SkPixmap pixmap;
+    return src.peekPixels(&pixmap) && SkEncodeImage(dst, pixmap, f, q);
+}
+
+/**
+ * Encode SkPixmap in the given binary image format.
+ *
+ * @param  src     source pixels.
+ * @param  format  image format, not all formats are supported.
+ * @param  quality range from 0-100, this is supported by jpeg and webp.
+ *                 higher values correspond to improved visual quality, but less compression.
+ *
+ * @return encoded data or nullptr if input is bad or format is unsupported.
+ *
+ * Will always return nullptr if Skia is compiled without image
+ * encoders.
+ *
+ * Note that webp encodes will use webp lossy compression.
+ */
+SK_API sk_sp<SkData> SkEncodePixmap(const SkPixmap& src, SkEncodedImageFormat format, int quality);
+
+/**
+ *  Helper that extracts the pixmap from the bitmap, and then calls SkEncodePixmap()
+ */
+SK_API sk_sp<SkData> SkEncodeBitmap(const SkBitmap& src, SkEncodedImageFormat format, int quality);
+
+#endif  // SkImageEncoder_DEFINED

+ 479 - 0
skia/include/core/SkImageFilter.h

@@ -0,0 +1,479 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImageFilter_DEFINED
+#define SkImageFilter_DEFINED
+
+#include "../private/SkTArray.h"
+#include "../private/SkTemplates.h"
+#include "../private/SkMutex.h"
+#include "SkColorSpace.h"
+#include "SkFilterQuality.h"
+#include "SkFlattenable.h"
+#include "SkImageInfo.h"
+#include "SkMatrix.h"
+#include "SkRect.h"
+
+class GrContext;
+class GrFragmentProcessor;
+class SkColorFilter;
+class SkColorSpaceXformer;
+struct SkIPoint;
+class SkSpecialImage;
+class SkImageFilterCache;
+struct SkImageFilterCacheKey;
+
+/**
+ *  Base class for image filters. If one is installed in the paint, then
+ *  all drawing occurs as usual, but it is as if the drawing happened into an
+ *  offscreen (before the xfermode is applied). This offscreen bitmap will
+ *  then be handed to the imagefilter, who in turn creates a new bitmap which
+ *  is what will finally be drawn to the device (using the original xfermode).
+ */
+class SK_API SkImageFilter : public SkFlattenable {
+public:
+    // Extra information about the output of a filter DAG. For now, this is just the color space
+    // (of the original requesting device). This is used when constructing intermediate rendering
+    // surfaces, so that we ensure we land in a surface that's similar/compatible to the final
+    // consumer of the DAG's output.
+    class OutputProperties {
+    public:
+        explicit OutputProperties(SkColorType colorType, SkColorSpace* colorSpace)
+            : fColorType(colorType), fColorSpace(colorSpace) {}
+
+        SkColorType colorType() const { return fColorType; }
+        SkColorSpace* colorSpace() const { return fColorSpace; }
+
+    private:
+        SkColorType fColorType;
+        // This will be a pointer to the device's color space, and our lifetime is bounded by
+        // the device, so we can store a bare pointer.
+        SkColorSpace* fColorSpace;
+    };
+
+    class Context {
+    public:
+        Context(const SkMatrix& ctm, const SkIRect& clipBounds, SkImageFilterCache* cache,
+                const OutputProperties& outputProperties)
+            : fCTM(ctm)
+            , fClipBounds(clipBounds)
+            , fCache(cache)
+            , fOutputProperties(outputProperties)
+        {}
+
+        const SkMatrix& ctm() const { return fCTM; }
+        const SkIRect& clipBounds() const { return fClipBounds; }
+        SkImageFilterCache* cache() const { return fCache; }
+        const OutputProperties& outputProperties() const { return fOutputProperties; }
+
+        /**
+         *  Since a context can be build directly, its constructor has no chance to
+         *  "return null" if it's given invalid or unsupported inputs. Call this to
+         *  know of the the context can be used.
+         *
+         *  The SkImageFilterCache Key, for example, requires a finite ctm (no infinities
+         *  or NaN), so that test is part of isValid.
+         */
+        bool isValid() const { return fCTM.isFinite(); }
+
+    private:
+        SkMatrix               fCTM;
+        SkIRect                fClipBounds;
+        SkImageFilterCache*    fCache;
+        OutputProperties       fOutputProperties;
+    };
+
+    class CropRect {
+    public:
+        enum CropEdge {
+            kHasLeft_CropEdge   = 0x01,
+            kHasTop_CropEdge    = 0x02,
+            kHasWidth_CropEdge  = 0x04,
+            kHasHeight_CropEdge = 0x08,
+            kHasAll_CropEdge    = 0x0F,
+        };
+        CropRect() {}
+        explicit CropRect(const SkRect& rect, uint32_t flags = kHasAll_CropEdge)
+            : fRect(rect), fFlags(flags) {}
+        uint32_t flags() const { return fFlags; }
+        const SkRect& rect() const { return fRect; }
+
+        /**
+         *  Apply this cropRect to the imageBounds. If a given edge of the cropRect is not
+         *  set, then the corresponding edge from imageBounds will be used. If "embiggen"
+         *  is true, the crop rect is allowed to enlarge the size of the rect, otherwise
+         *  it may only reduce the rect. Filters that can affect transparent black should
+         *  pass "true", while all other filters should pass "false".
+         *
+         *  Note: imageBounds is in "device" space, as the output cropped rectangle will be,
+         *  so the matrix is ignored for those. It is only applied the croprect's bounds.
+         */
+        void applyTo(const SkIRect& imageBounds, const SkMatrix& matrix, bool embiggen,
+                     SkIRect* cropped) const;
+
+    private:
+        SkRect fRect;
+        uint32_t fFlags;
+    };
+
+    enum TileUsage {
+        kPossible_TileUsage,    //!< the created device may be drawn tiled
+        kNever_TileUsage,       //!< the created device will never be drawn tiled
+    };
+
+    /**
+     *  Request a new filtered image to be created from the src image.
+     *
+     *  The context contains the environment in which the filter is occurring.
+     *  It includes the clip bounds, CTM and cache.
+     *
+     *  Offset is the amount to translate the resulting image relative to the
+     *  src when it is drawn. This is an out-param.
+     *
+     *  If the result image cannot be created, or the result would be
+     *  transparent black, return null, in which case the offset parameter
+     *  should be ignored by the caller.
+     *
+     *  TODO: Right now the imagefilters sometimes return empty result bitmaps/
+     *        specialimages. That doesn't seem quite right.
+     */
+    sk_sp<SkSpecialImage> filterImage(SkSpecialImage* src, const Context& context,
+                                      SkIPoint* offset) const;
+
+    enum MapDirection {
+        kForward_MapDirection,
+        kReverse_MapDirection,
+    };
+    /**
+     * Map a device-space rect recursively forward or backward through the
+     * filter DAG. kForward_MapDirection is used to determine which pixels of
+     * the destination canvas a source image rect would touch after filtering.
+     * kReverse_MapDirection is used to determine which rect of the source
+     * image would be required to fill the given rect (typically, clip bounds).
+     * Used for clipping and temp-buffer allocations, so the result need not
+     * be exact, but should never be smaller than the real answer. The default
+     * implementation recursively unions all input bounds, or returns the
+     * source rect if no inputs.
+     *
+     * In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
+     * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting
+     * answer may be incorrect.
+     */
+    SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm,
+                         MapDirection, const SkIRect* inputRect = nullptr) const;
+
+#if SK_SUPPORT_GPU
+    static sk_sp<SkSpecialImage> DrawWithFP(GrContext* context,
+                                            std::unique_ptr<GrFragmentProcessor> fp,
+                                            const SkIRect& bounds,
+                                            const OutputProperties& outputProperties);
+#endif
+
+    /**
+     *  Returns whether this image filter is a color filter and puts the color filter into the
+     *  "filterPtr" parameter if it can. Does nothing otherwise.
+     *  If this returns false, then the filterPtr is unchanged.
+     *  If this returns true, then if filterPtr is not null, it must be set to a ref'd colorfitler
+     *  (i.e. it may not be set to NULL).
+     */
+    bool isColorFilterNode(SkColorFilter** filterPtr) const {
+        return this->onIsColorFilterNode(filterPtr);
+    }
+
+    // DEPRECATED : use isColorFilterNode() instead
+    bool asColorFilter(SkColorFilter** filterPtr) const {
+        return this->isColorFilterNode(filterPtr);
+    }
+
+    void removeKey(const SkImageFilterCacheKey& key) const;
+
+    /**
+     *  Returns true (and optionally returns a ref'd filter) if this imagefilter can be completely
+     *  replaced by the returned colorfilter. i.e. the two effects will affect drawing in the
+     *  same way.
+     */
+    bool asAColorFilter(SkColorFilter** filterPtr) const;
+
+    /**
+     *  Returns the number of inputs this filter will accept (some inputs can
+     *  be NULL).
+     */
+    int countInputs() const { return fInputs.count(); }
+
+    /**
+     *  Returns the input filter at a given index, or NULL if no input is
+     *  connected.  The indices used are filter-specific.
+     */
+    SkImageFilter* getInput(int i) const {
+        SkASSERT(i < fInputs.count());
+        return fInputs[i].get();
+    }
+
+    /**
+     *  Returns whether any edges of the crop rect have been set. The crop
+     *  rect is set at construction time, and determines which pixels from the
+     *  input image will be processed, and which pixels in the output image will be allowed.
+     *  The size of the crop rect should be
+     *  used as the size of the destination image. The origin of this rect
+     *  should be used to offset access to the input images, and should also
+     *  be added to the "offset" parameter in onFilterImage.
+     */
+    bool cropRectIsSet() const { return fCropRect.flags() != 0x0; }
+
+    CropRect getCropRect() const { return fCropRect; }
+
+    // Default impl returns union of all input bounds.
+    virtual SkRect computeFastBounds(const SkRect& bounds) const;
+
+    // Can this filter DAG compute the resulting bounds of an object-space rectangle?
+    bool canComputeFastBounds() const;
+
+    /**
+     *  If this filter can be represented by another filter + a localMatrix, return that filter,
+     *  else return null.
+     */
+    sk_sp<SkImageFilter> makeWithLocalMatrix(const SkMatrix& matrix) const;
+
+    /**
+     *  ImageFilters can natively handle scaling and translate components in the CTM. Only some of
+     *  them can handle affine (or more complex) matrices. This call returns true iff the filter
+     *  and all of its (non-null) inputs can handle these more complex matrices.
+     */
+    bool canHandleComplexCTM() const;
+
+    /**
+     * Return an imagefilter which transforms its input by the given matrix.
+     */
+    static sk_sp<SkImageFilter> MakeMatrixFilter(const SkMatrix& matrix,
+                                                 SkFilterQuality quality,
+                                                 sk_sp<SkImageFilter> input);
+
+    static void RegisterFlattenables();
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkImageFilter_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkImageFilter_Type;
+    }
+
+    static sk_sp<SkImageFilter> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkImageFilter>(static_cast<SkImageFilter*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkImageFilter_Type, data, size, procs).release()));
+    }
+
+protected:
+    class Common {
+    public:
+        /**
+         *  Attempt to unflatten the cropRect and the expected number of input filters.
+         *  If any number of input filters is valid, pass -1.
+         *  If this fails (i.e. corrupt buffer or contents) then return false and common will
+         *  be left uninitialized.
+         *  If this returns true, then inputCount() is the number of found input filters, each
+         *  of which may be NULL or a valid imagefilter.
+         */
+        bool unflatten(SkReadBuffer&, int expectedInputs);
+
+        const CropRect& cropRect() const { return fCropRect; }
+        int             inputCount() const { return fInputs.count(); }
+        sk_sp<SkImageFilter>* inputs() { return fInputs.begin(); }
+
+        sk_sp<SkImageFilter> getInput(int index) { return fInputs[index]; }
+
+    private:
+        CropRect fCropRect;
+        // most filters accept at most 2 input-filters
+        SkSTArray<2, sk_sp<SkImageFilter>, true> fInputs;
+    };
+
+    SkImageFilter(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
+
+    ~SkImageFilter() override;
+
+    /**
+     *  Constructs a new SkImageFilter read from an SkReadBuffer object.
+     *
+     *  @param inputCount    The exact number of inputs expected for this SkImageFilter object.
+     *                       -1 can be used if the filter accepts any number of inputs.
+     *  @param rb            SkReadBuffer object from which the SkImageFilter is read.
+     */
+    explicit SkImageFilter(int inputCount, SkReadBuffer& rb);
+
+    void flatten(SkWriteBuffer&) const override;
+
+    const CropRect* getCropRectIfSet() const {
+        return this->cropRectIsSet() ? &fCropRect : nullptr;
+    }
+
+    /**
+     *  This is the virtual which should be overridden by the derived class
+     *  to perform image filtering.
+     *
+     *  src is the original primitive bitmap. If the filter has a connected
+     *  input, it should recurse on that input and use that in place of src.
+     *
+     *  The matrix is the current matrix on the canvas.
+     *
+     *  Offset is the amount to translate the resulting image relative to the
+     *  src when it is drawn. This is an out-param.
+     *
+     *  If the result image cannot be created (either because of error or if, say, the result
+     *  is entirely clipped out), this should return nullptr.
+     *  Callers that affect transparent black should explicitly handle nullptr
+     *  results and press on. In the error case this behavior will produce a better result
+     *  than nothing and is necessary for the clipped out case.
+     *  If the return value is nullptr then offset should be ignored.
+     */
+    virtual sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
+                                                SkIPoint* offset) const = 0;
+
+    /**
+     * This function recurses into its inputs with the given rect (first
+     * argument), calls filterBounds() with the given map direction on each,
+     * and returns the union of those results. If a derived class has special
+     * recursion requirements (e.g., it has an input which does not participate
+     * in bounds computation), it can be overridden here.
+     * In kReverse mode, 'inputRect' is the device-space bounds of the input pixels. In kForward
+     * mode it should always be null. If 'inputRect' is null in kReverse mode the resulting
+     * answer may be incorrect.
+     *
+     * Note that this function is *not* responsible for mapping the rect for
+     * this node's filter bounds requirements (i.e., calling
+     * onFilterNodeBounds()); that is handled by filterBounds().
+     */
+    virtual SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm,
+                                   MapDirection, const SkIRect* inputRect) const;
+
+    /**
+     * Performs a forwards or reverse mapping of the given rect to accommodate
+     * this filter's margin requirements. kForward_MapDirection is used to
+     * determine the destination pixels which would be touched by filtering
+     * the given source rect (e.g., given source bitmap bounds,
+     * determine the optimal bounds of the filtered offscreen bitmap).
+     * kReverse_MapDirection is used to determine which pixels of the
+     * input(s) would be required to fill the given destination rect
+     * (e.g., clip bounds). NOTE: these operations may not be the
+     * inverse of the other. For example, blurring expands the given rect
+     * in both forward and reverse directions. Unlike
+     * onFilterBounds(), this function is non-recursive.
+     * In kReverse mode, 'inputRect' will be the device space bounds of the input pixels. In
+     * kForward mode, 'inputRect' should always be null. If 'inputRect' is null in kReverse mode
+     * the resulting answer may be incorrect.
+     */
+    virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm,
+                                       MapDirection, const SkIRect* inputRect) const;
+
+    // Helper function which invokes filter processing on the input at the
+    // specified "index". If the input is null, it returns "src" and leaves
+    // "offset" untouched. If the input is non-null, it
+    // calls filterImage() on that input, and returns the result.
+    sk_sp<SkSpecialImage> filterInput(int index,
+                                      SkSpecialImage* src,
+                                      const Context&,
+                                      SkIPoint* offset) const;
+
+    /**
+     *  Return true (and return a ref'd colorfilter) if this node in the DAG is just a
+     *  colorfilter w/o CropRect constraints.
+     */
+    virtual bool onIsColorFilterNode(SkColorFilter** /*filterPtr*/) const {
+        return false;
+    }
+
+    /**
+     *  Override this to describe the behavior of your subclass - as a leaf node. The caller will
+     *  take care of calling your inputs (and return false if any of them could not handle it).
+     */
+    virtual bool onCanHandleComplexCTM() const { return false; }
+
+    /** Given a "srcBounds" rect, computes destination bounds for this filter.
+     *  "dstBounds" are computed by transforming the crop rect by the context's
+     *  CTM, applying it to the initial bounds, and intersecting the result with
+     *  the context's clip bounds.  "srcBounds" (if non-null) are computed by
+     *  intersecting the initial bounds with "dstBounds", to ensure that we never
+     *  sample outside of the crop rect (this restriction may be relaxed in the
+     *  future).
+     */
+    bool applyCropRect(const Context&, const SkIRect& srcBounds, SkIRect* dstBounds) const;
+
+    /** A variant of the above call which takes the original source bitmap and
+     *  source offset. If the resulting crop rect is not entirely contained by
+     *  the source bitmap's bounds, it creates a new bitmap in "result" and
+     *  pads the edges with transparent black. In that case, the srcOffset is
+     *  modified to be the same as the bounds, since no further adjustment is
+     *  needed by the caller. This version should only be used by filters
+     *  which are not capable of processing a smaller source bitmap into a
+     *  larger destination.
+     */
+    sk_sp<SkSpecialImage> applyCropRectAndPad(const Context&, SkSpecialImage* src,
+                                              SkIPoint* srcOffset, SkIRect* bounds) const;
+
+    /**
+     *  Creates a modified Context for use when recursing up the image filter DAG.
+     *  The clip bounds are adjusted to accommodate any margins that this
+     *  filter requires by calling this node's
+     *  onFilterNodeBounds(..., kReverse_MapDirection).
+     */
+    Context mapContext(const Context& ctx) const;
+
+#if SK_SUPPORT_GPU
+    /**
+     *  Returns a version of the passed-in image (possibly the original), that is in a colorspace
+     *  with the same gamut as the one from the OutputProperties. This allows filters that do many
+     *  texture samples to guarantee that any color space conversion has happened before running.
+     */
+    static sk_sp<SkSpecialImage> ImageToColorSpace(SkSpecialImage* src, const OutputProperties&);
+#endif
+
+    /**
+     *  Returns an image filter transformed into a new color space via the |xformer|.
+     */
+    sk_sp<SkImageFilter> makeColorSpace(SkColorSpaceXformer* xformer) const {
+        return this->onMakeColorSpace(xformer);
+    }
+    virtual sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const = 0;
+
+    sk_sp<SkImageFilter> refMe() const {
+        return sk_ref_sp(const_cast<SkImageFilter*>(this));
+    }
+
+    // If 'srcBounds' will sample outside the border of 'originalSrcBounds' (i.e., the sample
+    // will wrap around to the other side) we must preserve the far side of the src along that
+    // axis (e.g., if we will sample beyond the left edge of the src, the right side must be
+    // preserved for the repeat sampling to work).
+    static SkIRect DetermineRepeatedSrcBound(const SkIRect& srcBounds,
+                                             const SkIVector& filterOffset,
+                                             const SkISize& filterSize,
+                                             const SkIRect& originalSrcBounds);
+
+private:
+    // For makeColorSpace().
+    friend class SkColorSpaceXformer;
+
+    friend class SkGraphics;
+
+    static void PurgeCache();
+
+    void init(sk_sp<SkImageFilter> const* inputs, int inputCount, const CropRect* cropRect);
+
+    bool usesSrcInput() const { return fUsesSrcInput; }
+    virtual bool affectsTransparentBlack() const { return false; }
+
+    SkAutoSTArray<2, sk_sp<SkImageFilter>> fInputs;
+
+    bool fUsesSrcInput;
+    CropRect fCropRect;
+    uint32_t fUniqueID; // Globally unique
+
+    typedef SkFlattenable INHERITED;
+};
+
+#endif

+ 207 - 0
skia/include/core/SkImageGenerator.h

@@ -0,0 +1,207 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImageGenerator_DEFINED
+#define SkImageGenerator_DEFINED
+
+#include "SkBitmap.h"
+#include "SkColor.h"
+#include "SkImage.h"
+#include "SkImageInfo.h"
+#include "SkYUVAIndex.h"
+#include "SkYUVASizeInfo.h"
+
+class GrContext;
+class GrContextThreadSafeProxy;
+class GrTextureProxy;
+class GrSamplerState;
+class SkBitmap;
+class SkData;
+class SkMatrix;
+class SkPaint;
+class SkPicture;
+
+class SK_API SkImageGenerator {
+public:
+    /**
+     *  The PixelRef which takes ownership of this SkImageGenerator
+     *  will call the image generator's destructor.
+     */
+    virtual ~SkImageGenerator() { }
+
+    uint32_t uniqueID() const { return fUniqueID; }
+
+    /**
+     *  Return a ref to the encoded (i.e. compressed) representation
+     *  of this data.
+     *
+     *  If non-NULL is returned, the caller is responsible for calling
+     *  unref() on the data when it is finished.
+     */
+    sk_sp<SkData> refEncodedData() {
+        return this->onRefEncodedData();
+    }
+
+    /**
+     *  Return the ImageInfo associated with this generator.
+     */
+    const SkImageInfo& getInfo() const { return fInfo; }
+
+    /**
+     *  Can this generator be used to produce images that will be drawable to the specified context
+     *  (or to CPU, if context is nullptr)?
+     */
+    bool isValid(GrContext* context) const {
+        return this->onIsValid(context);
+    }
+
+    /**
+     *  Decode into the given pixels, a block of memory of size at
+     *  least (info.fHeight - 1) * rowBytes + (info.fWidth *
+     *  bytesPerPixel)
+     *
+     *  Repeated calls to this function should give the same results,
+     *  allowing the PixelRef to be immutable.
+     *
+     *  @param info A description of the format
+     *         expected by the caller.  This can simply be identical
+     *         to the info returned by getInfo().
+     *
+     *         This contract also allows the caller to specify
+     *         different output-configs, which the implementation can
+     *         decide to support or not.
+     *
+     *         A size that does not match getInfo() implies a request
+     *         to scale. If the generator cannot perform this scale,
+     *         it will return false.
+     *
+     *  @return true on success.
+     */
+    bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
+
+    /**
+     *  If decoding to YUV is supported, this returns true.  Otherwise, this
+     *  returns false and does not modify any of the parameters.
+     *
+     *  @param sizeInfo    Output parameter indicating the sizes and required
+     *                     allocation widths of the Y, U, V, and A planes.
+     *  @param yuvaIndices How the YUVA planes are organized/used
+     *  @param colorSpace  Output parameter.
+     */
+    bool queryYUVA8(SkYUVASizeInfo* sizeInfo,
+                    SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+                    SkYUVColorSpace* colorSpace) const;
+
+    /**
+     *  Returns true on success and false on failure.
+     *  This always attempts to perform a full decode.  If the client only
+     *  wants size, it should call queryYUVA8().
+     *
+     *  @param sizeInfo    Needs to exactly match the values returned by the
+     *                     query, except the WidthBytes may be larger than the
+     *                     recommendation (but not smaller).
+     *  @param yuvaIndices Needs to exactly match the values returned by the query.
+     *  @param planes      Memory for the Y, U, V, and A planes. Note that, depending on the
+     *                     settings in yuvaIndices, anywhere from 1..4 planes could be returned.
+     */
+    bool getYUVA8Planes(const SkYUVASizeInfo& sizeInfo,
+                        const SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
+                        void* planes[]);
+
+#if SK_SUPPORT_GPU
+    /**
+     *  If the generator can natively/efficiently return its pixels as a GPU image (backed by a
+     *  texture) this will return that image. If not, this will return NULL.
+     *
+     *  This routine also supports retrieving only a subset of the pixels. That subset is specified
+     *  by the following rectangle:
+     *
+     *      subset = SkIRect::MakeXYWH(origin.x(), origin.y(), info.width(), info.height())
+     *
+     *  If subset is not contained inside the generator's bounds, this returns false.
+     *
+     *      whole = SkIRect::MakeWH(getInfo().width(), getInfo().height())
+     *      if (!whole.contains(subset)) {
+     *          return false;
+     *      }
+     *
+     *  Regarding the GrContext parameter:
+     *
+     *  It must be non-NULL. The generator should only succeed if:
+     *  - its internal context is the same
+     *  - it can somehow convert its texture into one that is valid for the provided context.
+     *
+     *  If the willNeedMipMaps flag is true, the generator should try to create a TextureProxy that
+     *  at least has the mip levels allocated and the base layer filled in. If this is not possible,
+     *  the generator is allowed to return a non mipped proxy, but this will have some additional
+     *  overhead in later allocating mips and copying of the base layer.
+     */
+    sk_sp<GrTextureProxy> generateTexture(GrContext*, const SkImageInfo& info,
+                                          const SkIPoint& origin,
+                                          bool willNeedMipMaps);
+#endif
+
+    /**
+     *  If the default image decoder system can interpret the specified (encoded) data, then
+     *  this returns a new ImageGenerator for it. Otherwise this returns NULL. Either way
+     *  the caller is still responsible for managing their ownership of the data.
+     */
+    static std::unique_ptr<SkImageGenerator> MakeFromEncoded(sk_sp<SkData>);
+
+    /** Return a new image generator backed by the specified picture.  If the size is empty or
+     *  the picture is NULL, this returns NULL.
+     *  The optional matrix and paint arguments are passed to drawPicture() at rasterization
+     *  time.
+     */
+    static std::unique_ptr<SkImageGenerator> MakeFromPicture(const SkISize&, sk_sp<SkPicture>,
+                                                             const SkMatrix*, const SkPaint*,
+                                                             SkImage::BitDepth,
+                                                             sk_sp<SkColorSpace>);
+
+protected:
+    static constexpr int kNeedNewImageUniqueID = 0;
+
+    SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID);
+
+    virtual sk_sp<SkData> onRefEncodedData() { return nullptr; }
+    struct Options {};
+    virtual bool onGetPixels(const SkImageInfo&, void*, size_t, const Options&) { return false; }
+    virtual bool onIsValid(GrContext*) const { return true; }
+    virtual bool onQueryYUVA8(SkYUVASizeInfo*, SkYUVAIndex[SkYUVAIndex::kIndexCount],
+                              SkYUVColorSpace*) const { return false; }
+    virtual bool onGetYUVA8Planes(const SkYUVASizeInfo&, const SkYUVAIndex[SkYUVAIndex::kIndexCount],
+                                  void*[4] /*planes*/) { return false; }
+#if SK_SUPPORT_GPU
+    enum class TexGenType {
+        kNone,           //image generator does not implement onGenerateTexture
+        kCheap,          //onGenerateTexture is implemented and it is fast (does not render offscreen)
+        kExpensive,      //onGenerateTexture is implemented and it is relatively slow
+    };
+
+    virtual TexGenType onCanGenerateTexture() const { return TexGenType::kNone; }
+    virtual sk_sp<GrTextureProxy> onGenerateTexture(GrContext*, const SkImageInfo&, const SkIPoint&,
+                                                    bool willNeedMipMaps);  // returns nullptr
+#endif
+
+private:
+    const SkImageInfo fInfo;
+    const uint32_t fUniqueID;
+
+    friend class SkImage_Lazy;
+
+    // This is our default impl, which may be different on different platforms.
+    // It is called from NewFromEncoded() after it has checked for any runtime factory.
+    // The SkData will never be NULL, as that will have been checked by NewFromEncoded.
+    static std::unique_ptr<SkImageGenerator> MakeFromEncodedImpl(sk_sp<SkData>);
+
+    SkImageGenerator(SkImageGenerator&&) = delete;
+    SkImageGenerator(const SkImageGenerator&) = delete;
+    SkImageGenerator& operator=(SkImageGenerator&&) = delete;
+    SkImageGenerator& operator=(const SkImageGenerator&) = delete;
+};
+
+#endif  // SkImageGenerator_DEFINED

+ 623 - 0
skia/include/core/SkImageInfo.h

@@ -0,0 +1,623 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkImageInfo.h and docs/SkImageInfo_Reference.bmh
+   on 2018-07-13 08:15:11. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkImageInfo_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkImageInfo_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkImageInfo.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkImageInfo_DEFINED
+#define SkImageInfo_DEFINED
+
+#include "SkColorSpace.h"
+#include "SkMath.h"
+#include "SkRect.h"
+#include "SkSize.h"
+
+#include "../private/SkTFitsIn.h"
+#include "../private/SkTo.h"
+
+class SkReadBuffer;
+class SkWriteBuffer;
+
+/** \enum SkImageInfo::SkAlphaType
+    Describes how to interpret the alpha component of a pixel. A pixel may
+    be opaque, or alpha, describing multiple levels of transparency.
+
+    In simple blending, alpha weights the draw color and the destination
+    color to create a new color. If alpha describes a weight from zero to one:
+
+    new color = draw color * alpha + destination color * (1 - alpha)
+
+    In practice alpha is encoded in two or more bits, where 1.0 equals all bits set.
+
+    RGB may have alpha included in each component value; the stored
+    value is the original RGB multiplied by alpha. Premultiplied color
+    components improve performance.
+*/
+enum SkAlphaType {
+    kUnknown_SkAlphaType,                          //!< uninitialized
+    kOpaque_SkAlphaType,                           //!< pixel is opaque
+    kPremul_SkAlphaType,                           //!< pixel components are premultiplied by alpha
+    kUnpremul_SkAlphaType,                         //!< pixel components are independent of alpha
+    kLastEnum_SkAlphaType = kUnpremul_SkAlphaType, //!< last valid value
+};
+
+/** Returns true if SkAlphaType equals kOpaque_SkAlphaType. kOpaque_SkAlphaType is a
+    hint that the SkColorType is opaque, or that all alpha values are set to
+    their 1.0 equivalent. If SkAlphaType is kOpaque_SkAlphaType, and SkColorType is not
+    opaque, then the result of drawing any pixel with a alpha value less than
+    1.0 is undefined.
+
+    @param at  one of:
+               kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+               kUnpremul_SkAlphaType
+    @return    true if at equals kOpaque_SkAlphaType
+*/
+static inline bool SkAlphaTypeIsOpaque(SkAlphaType at) {
+    return kOpaque_SkAlphaType == at;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Temporary macro that allows us to add new color types without breaking Chrome compile. */
+#define SK_EXTENDED_COLOR_TYPES
+
+/** \enum SkImageInfo::SkColorType
+    Describes how pixel bits encode color. A pixel may be an alpha mask, a
+    grayscale, RGB, or ARGB.
+
+    kN32_SkColorType selects the native 32-bit ARGB format. On little endian
+    processors, pixels containing 8-bit ARGB components pack into 32-bit
+    kBGRA_8888_SkColorType. On big endian processors, pixels pack into 32-bit
+    kRGBA_8888_SkColorType.
+*/
+enum SkColorType {
+    kUnknown_SkColorType,      //!< uninitialized
+    kAlpha_8_SkColorType,      //!< pixel with alpha in 8-bit byte
+    kRGB_565_SkColorType,      //!< pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
+    kARGB_4444_SkColorType,    //!< pixel with 4 bits for alpha, red, green, blue; in 16-bit word
+    kRGBA_8888_SkColorType,    //!< pixel with 8 bits for red, green, blue, alpha; in 32-bit word
+    kRGB_888x_SkColorType,     //!< pixel with 8 bits each for red, green, blue; in 32-bit word
+    kBGRA_8888_SkColorType,    //!< pixel with 8 bits for blue, green, red, alpha; in 32-bit word
+    kRGBA_1010102_SkColorType, //!< 10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
+    kRGB_101010x_SkColorType,  //!< pixel with 10 bits each for red, green, blue; in 32-bit word
+    kGray_8_SkColorType,       //!< pixel with grayscale level in 8-bit byte
+    kRGBA_F16_SkColorType,   //!< pixel with half floats for red, green, blue, alpha; in 64-bit word
+    kRGBA_F32_SkColorType,     //!< pixel using C float for red, green, blue, alpha; in 128-bit word
+    kLastEnum_SkColorType     = kRGBA_F32_SkColorType,//!< last valid value
+
+#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
+    kN32_SkColorType          = kBGRA_8888_SkColorType,//!< native ARGB 32-bit encoding
+
+#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
+    kN32_SkColorType          = kRGBA_8888_SkColorType,//!< native ARGB 32-bit encoding
+
+#else
+    #error "SK_*32_SHIFT values must correspond to BGRA or RGBA byte order"
+#endif
+};
+
+/** Returns the number of bytes required to store a pixel, including unused padding.
+    Returns zero if ct is kUnknown_SkColorType or invalid.
+
+    @param ct  one of:
+               kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+               kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+               kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+               kGray_8_SkColorType, kRGBA_F16_SkColorType
+    @return    bytes per pixel
+*/
+SK_API int SkColorTypeBytesPerPixel(SkColorType ct);
+
+/** Returns true if SkColorType always decodes alpha to 1.0, making the pixel
+    fully opaque. If true, SkColorType does not reserve bits to encode alpha.
+
+    @param ct  one of:
+               kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+               kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+               kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+               kGray_8_SkColorType, kRGBA_F16_SkColorType
+    @return    true if alpha is always set to 1.0
+*/
+SK_API bool SkColorTypeIsAlwaysOpaque(SkColorType ct);
+
+/** Returns true if canonical can be set to a valid SkAlphaType for colorType. If
+    there is more than one valid canonical SkAlphaType, set to alphaType, if valid.
+    If true is returned and canonical is not nullptr, store valid SkAlphaType.
+
+    Returns false only if alphaType is kUnknown_SkAlphaType, color type is not
+    kUnknown_SkColorType, and SkColorType is not always opaque. If false is returned,
+    canonical is ignored.
+
+    For kUnknown_SkColorType: set canonical to kUnknown_SkAlphaType and return true.
+    For kAlpha_8_SkColorType: set canonical to kPremul_SkAlphaType or
+    kOpaque_SkAlphaType and return true if alphaType is not kUnknown_SkAlphaType.
+    For kRGB_565_SkColorType, kRGB_888x_SkColorType, kRGB_101010x_SkColorType, and
+    kGray_8_SkColorType: set canonical to kOpaque_SkAlphaType and return true.
+    For kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType,
+    kRGBA_1010102_SkColorType, and kRGBA_F16_SkColorType: set canonical to alphaType
+    and return true if alphaType is not kUnknown_SkAlphaType.
+
+    @param colorType  one of:
+                      kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+                      kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+                      kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+                      kGray_8_SkColorType, kRGBA_F16_SkColorType
+    @param alphaType  one of:
+                      kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                      kUnpremul_SkAlphaType
+    @param canonical  storage for SkAlphaType
+    @return           true if valid SkAlphaType can be associated with colorType
+*/
+SK_API bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
+                                         SkAlphaType* canonical = nullptr);
+
+/** \enum SkImageInfo::SkYUVColorSpace
+    Describes color range of YUV pixels. The color mapping from YUV to RGB varies
+    depending on the source. YUV pixels may be generated by JPEG images, standard
+    video streams, or high definition video streams. Each has its own mapping from
+    YUV and RGB.
+
+    JPEG YUV values encode the full range of 0 to 255 for all three components.
+    Video YUV values range from 16 to 235 for all three components. Details of
+    encoding and conversion to RGB are described in YCbCr color space.
+*/
+enum SkYUVColorSpace {
+    kJPEG_SkYUVColorSpace,                               //!< describes full range
+    kRec601_SkYUVColorSpace,                             //!< describes SDTV range
+    kRec709_SkYUVColorSpace,                             //!< describes HDTV range
+    kLastEnum_SkYUVColorSpace = kRec709_SkYUVColorSpace, //!< last valid value
+};
+
+/** \struct SkImageInfo
+    Describes pixel dimensions and encoding. SkBitmap, SkImage, PixMap, and SkSurface
+    can be created from SkImageInfo. SkImageInfo can be retrieved from SkBitmap and
+    SkPixmap, but not from SkImage and SkSurface. For example, SkImage and SkSurface
+    implementations may defer pixel depth, so may not completely specify SkImageInfo.
+
+    SkImageInfo contains dimensions, the pixel integral width and height. It encodes
+    how pixel bits describe alpha, transparency; color components red, blue,
+    and green; and SkColorSpace, the range and linearity of colors.
+*/
+struct SK_API SkImageInfo {
+public:
+
+    /** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType,
+        a width and height of zero, and no SkColorSpace.
+
+        @return  empty SkImageInfo
+    */
+    SkImageInfo()
+        : fColorSpace(nullptr)
+        , fDimensions{0, 0}
+        , fColorType(kUnknown_SkColorType)
+        , fAlphaType(kUnknown_SkAlphaType)
+    {}
+
+    /** Creates SkImageInfo from integral dimensions width and height, SkColorType ct,
+        SkAlphaType at, and optionally SkColorSpace cs.
+
+        If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
+        defaults to sRGB, mapping into SkSurface SkColorSpace.
+
+        Parameters are not validated to see if their values are legal, or that the
+        combination is supported.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @param ct      one of:
+                       kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+                       kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+                       kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+                       kGray_8_SkColorType, kRGBA_F16_SkColorType
+        @param at      one of:
+                       kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                       kUnpremul_SkAlphaType
+        @param cs      range of colors; may be nullptr
+        @return        created SkImageInfo
+    */
+    static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at,
+                            sk_sp<SkColorSpace> cs = nullptr) {
+        return SkImageInfo(width, height, ct, at, std::move(cs));
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
+        SkAlphaType at, and optionally SkColorSpace cs. kN32_SkColorType will equal either
+        kBGRA_8888_SkColorType or kRGBA_8888_SkColorType, whichever is optimal.
+
+        If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
+        defaults to sRGB, mapping into SkSurface SkColorSpace.
+
+        Parameters are not validated to see if their values are legal, or that the
+        combination is supported.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @param at      one of:
+                       kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                       kUnpremul_SkAlphaType
+        @param cs      range of colors; may be nullptr
+        @return        created SkImageInfo
+    */
+    static SkImageInfo MakeN32(int width, int height, SkAlphaType at,
+                               sk_sp<SkColorSpace> cs = nullptr) {
+        return Make(width, height, kN32_SkColorType, at, std::move(cs));
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
+        SkAlphaType at, with sRGB SkColorSpace.
+
+        Parameters are not validated to see if their values are legal, or that the
+        combination is supported.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @param at      one of:
+                       kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                       kUnpremul_SkAlphaType
+        @return        created SkImageInfo
+    */
+    static SkImageInfo MakeS32(int width, int height, SkAlphaType at);
+
+    /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
+        kPremul_SkAlphaType, with optional SkColorSpace.
+
+        If SkColorSpace cs is nullptr and SkImageInfo is part of drawing source: SkColorSpace
+        defaults to sRGB, mapping into SkSurface SkColorSpace.
+
+        Parameters are not validated to see if their values are legal, or that the
+        combination is supported.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @param cs      range of colors; may be nullptr
+        @return        created SkImageInfo
+    */
+    static SkImageInfo MakeN32Premul(int width, int height, sk_sp<SkColorSpace> cs = nullptr) {
+        return Make(width, height, kN32_SkColorType, kPremul_SkAlphaType, std::move(cs));
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height, kN32_SkColorType,
+        kPremul_SkAlphaType, with SkColorSpace set to nullptr.
+
+        If SkImageInfo is part of drawing source: SkColorSpace defaults to sRGB, mapping
+        into SkSurface SkColorSpace.
+
+        Parameters are not validated to see if their values are legal, or that the
+        combination is supported.
+
+        @param size  width and height, each must be zero or greater
+        @return      created SkImageInfo
+    */
+    static SkImageInfo MakeN32Premul(const SkISize& size) {
+        return MakeN32Premul(size.width(), size.height());
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height, kAlpha_8_SkColorType,
+        kPremul_SkAlphaType, with SkColorSpace set to nullptr.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @return        created SkImageInfo
+    */
+    static SkImageInfo MakeA8(int width, int height) {
+        return Make(width, height, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr);
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height, kUnknown_SkColorType,
+        kUnknown_SkAlphaType, with SkColorSpace set to nullptr.
+
+        Returned SkImageInfo as part of source does not draw, and as part of destination
+        can not be drawn to.
+
+        @param width   pixel column count; must be zero or greater
+        @param height  pixel row count; must be zero or greater
+        @return        created SkImageInfo
+    */
+    static SkImageInfo MakeUnknown(int width, int height) {
+        return Make(width, height, kUnknown_SkColorType, kUnknown_SkAlphaType, nullptr);
+    }
+
+    /** Creates SkImageInfo from integral dimensions width and height set to zero,
+        kUnknown_SkColorType, kUnknown_SkAlphaType, with SkColorSpace set to nullptr.
+
+        Returned SkImageInfo as part of source does not draw, and as part of destination
+        can not be drawn to.
+
+        @return  created SkImageInfo
+    */
+    static SkImageInfo MakeUnknown() {
+        return MakeUnknown(0, 0);
+    }
+
+    /** Returns pixel count in each row.
+
+        @return  pixel width
+    */
+    int width() const { return fDimensions.width(); }
+
+    /** Returns pixel row count.
+
+        @return  pixel height
+    */
+    int height() const { return fDimensions.height(); }
+
+    /** Returns SkColorType, one of:
+        kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+        kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+        kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+        kGray_8_SkColorType, kRGBA_F16_SkColorType.
+
+        @return  SkColorType
+    */
+    SkColorType colorType() const { return fColorType; }
+
+    /** Returns SkAlphaType, one of:
+        kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+        kUnpremul_SkAlphaType.
+
+        @return  SkAlphaType
+    */
+    SkAlphaType alphaType() const { return fAlphaType; }
+
+    /** Returns SkColorSpace, the range of colors. The reference count of
+        SkColorSpace is unchanged. The returned SkColorSpace is immutable.
+
+        @return  SkColorSpace, or nullptr
+    */
+    SkColorSpace* colorSpace() const { return fColorSpace.get(); }
+
+    /** Returns smart pointer to SkColorSpace, the range of colors. The smart pointer
+        tracks the number of objects sharing this SkColorSpace reference so the memory
+        is released when the owners destruct.
+
+        The returned SkColorSpace is immutable.
+
+        @return  SkColorSpace wrapped in a smart pointer
+    */
+    sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; }
+
+    /** Returns if SkImageInfo describes an empty area of pixels by checking if either
+        width or height is zero or smaller.
+
+        @return  true if either dimension is zero or smaller
+    */
+    bool isEmpty() const { return fDimensions.isEmpty(); }
+
+    /** Returns true if SkAlphaType is set to hint that all pixels are opaque; their
+        alpha value is implicitly or explicitly 1.0. If true, and all pixels are
+        not opaque, Skia may draw incorrectly.
+
+        Does not check if SkColorType allows alpha, or if any pixel value has
+        transparency.
+
+        @return  true if SkAlphaType is kOpaque_SkAlphaType
+    */
+    bool isOpaque() const {
+        return SkAlphaTypeIsOpaque(fAlphaType);
+    }
+
+    /** Returns SkISize { width(), height() }.
+
+        @return  integral size of width() and height()
+    */
+    SkISize dimensions() const { return fDimensions; }
+
+    /** Returns SkIRect { 0, 0, width(), height() }.
+
+        @return  integral rectangle from origin to width() and height()
+    */
+    SkIRect bounds() const { return SkIRect::MakeSize(fDimensions); }
+
+    /** Returns true if associated SkColorSpace is not nullptr, and SkColorSpace gamma
+        is approximately the same as sRGB.
+        This includes the
+
+        @return  true if SkColorSpace gamma is approximately the same as sRGB
+    */
+    bool gammaCloseToSRGB() const {
+        return fColorSpace && fColorSpace->gammaCloseToSRGB();
+    }
+
+    /** Creates SkImageInfo with the same SkColorType, SkColorSpace, and SkAlphaType,
+        with dimensions set to width and height.
+
+        @param newWidth   pixel column count; must be zero or greater
+        @param newHeight  pixel row count; must be zero or greater
+        @return           created SkImageInfo
+    */
+    SkImageInfo makeWH(int newWidth, int newHeight) const {
+        return Make(newWidth, newHeight, fColorType, fAlphaType, fColorSpace);
+    }
+
+    /** Creates SkImageInfo with same SkColorType, SkColorSpace, width, and height,
+        with SkAlphaType set to newAlphaType.
+
+        Created SkImageInfo contains newAlphaType even if it is incompatible with
+        SkColorType, in which case SkAlphaType in SkImageInfo is ignored.
+
+        @param newAlphaType  one of:
+                             kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+                             kUnpremul_SkAlphaType
+        @return              created SkImageInfo
+    */
+    SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const {
+        return Make(this->width(), this->height(), fColorType, newAlphaType, fColorSpace);
+    }
+
+    /** Creates SkImageInfo with same SkAlphaType, SkColorSpace, width, and height,
+        with SkColorType set to newColorType.
+
+        @param newColorType  one of:
+                             kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+                             kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+                             kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType,
+                             kRGB_101010x_SkColorType, kGray_8_SkColorType, kRGBA_F16_SkColorType
+        @return              created SkImageInfo
+    */
+    SkImageInfo makeColorType(SkColorType newColorType) const {
+        return Make(this->width(), this->height(), newColorType, fAlphaType, fColorSpace);
+    }
+
+    /** Creates SkImageInfo with same SkAlphaType, SkColorType, width, and height,
+        with SkColorSpace set to cs.
+
+        @param cs  range of colors; may be nullptr
+        @return    created SkImageInfo
+    */
+    SkImageInfo makeColorSpace(sk_sp<SkColorSpace> cs) const {
+        return Make(this->width(), this->height(), fColorType, fAlphaType, std::move(cs));
+    }
+
+    /** Returns number of bytes per pixel required by SkColorType.
+        Returns zero if colorType( is kUnknown_SkColorType.
+
+        @return  bytes in pixel
+    */
+    int bytesPerPixel() const;
+
+    /** Returns bit shift converting row bytes to row pixels.
+        Returns zero for kUnknown_SkColorType.
+
+        @return  one of: 0, 1, 2, 3; left shift to convert pixels to bytes
+    */
+    int shiftPerPixel() const;
+
+    /** Returns minimum bytes per row, computed from pixel width() and SkColorType, which
+        specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit
+        in 31 bits.
+
+        @return  width() times bytesPerPixel() as unsigned 64-bit integer
+    */
+    uint64_t minRowBytes64() const { return sk_64_mul(this->width(), this->bytesPerPixel()); }
+
+    /** Returns minimum bytes per row, computed from pixel width() and SkColorType, which
+        specifies bytesPerPixel(). SkBitmap maximum value for row bytes must fit
+        in 31 bits.
+
+        @return  width() times bytesPerPixel() as signed 32-bit integer
+    */
+    size_t minRowBytes() const {
+        uint64_t minRowBytes = this->minRowBytes64();
+        if (!SkTFitsIn<int32_t>(minRowBytes)) {
+            return 0;
+        }
+        return SkTo<int32_t>(minRowBytes);
+    }
+
+    /** Returns byte offset of pixel from pixel base address.
+
+        Asserts in debug build if x or y is outside of bounds. Does not assert if
+        rowBytes is smaller than minRowBytes(), even though result may be incorrect.
+
+        @param x         column index, zero or greater, and less than width()
+        @param y         row index, zero or greater, and less than height()
+        @param rowBytes  size of pixel row or larger
+        @return          offset within pixel array
+    */
+    size_t computeOffset(int x, int y, size_t rowBytes) const;
+
+    /** Compares SkImageInfo with other, and returns true if width, height, SkColorType,
+        SkAlphaType, and SkColorSpace are equivalent.
+
+        @param other  SkImageInfo to compare
+        @return       true if SkImageInfo equals other
+    */
+    bool operator==(const SkImageInfo& other) const {
+        return fDimensions == other.fDimensions &&
+               fColorType == other.fColorType && fAlphaType == other.fAlphaType &&
+               SkColorSpace::Equals(fColorSpace.get(), other.fColorSpace.get());
+    }
+
+    /** Compares SkImageInfo with other, and returns true if width, height, SkColorType,
+        SkAlphaType, and SkColorSpace are not equivalent.
+
+        @param other  SkImageInfo to compare
+        @return       true if SkImageInfo is not equal to other
+    */
+    bool operator!=(const SkImageInfo& other) const {
+        return !(*this == other);
+    }
+
+    /** Returns storage required by pixel array, given SkImageInfo dimensions, SkColorType,
+        and rowBytes. rowBytes is assumed to be at least as large as minRowBytes().
+
+        Returns zero if height is zero.
+        Returns SIZE_MAX if answer exceeds the range of size_t.
+
+        @param rowBytes  size of pixel row or larger
+        @return          memory required by pixel buffer
+    */
+    size_t computeByteSize(size_t rowBytes) const;
+
+    /** Returns storage required by pixel array, given SkImageInfo dimensions, and
+        SkColorType. Uses minRowBytes() to compute bytes for pixel row.
+
+        Returns zero if height is zero.
+        Returns SIZE_MAX if answer exceeds the range of size_t.
+
+        @return  least memory required by pixel buffer
+    */
+    size_t computeMinByteSize() const {
+        return this->computeByteSize(this->minRowBytes());
+    }
+
+    /** Returns true if byteSize equals SIZE_MAX. computeByteSize() and
+        computeMinByteSize() return SIZE_MAX if size_t can not hold buffer size.
+
+        @param byteSize  result of computeByteSize() or computeMinByteSize()
+        @return          true if computeByteSize() or computeMinByteSize() result exceeds size_t
+    */
+    static bool ByteSizeOverflowed(size_t byteSize) {
+        return SIZE_MAX == byteSize;
+    }
+
+    /** Returns true if rowBytes is smaller than width times pixel size.
+
+        @param rowBytes  size of pixel row or larger
+        @return          true if rowBytes is large enough to contain pixel row
+    */
+    bool validRowBytes(size_t rowBytes) const {
+        return rowBytes >= this->minRowBytes64();
+    }
+
+    /** Creates an empty SkImageInfo with kUnknown_SkColorType, kUnknown_SkAlphaType,
+        a width and height of zero, and no SkColorSpace.
+    */
+    void reset() {
+        fColorSpace = nullptr;
+        fDimensions = {0, 0};
+        fColorType = kUnknown_SkColorType;
+        fAlphaType = kUnknown_SkAlphaType;
+    }
+
+    /** Asserts if internal values are illegal or inconsistent. Only available if
+        SK_DEBUG is defined at compile time.
+    */
+    SkDEBUGCODE(void validate() const;)
+
+private:
+    sk_sp<SkColorSpace> fColorSpace;
+    SkISize             fDimensions;
+    SkColorType         fColorType;
+    SkAlphaType         fAlphaType;
+
+    SkImageInfo(int width, int height, SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs)
+        : fColorSpace(std::move(cs))
+        , fDimensions{width, height}
+        , fColorType(ct)
+        , fAlphaType(at)
+    {}
+};
+
+#endif

+ 195 - 0
skia/include/core/SkLights.h

@@ -0,0 +1,195 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkLights_DEFINED
+#define SkLights_DEFINED
+
+#include "SkPoint3.h"
+#include "SkRefCnt.h"
+#include "../private/SkTArray.h"
+
+class SkColorSpaceXformer;
+class SkReadBuffer;
+class SkWriteBuffer;
+
+/** \class SkLights
+    SkLights encapsulates a set of directional, point and ambient lights for use with the
+    SkLightingShader.
+*/
+class SK_API SkLights  : public SkRefCnt {
+public:
+    class Light {
+    public:
+        enum LightType {
+            kDirectional_LightType,
+            kPoint_LightType
+        };
+
+        Light(const Light& other)
+                : fType(other.fType)
+                , fColor(other.fColor)
+                , fDirOrPos(other.fDirOrPos)
+                , fIntensity(other.fIntensity) {}
+
+        Light(Light&& other)
+                : fType(other.fType)
+                , fColor(other.fColor)
+                , fDirOrPos(other.fDirOrPos)
+                , fIntensity(other.fIntensity) {}
+
+        static Light MakeDirectional(const SkColor3f& color, const SkVector3& dir) {
+            Light light(kDirectional_LightType, color, dir, 0.0f);
+            if (!light.fDirOrPos.normalize()) {
+                light.fDirOrPos.set(0.0f, 0.0f, 1.0f);
+            }
+            return light;
+        }
+
+        static Light MakePoint(const SkColor3f& color, const SkPoint3& pos, SkScalar intensity) {
+            return Light(kPoint_LightType, color, pos, intensity);
+        }
+
+        LightType type() const { return fType; }
+        const SkColor3f& color() const { return fColor; }
+        const SkVector3& dir() const {
+            SkASSERT(kDirectional_LightType == fType);
+            return fDirOrPos;
+        }
+        const SkPoint3& pos() const {
+            SkASSERT(kPoint_LightType == fType);
+            return fDirOrPos;
+        }
+        SkScalar intensity() const {
+            SkASSERT(kPoint_LightType == fType);
+            return fIntensity;
+        }
+
+        Light& operator=(const Light& other) {
+            if (this == &other) {
+                return *this;
+            }
+
+            fType = other.fType;
+            fColor = other.fColor;
+            fDirOrPos = other.fDirOrPos;
+            fIntensity = other.fIntensity;
+            return *this;
+        }
+
+        bool operator==(const Light& other) {
+            return (fType      == other.fType) &&
+                   (fColor     == other.fColor) &&
+                   (fDirOrPos  == other.fDirOrPos) &&
+                   (fIntensity == other.fIntensity);
+        }
+
+        bool operator!=(const Light& other) { return !(this->operator==(other)); }
+
+    private:
+        friend class SkLights;
+
+        Light(LightType type, const SkColor3f& color, const SkVector3& dirOrPos,
+              SkScalar intensity)
+                : fType(type)
+                , fColor(color)
+                , fDirOrPos(dirOrPos)
+                , fIntensity(intensity) {}
+
+        LightType   fType;
+        SkColor3f   fColor;           // linear (unpremul) color. Range is 0..1 in each channel.
+
+        SkVector3   fDirOrPos;        // For directional lights, holds the direction towards the
+                                      // light (+Z is out of the screen).
+                                      // If degenerate, it will be replaced with (0, 0, 1).
+                                      // For point lights, holds location of point light
+
+        SkScalar    fIntensity;       // For point lights, dictates the light intensity.
+                                      // Simply a multiplier to the final light output value.
+    };
+
+    class Builder {
+    public:
+        Builder() : fLights(new SkLights) {}
+
+        void add(const Light& light) {
+            if (fLights) {
+                fLights->fLights.push_back(light);
+            }
+        }
+
+        void add(Light&& light) {
+            if (fLights) {
+                fLights->fLights.push_back(std::move(light));
+            }
+        }
+
+        void setAmbientLightColor(const SkColor3f& color) {
+            if (fLights) {
+                fLights->fAmbientLightColor = color;
+            }
+        }
+
+        sk_sp<SkLights> finish() {
+            return std::move(fLights);
+        }
+
+    private:
+        sk_sp<SkLights> fLights;
+    };
+
+    /** Returns number of lights not including the ambient light.
+
+        @return number of lights not including the ambient light
+    */
+    int numLights() const { return fLights.count(); }
+
+    /** Returns the index-th light.
+
+        @param index  the index of the desired light
+        @return       the index-th light
+    */
+    const Light& light(int index) const { return fLights[index]; }
+
+    /** Returns the ambient light.
+
+        @return the ambient light
+    */
+    const SkColor3f& ambientLightColor() const {
+        return fAmbientLightColor;
+    }
+
+    /**
+     *  Recreate an SkLights object that was serialized into a buffer.
+     *
+     *  @param  SkReadBuffer Serialized blob data.
+     *  @return A new SkLights representing the serialized data, or NULL if the buffer is
+     *          invalid.
+     */
+    static sk_sp<SkLights> MakeFromBuffer(SkReadBuffer& buf);
+
+    /**
+     *  Serialize to a buffer.
+     *
+     *  @param  buffer the write buffer to write out to
+     */
+    void flatten(SkWriteBuffer& buf) const;
+
+private:
+    friend class SkLightingShaderImpl;
+
+    SkLights() : fAmbientLightColor(SkColor3f::Make(0.0f, 0.0f, 0.0f)) {}
+
+    sk_sp<SkLights> makeColorSpace(SkColorSpaceXformer* xformer) const;
+
+    SkTArray<Light> fLights;
+    SkColor3f       fAmbientLightColor;
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 93 - 0
skia/include/core/SkMallocPixelRef.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMallocPixelRef_DEFINED
+#define SkMallocPixelRef_DEFINED
+
+#include "SkPixelRef.h"
+#include "SkRefCnt.h"
+#include "SkTypes.h"
+class SkData;
+struct SkImageInfo;
+
+/** We explicitly use the same allocator for our pixels that SkMask does,
+    so that we can freely assign memory allocated by one class to the other.
+*/
+class SK_API SkMallocPixelRef : public SkPixelRef {
+public:
+    /**
+     *  Return a new SkMallocPixelRef with the provided pixel storage, rowBytes,
+     *  and optional colortable. The caller is responsible for managing the
+     *  lifetime of the pixel storage buffer, as this pixelref will not try
+     *  to delete it.
+     *
+     *  Returns NULL on failure.
+     */
+    static sk_sp<SkPixelRef> MakeDirect(const SkImageInfo&, void* addr, size_t rowBytes);
+
+    /**
+     *  Return a new SkMallocPixelRef, automatically allocating storage for the
+     *  pixels. If rowBytes are 0, an optimal value will be chosen automatically.
+     *  If rowBytes is > 0, then it will be respected, or NULL will be returned
+     *  if rowBytes is invalid for the specified info.
+     *
+     *  This pixelref will ref() the specified colortable (if not NULL).
+     *
+     *  Returns NULL on failure.
+     */
+    static sk_sp<SkPixelRef> MakeAllocate(const SkImageInfo&, size_t rowBytes);
+
+    /**
+     *  Identical to MakeAllocate, except all pixel bytes are zeroed.
+     */
+    static sk_sp<SkPixelRef> MakeZeroed(const SkImageInfo&, size_t rowBytes);
+
+    /**
+     *  Return a new SkMallocPixelRef with the provided pixel storage,
+     *  rowBytes, and optional colortable. On destruction, ReleaseProc
+     *  will be called.
+     *
+     *  If ReleaseProc is NULL, the pixels will never be released. This
+     *  can be useful if the pixels were stack allocated. However, such an
+     *  SkMallocPixelRef must not live beyond its pixels (e.g. by copying
+     *  an SkBitmap pointing to it, or drawing to an SkPicture).
+     *
+     *  Returns NULL on failure.
+     */
+    typedef void (*ReleaseProc)(void* addr, void* context);
+    static sk_sp<SkPixelRef> MakeWithProc(const SkImageInfo& info, size_t rowBytes, void* addr,
+                                          ReleaseProc proc, void* context);
+
+    /**
+     *  Return a new SkMallocPixelRef that will use the provided
+     *  SkData, rowBytes, and optional colortable as pixel storage.
+     *  The SkData will be ref()ed and on destruction of the PielRef,
+     *  the SkData will be unref()ed.
+     *
+     *  Returns NULL on failure.
+     */
+    static sk_sp<SkPixelRef> MakeWithData(const SkImageInfo&, size_t rowBytes, sk_sp<SkData> data);
+
+protected:
+    ~SkMallocPixelRef() override;
+
+private:
+    // Uses alloc to implement NewAllocate or NewZeroed.
+    static sk_sp<SkPixelRef> MakeUsing(void*(*alloc)(size_t),
+                                       const SkImageInfo&,
+                                       size_t rowBytes);
+
+    ReleaseProc fReleaseProc;
+    void*       fReleaseProcContext;
+
+    SkMallocPixelRef(const SkImageInfo&, void* addr, size_t rb, ReleaseProc proc, void* context);
+
+    typedef SkPixelRef INHERITED;
+};
+
+
+#endif

+ 77 - 0
skia/include/core/SkMaskFilter.h

@@ -0,0 +1,77 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMaskFilter_DEFINED
+#define SkMaskFilter_DEFINED
+
+#include "SkBlurTypes.h"
+#include "SkCoverageMode.h"
+#include "SkFlattenable.h"
+#include "SkScalar.h"
+
+class SkMatrix;
+struct SkRect;
+class SkString;
+
+/** \class SkMaskFilter
+
+    SkMaskFilter is the base class for object that perform transformations on
+    the mask before drawing it. An example subclass is Blur.
+*/
+class SK_API SkMaskFilter : public SkFlattenable {
+public:
+    /** Create a blur maskfilter.
+     *  @param style      The SkBlurStyle to use
+     *  @param sigma      Standard deviation of the Gaussian blur to apply. Must be > 0.
+     *  @param respectCTM if true the blur's sigma is modified by the CTM.
+     *  @return The new blur maskfilter
+     */
+    static sk_sp<SkMaskFilter> MakeBlur(SkBlurStyle style, SkScalar sigma,
+                                        bool respectCTM = true);
+
+    /**
+     *  Construct a maskfilter whose effect is to first apply the inner filter and then apply
+     *  the outer filter to the result of the inner's. Returns nullptr on failure.
+     */
+    static sk_sp<SkMaskFilter> MakeCompose(sk_sp<SkMaskFilter> outer, sk_sp<SkMaskFilter> inner);
+
+    /**
+     *  Compose two maskfilters together using a coverage mode. Returns nullptr on failure.
+     */
+    static sk_sp<SkMaskFilter> MakeCombine(sk_sp<SkMaskFilter> filterA, sk_sp<SkMaskFilter> filterB,
+                                           SkCoverageMode mode);
+
+    /**
+     *  Construct a maskfilter with an additional transform.
+     *
+     *  Note: unlike shader local matrices, this transform composes next to the CTM.
+     *
+     *    TotalMatrix = CTM x MaskFilterMatrix x (optional/downstream) ShaderLocalMatrix
+     */
+    sk_sp<SkMaskFilter> makeWithMatrix(const SkMatrix&) const;
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkMaskFilter_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkMaskFilter_Type;
+    }
+
+    static sk_sp<SkMaskFilter> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkMaskFilter>(static_cast<SkMaskFilter*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkMaskFilter_Type, data, size, procs).release()));
+    }
+
+private:
+    static void RegisterFlattenables();
+    friend class SkFlattenable;
+};
+
+#endif

+ 75 - 0
skia/include/core/SkMath.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMath_DEFINED
+#define SkMath_DEFINED
+
+#include "SkTypes.h"
+
+// 64bit -> 32bit utilities
+
+// Handy util that can be passed two ints, and will automatically promote to
+// 64bits before the multiply, so the caller doesn't have to remember to cast
+// e.g. (int64_t)a * b;
+static inline int64_t sk_64_mul(int64_t a, int64_t b) {
+    return a * b;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/** Given an integer and a positive (max) integer, return the value
+ *  pinned against 0 and max, inclusive.
+ *  @param value    The value we want returned pinned between [0...max]
+ *  @param max      The positive max value
+ *  @return 0 if value < 0, max if value > max, else value
+ */
+static inline int SkClampMax(int value, int max) {
+    // ensure that max is positive
+    SkASSERT(max >= 0);
+    if (value < 0) {
+        value = 0;
+    }
+    if (value > max) {
+        value = max;
+    }
+    return value;
+}
+
+/**
+ *  Returns true if value is a power of 2. Does not explicitly check for
+ *  value <= 0.
+ */
+template <typename T> constexpr inline bool SkIsPow2(T value) {
+    return (value & (value - 1)) == 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ *  Return a*b/((1 << shift) - 1), rounding any fractional bits.
+ *  Only valid if a and b are unsigned and <= 32767 and shift is > 0 and <= 8
+ */
+static inline unsigned SkMul16ShiftRound(U16CPU a, U16CPU b, int shift) {
+    SkASSERT(a <= 32767);
+    SkASSERT(b <= 32767);
+    SkASSERT(shift > 0 && shift <= 8);
+    unsigned prod = a*b + (1 << (shift - 1));
+    return (prod + (prod >> shift)) >> shift;
+}
+
+/**
+ *  Return a*b/255, rounding any fractional bits.
+ *  Only valid if a and b are unsigned and <= 32767.
+ */
+static inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) {
+    SkASSERT(a <= 32767);
+    SkASSERT(b <= 32767);
+    unsigned prod = a*b + 128;
+    return (prod + (prod >> 8)) >> 8;
+}
+
+#endif

+ 1863 - 0
skia/include/core/SkMatrix.h

@@ -0,0 +1,1863 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkMatrix.h and docs/SkMatrix_Reference.bmh
+   on 2018-09-13 13:59:55. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkMatrix_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkMatrix_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkMatrix.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkMatrix_DEFINED
+#define SkMatrix_DEFINED
+
+#include "../private/SkMacros.h"
+#include "../private/SkTo.h"
+#include "SkRect.h"
+
+struct SkRSXform;
+struct SkPoint3;
+class SkString;
+
+/** \class SkMatrix
+    SkMatrix holds a 3x3 matrix for transforming coordinates. This allows mapping
+    SkPoint and vectors with translation, scaling, skewing, rotation, and
+    perspective.
+
+    SkMatrix elements are in row major order. SkMatrix does not have a constructor,
+    so it must be explicitly initialized. setIdentity() initializes SkMatrix
+    so it has no effect. setTranslate(), setScale(), setSkew(), setRotate(), set9 and setAll()
+    initializes all SkMatrix elements with the corresponding mapping.
+
+    SkMatrix includes a hidden variable that classifies the type of matrix to
+    improve performance. SkMatrix is not thread safe unless getType() is called first.
+*/
+SK_BEGIN_REQUIRE_DENSE
+class SK_API SkMatrix {
+public:
+
+    /** Sets SkMatrix to scale by (sx, sy). Returned matrix is:
+
+            | sx  0  0 |
+            |  0 sy  0 |
+            |  0  0  1 |
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+        @return    SkMatrix with scale
+    */
+    static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar sx, SkScalar sy) {
+        SkMatrix m;
+        m.setScale(sx, sy);
+        return m;
+    }
+
+    /** Sets SkMatrix to scale by (scale, scale). Returned matrix is:
+
+            | scale   0   0 |
+            |   0   scale 0 |
+            |   0     0   1 |
+
+        @param scale  horizontal and vertical scale factor
+        @return       SkMatrix with scale
+    */
+    static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar scale) {
+        SkMatrix m;
+        m.setScale(scale, scale);
+        return m;
+    }
+
+    /** Sets SkMatrix to translate by (dx, dy). Returned matrix is:
+
+            | 1 0 dx |
+            | 0 1 dy |
+            | 0 0  1 |
+
+        @param dx  horizontal translation
+        @param dy  vertical translation
+        @return    SkMatrix with translation
+    */
+    static SkMatrix SK_WARN_UNUSED_RESULT MakeTrans(SkScalar dx, SkScalar dy) {
+        SkMatrix m;
+        m.setTranslate(dx, dy);
+        return m;
+    }
+
+    /** Sets SkMatrix to:
+
+            | scaleX  skewX transX |
+            |  skewY scaleY transY |
+            |  pers0  pers1  pers2 |
+
+        @param scaleX  horizontal scale factor
+        @param skewX   horizontal skew factor
+        @param transX  horizontal translation
+        @param skewY   vertical skew factor
+        @param scaleY  vertical scale factor
+        @param transY  vertical translation
+        @param pers0   input x-axis perspective factor
+        @param pers1   input y-axis perspective factor
+        @param pers2   perspective scale factor
+        @return        SkMatrix constructed from parameters
+    */
+    static SkMatrix SK_WARN_UNUSED_RESULT MakeAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
+                                                  SkScalar skewY,  SkScalar scaleY, SkScalar transY,
+                                                  SkScalar pers0, SkScalar pers1, SkScalar pers2) {
+        SkMatrix m;
+        m.setAll(scaleX, skewX, transX, skewY, scaleY, transY, pers0, pers1, pers2);
+        return m;
+    }
+
+    /** \enum SkMatrix::TypeMask
+        Enum of bit fields for mask returned by getType().
+        Used to identify the complexity of SkMatrix, to optimize performance.
+    */
+    enum TypeMask {
+        kIdentity_Mask    = 0,    //!< identity SkMatrix; all bits clear
+        kTranslate_Mask   = 0x01, //!< translation SkMatrix
+        kScale_Mask       = 0x02, //!< scale SkMatrix
+        kAffine_Mask      = 0x04, //!< skew or rotate SkMatrix
+        kPerspective_Mask = 0x08, //!< perspective SkMatrix
+    };
+
+    /** Returns a bit field describing the transformations the matrix may
+        perform. The bit field is computed conservatively, so it may include
+        false positives. For example, when kPerspective_Mask is set, all
+        other bits are set.
+
+        @return  kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask,
+                 kAffine_Mask, kPerspective_Mask
+    */
+    TypeMask getType() const {
+        if (fTypeMask & kUnknown_Mask) {
+            fTypeMask = this->computeTypeMask();
+        }
+        // only return the public masks
+        return (TypeMask)(fTypeMask & 0xF);
+    }
+
+    /** Returns true if SkMatrix is identity.  Identity matrix is:
+
+            | 1 0 0 |
+            | 0 1 0 |
+            | 0 0 1 |
+
+        @return  true if SkMatrix has no effect
+    */
+    bool isIdentity() const {
+        return this->getType() == 0;
+    }
+
+    /** Returns true if SkMatrix at most scales and translates. SkMatrix may be identity,
+        contain only scale elements, only translate elements, or both. SkMatrix form is:
+
+            | scale-x    0    translate-x |
+            |    0    scale-y translate-y |
+            |    0       0         1      |
+
+        @return  true if SkMatrix is identity; or scales, translates, or both
+    */
+    bool isScaleTranslate() const {
+        return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
+    }
+
+    /** Returns true if SkMatrix is identity, or translates. SkMatrix form is:
+
+            | 1 0 translate-x |
+            | 0 1 translate-y |
+            | 0 0      1      |
+
+        @return  true if SkMatrix is identity, or translates
+    */
+    bool isTranslate() const { return !(this->getType() & ~(kTranslate_Mask)); }
+
+    /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity,
+        or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
+        cases, SkMatrix may also have translation. SkMatrix form is either:
+
+            | scale-x    0    translate-x |
+            |    0    scale-y translate-y |
+            |    0       0         1      |
+
+        or
+
+            |    0     rotate-x translate-x |
+            | rotate-y    0     translate-y |
+            |    0        0          1      |
+
+        for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
+
+        Also called preservesAxisAlignment(); use the one that provides better inline
+        documentation.
+
+        @return  true if SkMatrix maps one SkRect into another
+    */
+    bool rectStaysRect() const {
+        if (fTypeMask & kUnknown_Mask) {
+            fTypeMask = this->computeTypeMask();
+        }
+        return (fTypeMask & kRectStaysRect_Mask) != 0;
+    }
+
+    /** Returns true SkMatrix maps SkRect to another SkRect. If true, SkMatrix is identity,
+        or scales, or rotates a multiple of 90 degrees, or mirrors on axes. In all
+        cases, SkMatrix may also have translation. SkMatrix form is either:
+
+            | scale-x    0    translate-x |
+            |    0    scale-y translate-y |
+            |    0       0         1      |
+
+        or
+
+            |    0     rotate-x translate-x |
+            | rotate-y    0     translate-y |
+            |    0        0          1      |
+
+        for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
+
+        Also called rectStaysRect(); use the one that provides better inline
+        documentation.
+
+        @return  true if SkMatrix maps one SkRect into another
+    */
+    bool preservesAxisAlignment() const { return this->rectStaysRect(); }
+
+    /** Returns true if the matrix contains perspective elements. SkMatrix form is:
+
+            |       --            --              --          |
+            |       --            --              --          |
+            | perspective-x  perspective-y  perspective-scale |
+
+        where perspective-x or perspective-y is non-zero, or perspective-scale is
+        not one. All other elements may have any value.
+
+        @return  true if SkMatrix is in most general form
+    */
+    bool hasPerspective() const {
+        return SkToBool(this->getPerspectiveTypeMaskOnly() &
+                        kPerspective_Mask);
+    }
+
+    /** Returns true if SkMatrix contains only translation, rotation, reflection, and
+        uniform scale.
+        Returns false if SkMatrix contains different scales, skewing, perspective, or
+        degenerate forms that collapse to a line or point.
+
+        Describes that the SkMatrix makes rendering with and without the matrix are
+        visually alike; a transformed circle remains a circle. Mathematically, this is
+        referred to as similarity of a Euclidean space, or a similarity transformation.
+
+        Preserves right angles, keeping the arms of the angle equal lengths.
+
+        @param tol  to be deprecated
+        @return     true if SkMatrix only rotates, uniformly scales, translates
+    */
+    bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
+
+    /** Returns true if SkMatrix contains only translation, rotation, reflection, and
+        scale. Scale may differ along rotated axes.
+        Returns false if SkMatrix skewing, perspective, or degenerate forms that collapse
+        to a line or point.
+
+        Preserves right angles, but not requiring that the arms of the angle
+        retain equal lengths.
+
+        @param tol  to be deprecated
+        @return     true if SkMatrix only rotates, scales, translates
+    */
+    bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
+
+    /** SkMatrix organizes its values in row order. These members correspond to
+        each value in SkMatrix.
+    */
+    static constexpr int kMScaleX = 0; //!< horizontal scale factor
+    static constexpr int kMSkewX  = 1; //!< horizontal skew factor
+    static constexpr int kMTransX = 2; //!< horizontal translation
+    static constexpr int kMSkewY  = 3; //!< vertical skew factor
+    static constexpr int kMScaleY = 4; //!< vertical scale factor
+    static constexpr int kMTransY = 5; //!< vertical translation
+    static constexpr int kMPersp0 = 6; //!< input x perspective factor
+    static constexpr int kMPersp1 = 7; //!< input y perspective factor
+    static constexpr int kMPersp2 = 8; //!< perspective bias
+
+    /** Affine arrays are in column major order to match the matrix used by
+        PDF and XPS.
+    */
+    static constexpr int kAScaleX = 0; //!< horizontal scale factor
+    static constexpr int kASkewY  = 1; //!< vertical skew factor
+    static constexpr int kASkewX  = 2; //!< horizontal skew factor
+    static constexpr int kAScaleY = 3; //!< vertical scale factor
+    static constexpr int kATransX = 4; //!< horizontal translation
+    static constexpr int kATransY = 5; //!< vertical translation
+
+    /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
+        defined.
+
+        @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
+                      kMPersp0, kMPersp1, kMPersp2
+        @return       value corresponding to index
+    */
+    SkScalar operator[](int index) const {
+        SkASSERT((unsigned)index < 9);
+        return fMat[index];
+    }
+
+    /** Returns one matrix value. Asserts if index is out of range and SK_DEBUG is
+        defined.
+
+        @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
+                      kMPersp0, kMPersp1, kMPersp2
+        @return       value corresponding to index
+    */
+    SkScalar get(int index) const {
+        SkASSERT((unsigned)index < 9);
+        return fMat[index];
+    }
+
+    /** Returns scale factor multiplied by x-axis input, contributing to x-axis output.
+        With mapPoints(), scales SkPoint along the x-axis.
+
+        @return  horizontal scale factor
+    */
+    SkScalar getScaleX() const { return fMat[kMScaleX]; }
+
+    /** Returns scale factor multiplied by y-axis input, contributing to y-axis output.
+        With mapPoints(), scales SkPoint along the y-axis.
+
+        @return  vertical scale factor
+    */
+    SkScalar getScaleY() const { return fMat[kMScaleY]; }
+
+    /** Returns scale factor multiplied by x-axis input, contributing to y-axis output.
+        With mapPoints(), skews SkPoint along the y-axis.
+        Skewing both axes can rotate SkPoint.
+
+        @return  vertical skew factor
+    */
+    SkScalar getSkewY() const { return fMat[kMSkewY]; }
+
+    /** Returns scale factor multiplied by y-axis input, contributing to x-axis output.
+        With mapPoints(), skews SkPoint along the x-axis.
+        Skewing both axes can rotate SkPoint.
+
+        @return  horizontal scale factor
+    */
+    SkScalar getSkewX() const { return fMat[kMSkewX]; }
+
+    /** Returns translation contributing to x-axis output.
+        With mapPoints(), moves SkPoint along the x-axis.
+
+        @return  horizontal translation factor
+    */
+    SkScalar getTranslateX() const { return fMat[kMTransX]; }
+
+    /** Returns translation contributing to y-axis output.
+        With mapPoints(), moves SkPoint along the y-axis.
+
+        @return  vertical translation factor
+    */
+    SkScalar getTranslateY() const { return fMat[kMTransY]; }
+
+    /** Returns factor scaling input x-axis relative to input y-axis.
+
+        @return  input x-axis perspective factor
+    */
+    SkScalar getPerspX() const { return fMat[kMPersp0]; }
+
+    /** Returns factor scaling input y-axis relative to input x-axis.
+
+        @return  input y-axis perspective factor
+    */
+    SkScalar getPerspY() const { return fMat[kMPersp1]; }
+
+    /** Returns writable SkMatrix value. Asserts if index is out of range and SK_DEBUG is
+        defined. Clears internal cache anticipating that caller will change SkMatrix value.
+
+        Next call to read SkMatrix state may recompute cache; subsequent writes to SkMatrix
+        value must be followed by dirtyMatrixTypeCache().
+
+        @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
+                      kMPersp0, kMPersp1, kMPersp2
+        @return       writable value corresponding to index
+    */
+    SkScalar& operator[](int index) {
+        SkASSERT((unsigned)index < 9);
+        this->setTypeMask(kUnknown_Mask);
+        return fMat[index];
+    }
+
+    /** Sets SkMatrix value. Asserts if index is out of range and SK_DEBUG is
+        defined. Safer than operator[]; internal cache is always maintained.
+
+        @param index  one of: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
+                      kMPersp0, kMPersp1, kMPersp2
+        @param value  scalar to store in SkMatrix
+    */
+    void set(int index, SkScalar value) {
+        SkASSERT((unsigned)index < 9);
+        fMat[index] = value;
+        this->setTypeMask(kUnknown_Mask);
+    }
+
+    /** Sets horizontal scale factor.
+
+        @param v  horizontal scale factor to store
+    */
+    void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
+
+    /** Sets vertical scale factor.
+
+        @param v  vertical scale factor to store
+    */
+    void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
+
+    /** Sets vertical skew factor.
+
+        @param v  vertical skew factor to store
+    */
+    void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
+
+    /** Sets horizontal skew factor.
+
+        @param v  horizontal skew factor to store
+    */
+    void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
+
+    /** Sets horizontal translation.
+
+        @param v  horizontal translation to store
+    */
+    void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
+
+    /** Sets vertical translation.
+
+        @param v  vertical translation to store
+    */
+    void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
+
+    /** Sets input x-axis perspective factor, which causes mapXY() to vary input x-axis values
+        inversely proportional to input y-axis values.
+
+        @param v  perspective factor
+    */
+    void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
+
+    /** Sets input y-axis perspective factor, which causes mapXY() to vary input y-axis values
+        inversely proportional to input x-axis values.
+
+        @param v  perspective factor
+    */
+    void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
+
+    /** Sets all values from parameters. Sets matrix to:
+
+            | scaleX  skewX transX |
+            |  skewY scaleY transY |
+            | persp0 persp1 persp2 |
+
+        @param scaleX  horizontal scale factor to store
+        @param skewX   horizontal skew factor to store
+        @param transX  horizontal translation to store
+        @param skewY   vertical skew factor to store
+        @param scaleY  vertical scale factor to store
+        @param transY  vertical translation to store
+        @param persp0  input x-axis values perspective factor to store
+        @param persp1  input y-axis values perspective factor to store
+        @param persp2  perspective scale factor to store
+    */
+    void setAll(SkScalar scaleX, SkScalar skewX,  SkScalar transX,
+                SkScalar skewY,  SkScalar scaleY, SkScalar transY,
+                SkScalar persp0, SkScalar persp1, SkScalar persp2) {
+        fMat[kMScaleX] = scaleX;
+        fMat[kMSkewX]  = skewX;
+        fMat[kMTransX] = transX;
+        fMat[kMSkewY]  = skewY;
+        fMat[kMScaleY] = scaleY;
+        fMat[kMTransY] = transY;
+        fMat[kMPersp0] = persp0;
+        fMat[kMPersp1] = persp1;
+        fMat[kMPersp2] = persp2;
+        this->setTypeMask(kUnknown_Mask);
+    }
+
+    /** Copies nine scalar values contained by SkMatrix into buffer, in member value
+        ascending order: kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY,
+        kMPersp0, kMPersp1, kMPersp2.
+
+        @param buffer  storage for nine scalar values
+    */
+    void get9(SkScalar buffer[9]) const {
+        memcpy(buffer, fMat, 9 * sizeof(SkScalar));
+    }
+
+    /** Sets SkMatrix to nine scalar values in buffer, in member value ascending order:
+        kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1,
+        kMPersp2.
+
+        Sets matrix to:
+
+            | buffer[0] buffer[1] buffer[2] |
+            | buffer[3] buffer[4] buffer[5] |
+            | buffer[6] buffer[7] buffer[8] |
+
+        In the future, set9 followed by get9 may not return the same values. Since SkMatrix
+        maps non-homogeneous coordinates, scaling all nine values produces an equivalent
+        transformation, possibly improving precision.
+
+        @param buffer  nine scalar values
+    */
+    void set9(const SkScalar buffer[9]);
+
+    /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to:
+
+            | 1 0 0 |
+            | 0 1 0 |
+            | 0 0 1 |
+
+        Also called setIdentity(); use the one that provides better inline
+        documentation.
+    */
+    void reset();
+
+    /** Sets SkMatrix to identity; which has no effect on mapped SkPoint. Sets SkMatrix to:
+
+            | 1 0 0 |
+            | 0 1 0 |
+            | 0 0 1 |
+
+        Also called reset(); use the one that provides better inline
+        documentation.
+    */
+    void setIdentity() { this->reset(); }
+
+    /** Sets SkMatrix to translate by (dx, dy).
+
+        @param dx  horizontal translation
+        @param dy  vertical translation
+    */
+    void setTranslate(SkScalar dx, SkScalar dy);
+
+    /** Sets SkMatrix to translate by (v.fX, v.fY).
+
+        @param v  vector containing horizontal and vertical translation
+    */
+    void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
+
+    /** Sets SkMatrix to scale by sx and sy, about a pivot point at (px, py).
+        The pivot point is unchanged when mapped with SkMatrix.
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to scale by sx and sy about at pivot point at (0, 0).
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+    */
+    void setScale(SkScalar sx, SkScalar sy);
+
+    /** Sets SkMatrix to rotate by degrees about a pivot point at (px, py).
+        The pivot point is unchanged when mapped with SkMatrix.
+
+        Positive degrees rotates clockwise.
+
+        @param degrees  angle of axes relative to upright axes
+        @param px       pivot on x-axis
+        @param py       pivot on y-axis
+    */
+    void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to rotate by degrees about a pivot point at (0, 0).
+        Positive degrees rotates clockwise.
+
+        @param degrees  angle of axes relative to upright axes
+    */
+    void setRotate(SkScalar degrees);
+
+    /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (px, py).
+        The pivot point is unchanged when mapped with SkMatrix.
+
+        Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
+        Vector length specifies scale.
+
+        @param sinValue  rotation vector x-axis component
+        @param cosValue  rotation vector y-axis component
+        @param px        pivot on x-axis
+        @param py        pivot on y-axis
+    */
+    void setSinCos(SkScalar sinValue, SkScalar cosValue,
+                   SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to rotate by sinValue and cosValue, about a pivot point at (0, 0).
+
+        Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
+        Vector length specifies scale.
+
+        @param sinValue  rotation vector x-axis component
+        @param cosValue  rotation vector y-axis component
+    */
+    void setSinCos(SkScalar sinValue, SkScalar cosValue);
+
+    /** Sets SkMatrix to rotate, scale, and translate using a compressed matrix form.
+
+        Vector (rsxForm.fSSin, rsxForm.fSCos) describes the angle of rotation relative
+        to (0, 1). Vector length specifies scale. Mapped point is rotated and scaled
+        by vector, then translated by (rsxForm.fTx, rsxForm.fTy).
+
+        @param rsxForm  compressed SkRSXform matrix
+        @return         reference to SkMatrix
+    */
+    SkMatrix& setRSXform(const SkRSXform& rsxForm);
+
+    /** Sets SkMatrix to skew by kx and ky, about a pivot point at (px, py).
+        The pivot point is unchanged when mapped with SkMatrix.
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to skew by kx and ky, about a pivot point at (0, 0).
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+    */
+    void setSkew(SkScalar kx, SkScalar ky);
+
+    /** Sets SkMatrix to SkMatrix a multiplied by SkMatrix b. Either a or b may be this.
+
+        Given:
+
+                | A B C |      | J K L |
+            a = | D E F |, b = | M N O |
+                | G H I |      | P Q R |
+
+        sets SkMatrix to:
+
+                    | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
+            a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
+                    | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
+
+        @param a  SkMatrix on left side of multiply expression
+        @param b  SkMatrix on right side of multiply expression
+    */
+    void setConcat(const SkMatrix& a, const SkMatrix& b);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from translation (dx, dy).
+        This can be thought of as moving the point to be mapped before applying SkMatrix.
+
+        Given:
+
+                     | A B C |               | 1 0 dx |
+            Matrix = | D E F |,  T(dx, dy) = | 0 1 dy |
+                     | G H I |               | 0 0  1 |
+
+        sets SkMatrix to:
+
+                                 | A B C | | 1 0 dx |   | A B A*dx+B*dy+C |
+            Matrix * T(dx, dy) = | D E F | | 0 1 dy | = | D E D*dx+E*dy+F |
+                                 | G H I | | 0 0  1 |   | G H G*dx+H*dy+I |
+
+        @param dx  x-axis translation before applying SkMatrix
+        @param dy  y-axis translation before applying SkMatrix
+    */
+    void preTranslate(SkScalar dx, SkScalar dy);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy)
+        about pivot point (px, py).
+        This can be thought of as scaling about a pivot point before applying SkMatrix.
+
+        Given:
+
+                     | A B C |                       | sx  0 dx |
+            Matrix = | D E F |,  S(sx, sy, px, py) = |  0 sy dy |
+                     | G H I |                       |  0  0  1 |
+
+        where
+
+            dx = px - sx * px
+            dy = py - sy * py
+
+        sets SkMatrix to:
+
+                                         | A B C | | sx  0 dx |   | A*sx B*sy A*dx+B*dy+C |
+            Matrix * S(sx, sy, px, py) = | D E F | |  0 sy dy | = | D*sx E*sy D*dx+E*dy+F |
+                                         | G H I | |  0  0  1 |   | G*sx H*sy G*dx+H*dy+I |
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from scaling by (sx, sy)
+        about pivot point (0, 0).
+        This can be thought of as scaling about the origin before applying SkMatrix.
+
+        Given:
+
+                     | A B C |               | sx  0  0 |
+            Matrix = | D E F |,  S(sx, sy) = |  0 sy  0 |
+                     | G H I |               |  0  0  1 |
+
+        sets SkMatrix to:
+
+                                 | A B C | | sx  0  0 |   | A*sx B*sy C |
+            Matrix * S(sx, sy) = | D E F | |  0 sy  0 | = | D*sx E*sy F |
+                                 | G H I | |  0  0  1 |   | G*sx H*sy I |
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+    */
+    void preScale(SkScalar sx, SkScalar sy);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees
+        about pivot point (px, py).
+        This can be thought of as rotating about a pivot point before applying SkMatrix.
+
+        Positive degrees rotates clockwise.
+
+        Given:
+
+                     | A B C |                        | c -s dx |
+            Matrix = | D E F |,  R(degrees, px, py) = | s  c dy |
+                     | G H I |                        | 0  0  1 |
+
+        where
+
+            c  = cos(degrees)
+            s  = sin(degrees)
+            dx =  s * py + (1 - c) * px
+            dy = -s * px + (1 - c) * py
+
+        sets SkMatrix to:
+
+                                          | A B C | | c -s dx |   | Ac+Bs -As+Bc A*dx+B*dy+C |
+            Matrix * R(degrees, px, py) = | D E F | | s  c dy | = | Dc+Es -Ds+Ec D*dx+E*dy+F |
+                                          | G H I | | 0  0  1 |   | Gc+Hs -Gs+Hc G*dx+H*dy+I |
+
+        @param degrees  angle of axes relative to upright axes
+        @param px       pivot on x-axis
+        @param py       pivot on y-axis
+    */
+    void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from rotating by degrees
+        about pivot point (0, 0).
+        This can be thought of as rotating about the origin before applying SkMatrix.
+
+        Positive degrees rotates clockwise.
+
+        Given:
+
+                     | A B C |                        | c -s 0 |
+            Matrix = | D E F |,  R(degrees, px, py) = | s  c 0 |
+                     | G H I |                        | 0  0 1 |
+
+        where
+
+            c  = cos(degrees)
+            s  = sin(degrees)
+
+        sets SkMatrix to:
+
+                                          | A B C | | c -s 0 |   | Ac+Bs -As+Bc C |
+            Matrix * R(degrees, px, py) = | D E F | | s  c 0 | = | Dc+Es -Ds+Ec F |
+                                          | G H I | | 0  0 1 |   | Gc+Hs -Gs+Hc I |
+
+        @param degrees  angle of axes relative to upright axes
+    */
+    void preRotate(SkScalar degrees);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky)
+        about pivot point (px, py).
+        This can be thought of as skewing about a pivot point before applying SkMatrix.
+
+        Given:
+
+                     | A B C |                       |  1 kx dx |
+            Matrix = | D E F |,  K(kx, ky, px, py) = | ky  1 dy |
+                     | G H I |                       |  0  0  1 |
+
+        where
+
+            dx = -kx * py
+            dy = -ky * px
+
+        sets SkMatrix to:
+
+                                         | A B C | |  1 kx dx |   | A+B*ky A*kx+B A*dx+B*dy+C |
+            Matrix * K(kx, ky, px, py) = | D E F | | ky  1 dy | = | D+E*ky D*kx+E D*dx+E*dy+F |
+                                         | G H I | |  0  0  1 |   | G+H*ky G*kx+H G*dx+H*dy+I |
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix constructed from skewing by (kx, ky)
+        about pivot point (0, 0).
+        This can be thought of as skewing about the origin before applying SkMatrix.
+
+        Given:
+
+                     | A B C |               |  1 kx 0 |
+            Matrix = | D E F |,  K(kx, ky) = | ky  1 0 |
+                     | G H I |               |  0  0 1 |
+
+        sets SkMatrix to:
+
+                                 | A B C | |  1 kx 0 |   | A+B*ky A*kx+B C |
+            Matrix * K(kx, ky) = | D E F | | ky  1 0 | = | D+E*ky D*kx+E F |
+                                 | G H I | |  0  0 1 |   | G+H*ky G*kx+H I |
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+    */
+    void preSkew(SkScalar kx, SkScalar ky);
+
+    /** Sets SkMatrix to SkMatrix multiplied by SkMatrix other.
+        This can be thought of mapping by other before applying SkMatrix.
+
+        Given:
+
+                     | A B C |          | J K L |
+            Matrix = | D E F |, other = | M N O |
+                     | G H I |          | P Q R |
+
+        sets SkMatrix to:
+
+                             | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
+            Matrix * other = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
+                             | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
+
+        @param other  SkMatrix on right side of multiply expression
+    */
+    void preConcat(const SkMatrix& other);
+
+    /** Sets SkMatrix to SkMatrix constructed from translation (dx, dy) multiplied by SkMatrix.
+        This can be thought of as moving the point to be mapped after applying SkMatrix.
+
+        Given:
+
+                     | J K L |               | 1 0 dx |
+            Matrix = | M N O |,  T(dx, dy) = | 0 1 dy |
+                     | P Q R |               | 0 0  1 |
+
+        sets SkMatrix to:
+
+                                 | 1 0 dx | | J K L |   | J+dx*P K+dx*Q L+dx*R |
+            T(dx, dy) * Matrix = | 0 1 dy | | M N O | = | M+dy*P N+dy*Q O+dy*R |
+                                 | 0 0  1 | | P Q R |   |      P      Q      R |
+
+        @param dx  x-axis translation after applying SkMatrix
+        @param dy  y-axis translation after applying SkMatrix
+    */
+    void postTranslate(SkScalar dx, SkScalar dy);
+
+    /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point
+        (px, py), multiplied by SkMatrix.
+        This can be thought of as scaling about a pivot point after applying SkMatrix.
+
+        Given:
+
+                     | J K L |                       | sx  0 dx |
+            Matrix = | M N O |,  S(sx, sy, px, py) = |  0 sy dy |
+                     | P Q R |                       |  0  0  1 |
+
+        where
+
+            dx = px - sx * px
+            dy = py - sy * py
+
+        sets SkMatrix to:
+
+                                         | sx  0 dx | | J K L |   | sx*J+dx*P sx*K+dx*Q sx*L+dx+R |
+            S(sx, sy, px, py) * Matrix = |  0 sy dy | | M N O | = | sy*M+dy*P sy*N+dy*Q sy*O+dy*R |
+                                         |  0  0  1 | | P Q R |   |         P         Q         R |
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix constructed from scaling by (sx, sy) about pivot point
+        (0, 0), multiplied by SkMatrix.
+        This can be thought of as scaling about the origin after applying SkMatrix.
+
+        Given:
+
+                     | J K L |               | sx  0  0 |
+            Matrix = | M N O |,  S(sx, sy) = |  0 sy  0 |
+                     | P Q R |               |  0  0  1 |
+
+        sets SkMatrix to:
+
+                                 | sx  0  0 | | J K L |   | sx*J sx*K sx*L |
+            S(sx, sy) * Matrix = |  0 sy  0 | | M N O | = | sy*M sy*N sy*O |
+                                 |  0  0  1 | | P Q R |   |    P    Q    R |
+
+        @param sx  horizontal scale factor
+        @param sy  vertical scale factor
+    */
+    void postScale(SkScalar sx, SkScalar sy);
+
+    /** Sets SkMatrix to SkMatrix constructed from scaling by (1/divx, 1/divy),
+        about pivot point (px, py), multiplied by SkMatrix.
+
+        Returns false if either divx or divy is zero.
+
+        Given:
+
+                     | J K L |                   | sx  0  0 |
+            Matrix = | M N O |,  I(divx, divy) = |  0 sy  0 |
+                     | P Q R |                   |  0  0  1 |
+
+        where
+
+            sx = 1 / divx
+            sy = 1 / divy
+
+        sets SkMatrix to:
+
+                                     | sx  0  0 | | J K L |   | sx*J sx*K sx*L |
+            I(divx, divy) * Matrix = |  0 sy  0 | | M N O | = | sy*M sy*N sy*O |
+                                     |  0  0  1 | | P Q R |   |    P    Q    R |
+
+        @param divx  integer divisor for inverse scale in x
+        @param divy  integer divisor for inverse scale in y
+        @return      true on successful scale
+    */
+    bool postIDiv(int divx, int divy);
+
+    /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point
+        (px, py), multiplied by SkMatrix.
+        This can be thought of as rotating about a pivot point after applying SkMatrix.
+
+        Positive degrees rotates clockwise.
+
+        Given:
+
+                     | J K L |                        | c -s dx |
+            Matrix = | M N O |,  R(degrees, px, py) = | s  c dy |
+                     | P Q R |                        | 0  0  1 |
+
+        where
+
+            c  = cos(degrees)
+            s  = sin(degrees)
+            dx =  s * py + (1 - c) * px
+            dy = -s * px + (1 - c) * py
+
+        sets SkMatrix to:
+
+                                          |c -s dx| |J K L|   |cJ-sM+dx*P cK-sN+dx*Q cL-sO+dx+R|
+            R(degrees, px, py) * Matrix = |s  c dy| |M N O| = |sJ+cM+dy*P sK+cN+dy*Q sL+cO+dy*R|
+                                          |0  0  1| |P Q R|   |         P          Q          R|
+
+        @param degrees  angle of axes relative to upright axes
+        @param px       pivot on x-axis
+        @param py       pivot on y-axis
+    */
+    void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix constructed from rotating by degrees about pivot point
+        (0, 0), multiplied by SkMatrix.
+        This can be thought of as rotating about the origin after applying SkMatrix.
+
+        Positive degrees rotates clockwise.
+
+        Given:
+
+                     | J K L |                        | c -s 0 |
+            Matrix = | M N O |,  R(degrees, px, py) = | s  c 0 |
+                     | P Q R |                        | 0  0 1 |
+
+        where
+
+            c  = cos(degrees)
+            s  = sin(degrees)
+
+        sets SkMatrix to:
+
+                                          | c -s dx | | J K L |   | cJ-sM cK-sN cL-sO |
+            R(degrees, px, py) * Matrix = | s  c dy | | M N O | = | sJ+cM sK+cN sL+cO |
+                                          | 0  0  1 | | P Q R |   |     P     Q     R |
+
+        @param degrees  angle of axes relative to upright axes
+    */
+    void postRotate(SkScalar degrees);
+
+    /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point
+        (px, py), multiplied by SkMatrix.
+        This can be thought of as skewing about a pivot point after applying SkMatrix.
+
+        Given:
+
+                     | J K L |                       |  1 kx dx |
+            Matrix = | M N O |,  K(kx, ky, px, py) = | ky  1 dy |
+                     | P Q R |                       |  0  0  1 |
+
+        where
+
+            dx = -kx * py
+            dy = -ky * px
+
+        sets SkMatrix to:
+
+                                         | 1 kx dx| |J K L|   |J+kx*M+dx*P K+kx*N+dx*Q L+kx*O+dx+R|
+            K(kx, ky, px, py) * Matrix = |ky  1 dy| |M N O| = |ky*J+M+dy*P ky*K+N+dy*Q ky*L+O+dy*R|
+                                         | 0  0  1| |P Q R|   |          P           Q           R|
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+        @param px  pivot on x-axis
+        @param py  pivot on y-axis
+    */
+    void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
+
+    /** Sets SkMatrix to SkMatrix constructed from skewing by (kx, ky) about pivot point
+        (0, 0), multiplied by SkMatrix.
+        This can be thought of as skewing about the origin after applying SkMatrix.
+
+        Given:
+
+                     | J K L |               |  1 kx 0 |
+            Matrix = | M N O |,  K(kx, ky) = | ky  1 0 |
+                     | P Q R |               |  0  0 1 |
+
+        sets SkMatrix to:
+
+                                 |  1 kx 0 | | J K L |   | J+kx*M K+kx*N L+kx*O |
+            K(kx, ky) * Matrix = | ky  1 0 | | M N O | = | ky*J+M ky*K+N ky*L+O |
+                                 |  0  0 1 | | P Q R |   |      P      Q      R |
+
+        @param kx  horizontal skew factor
+        @param ky  vertical skew factor
+    */
+    void postSkew(SkScalar kx, SkScalar ky);
+
+    /** Sets SkMatrix to SkMatrix other multiplied by SkMatrix.
+        This can be thought of mapping by other after applying SkMatrix.
+
+        Given:
+
+                     | J K L |           | A B C |
+            Matrix = | M N O |,  other = | D E F |
+                     | P Q R |           | G H I |
+
+        sets SkMatrix to:
+
+                             | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
+            other * Matrix = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
+                             | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
+
+        @param other  SkMatrix on left side of multiply expression
+    */
+    void postConcat(const SkMatrix& other);
+
+    /** \enum SkMatrix::ScaleToFit
+        ScaleToFit describes how SkMatrix is constructed to map one SkRect to another.
+        ScaleToFit may allow SkMatrix to have unequal horizontal and vertical scaling,
+        or may restrict SkMatrix to square scaling. If restricted, ScaleToFit specifies
+        how SkMatrix maps to the side or center of the destination SkRect.
+    */
+    enum ScaleToFit {
+        kFill_ScaleToFit,   //!< scales in x and y to fill destination SkRect
+        kStart_ScaleToFit,  //!< scales and aligns to left and top
+        kCenter_ScaleToFit, //!< scales and aligns to center
+        kEnd_ScaleToFit,    //!< scales and aligns to right and bottom
+    };
+
+    /** Sets SkMatrix to scale and translate src SkRect to dst SkRect. stf selects whether
+        mapping completely fills dst or preserves the aspect ratio, and how to align
+        src within dst. Returns false if src is empty, and sets SkMatrix to identity.
+        Returns true if dst is empty, and sets SkMatrix to:
+
+            | 0 0 0 |
+            | 0 0 0 |
+            | 0 0 1 |
+
+        @param src  SkRect to map from
+        @param dst  SkRect to map to
+        @param stf  one of: kFill_ScaleToFit, kStart_ScaleToFit,
+                    kCenter_ScaleToFit, kEnd_ScaleToFit
+        @return     true if SkMatrix can represent SkRect mapping
+    */
+    bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
+
+    /** Returns SkMatrix set to scale and translate src SkRect to dst SkRect. stf selects
+        whether mapping completely fills dst or preserves the aspect ratio, and how to
+        align src within dst. Returns the identity SkMatrix if src is empty. If dst is
+        empty, returns SkMatrix set to:
+
+            | 0 0 0 |
+            | 0 0 0 |
+            | 0 0 1 |
+
+        @param src  SkRect to map from
+        @param dst  SkRect to map to
+        @param stf  one of: kFill_ScaleToFit, kStart_ScaleToFit,
+                    kCenter_ScaleToFit, kEnd_ScaleToFit
+        @return     SkMatrix mapping src to dst
+    */
+    static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) {
+        SkMatrix m;
+        m.setRectToRect(src, dst, stf);
+        return m;
+    }
+
+    /** Sets SkMatrix to map src to dst. count must be zero or greater, and four or less.
+
+        If count is zero, sets SkMatrix to identity and returns true.
+        If count is one, sets SkMatrix to translate and returns true.
+        If count is two or more, sets SkMatrix to map SkPoint if possible; returns false
+        if SkMatrix cannot be constructed. If count is four, SkMatrix may include
+        perspective.
+
+        @param src    SkPoint to map from
+        @param dst    SkPoint to map to
+        @param count  number of SkPoint in src and dst
+        @return       true if SkMatrix was constructed successfully
+    */
+    bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
+
+    /** Sets inverse to reciprocal matrix, returning true if SkMatrix can be inverted.
+        Geometrically, if SkMatrix maps from source to destination, inverse SkMatrix
+        maps from destination to source. If SkMatrix can not be inverted, inverse is
+        unchanged.
+
+        @param inverse  storage for inverted SkMatrix; may be nullptr
+        @return         true if SkMatrix can be inverted
+    */
+    bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
+        // Allow the trivial case to be inlined.
+        if (this->isIdentity()) {
+            if (inverse) {
+                inverse->reset();
+            }
+            return true;
+        }
+        return this->invertNonIdentity(inverse);
+    }
+
+    /** Fills affine with identity values in column major order.
+        Sets affine to:
+
+            | 1 0 0 |
+            | 0 1 0 |
+
+        Affine 3 by 2 matrices in column major order are used by OpenGL and XPS.
+
+        @param affine  storage for 3 by 2 affine matrix
+    */
+    static void SetAffineIdentity(SkScalar affine[6]);
+
+    /** Fills affine in column major order. Sets affine to:
+
+            | scale-x  skew-x translate-x |
+            | skew-y  scale-y translate-y |
+
+        If SkMatrix contains perspective, returns false and leaves affine unchanged.
+
+        @param affine  storage for 3 by 2 affine matrix; may be nullptr
+        @return        true if SkMatrix does not contain perspective
+    */
+    bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const;
+
+    /** Sets SkMatrix to affine values, passed in column major order. Given affine,
+        column, then row, as:
+
+            | scale-x  skew-x translate-x |
+            |  skew-y scale-y translate-y |
+
+        SkMatrix is set, row, then column, to:
+
+            | scale-x  skew-x translate-x |
+            |  skew-y scale-y translate-y |
+            |       0       0           1 |
+
+        @param affine  3 by 2 affine matrix
+    */
+    void setAffine(const SkScalar affine[6]);
+
+    /** Maps src SkPoint array of length count to dst SkPoint array of equal or greater
+        length. SkPoint are mapped by multiplying each SkPoint by SkMatrix. Given:
+
+                     | A B C |        | x |
+            Matrix = | D E F |,  pt = | y |
+                     | G H I |        | 1 |
+
+        where
+
+            for (i = 0; i < count; ++i) {
+                x = src[i].fX
+                y = src[i].fY
+            }
+
+        each dst SkPoint is computed as:
+
+                          |A B C| |x|                               Ax+By+C   Dx+Ey+F
+            Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+                          |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
+
+        src and dst may point to the same storage.
+
+        @param dst    storage for mapped SkPoint
+        @param src    SkPoint to transform
+        @param count  number of SkPoint to transform
+    */
+    void mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
+        SkASSERT((dst && src && count > 0) || 0 == count);
+        // no partial overlap
+        SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
+        this->getMapPtsProc()(*this, dst, src, count);
+    }
+
+    /** Maps pts SkPoint array of length count in place. SkPoint are mapped by multiplying
+        each SkPoint by SkMatrix. Given:
+
+                     | A B C |        | x |
+            Matrix = | D E F |,  pt = | y |
+                     | G H I |        | 1 |
+
+        where
+
+            for (i = 0; i < count; ++i) {
+                x = pts[i].fX
+                y = pts[i].fY
+            }
+
+        each resulting pts SkPoint is computed as:
+
+                          |A B C| |x|                               Ax+By+C   Dx+Ey+F
+            Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+                          |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
+
+        @param pts    storage for mapped SkPoint
+        @param count  number of SkPoint to transform
+    */
+    void mapPoints(SkPoint pts[], int count) const {
+        this->mapPoints(pts, pts, count);
+    }
+
+    /** Maps src SkPoint3 array of length count to dst SkPoint3 array, which must of length count or
+        greater. SkPoint3 array is mapped by multiplying each SkPoint3 by SkMatrix. Given:
+
+                     | A B C |         | x |
+            Matrix = | D E F |,  src = | y |
+                     | G H I |         | z |
+
+        each resulting dst SkPoint is computed as:
+
+                           |A B C| |x|
+            Matrix * src = |D E F| |y| = |Ax+By+Cz Dx+Ey+Fz Gx+Hy+Iz|
+                           |G H I| |z|
+
+        @param dst    storage for mapped SkPoint3 array
+        @param src    SkPoint3 array to transform
+        @param count  items in SkPoint3 array to transform
+    */
+    void mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const;
+
+    /** Maps SkPoint (x, y) to result. SkPoint is mapped by multiplying by SkMatrix. Given:
+
+                     | A B C |        | x |
+            Matrix = | D E F |,  pt = | y |
+                     | G H I |        | 1 |
+
+        result is computed as:
+
+                          |A B C| |x|                               Ax+By+C   Dx+Ey+F
+            Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+                          |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
+
+        @param x       x-axis value of SkPoint to map
+        @param y       y-axis value of SkPoint to map
+        @param result  storage for mapped SkPoint
+    */
+    void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
+        SkASSERT(result);
+        this->getMapXYProc()(*this, x, y, result);
+    }
+
+    /** Returns SkPoint (x, y) multiplied by SkMatrix. Given:
+
+                     | A B C |        | x |
+            Matrix = | D E F |,  pt = | y |
+                     | G H I |        | 1 |
+
+        result is computed as:
+
+                          |A B C| |x|                               Ax+By+C   Dx+Ey+F
+            Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+                          |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
+
+        @param x  x-axis value of SkPoint to map
+        @param y  y-axis value of SkPoint to map
+        @return   mapped SkPoint
+    */
+    SkPoint mapXY(SkScalar x, SkScalar y) const {
+        SkPoint result;
+        this->getMapXYProc()(*this, x, y, &result);
+        return result;
+    }
+
+    /** Maps src vector array of length count to vector SkPoint array of equal or greater
+        length. Vectors are mapped by multiplying each vector by SkMatrix, treating
+        SkMatrix translation as zero. Given:
+
+                     | A B 0 |         | x |
+            Matrix = | D E 0 |,  src = | y |
+                     | G H I |         | 1 |
+
+        where
+
+            for (i = 0; i < count; ++i) {
+                x = src[i].fX
+                y = src[i].fY
+            }
+
+        each dst vector is computed as:
+
+                           |A B 0| |x|                            Ax+By     Dx+Ey
+            Matrix * src = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , -------
+                           |G H I| |1|                           Gx+Hy+I   Gx+Hy+I
+
+        src and dst may point to the same storage.
+
+        @param dst    storage for mapped vectors
+        @param src    vectors to transform
+        @param count  number of vectors to transform
+    */
+    void mapVectors(SkVector dst[], const SkVector src[], int count) const;
+
+    /** Maps vecs vector array of length count in place, multiplying each vector by
+        SkMatrix, treating SkMatrix translation as zero. Given:
+
+                     | A B 0 |         | x |
+            Matrix = | D E 0 |,  vec = | y |
+                     | G H I |         | 1 |
+
+        where
+
+            for (i = 0; i < count; ++i) {
+                x = vecs[i].fX
+                y = vecs[i].fY
+            }
+
+        each result vector is computed as:
+
+                           |A B 0| |x|                            Ax+By     Dx+Ey
+            Matrix * vec = |D E 0| |y| = |Ax+By Dx+Ey Gx+Hy+I| = ------- , -------
+                           |G H I| |1|                           Gx+Hy+I   Gx+Hy+I
+
+        @param vecs   vectors to transform, and storage for mapped vectors
+        @param count  number of vectors to transform
+    */
+    void mapVectors(SkVector vecs[], int count) const {
+        this->mapVectors(vecs, vecs, count);
+    }
+
+    /** Maps vector (dx, dy) to result. Vector is mapped by multiplying by SkMatrix,
+        treating SkMatrix translation as zero. Given:
+
+                     | A B 0 |         | dx |
+            Matrix = | D E 0 |,  vec = | dy |
+                     | G H I |         |  1 |
+
+        each result vector is computed as:
+
+                       |A B 0| |dx|                                        A*dx+B*dy     D*dx+E*dy
+        Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , -----------
+                       |G H I| | 1|                                       G*dx+H*dy+I   G*dx+*dHy+I
+
+        @param dx      x-axis value of vector to map
+        @param dy      y-axis value of vector to map
+        @param result  storage for mapped vector
+    */
+    void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const {
+        SkVector vec = { dx, dy };
+        this->mapVectors(result, &vec, 1);
+    }
+
+    /** Returns vector (dx, dy) multiplied by SkMatrix, treating SkMatrix translation as zero.
+        Given:
+
+                     | A B 0 |         | dx |
+            Matrix = | D E 0 |,  vec = | dy |
+                     | G H I |         |  1 |
+
+        each result vector is computed as:
+
+                       |A B 0| |dx|                                        A*dx+B*dy     D*dx+E*dy
+        Matrix * vec = |D E 0| |dy| = |A*dx+B*dy D*dx+E*dy G*dx+H*dy+I| = ----------- , -----------
+                       |G H I| | 1|                                       G*dx+H*dy+I   G*dx+*dHy+I
+
+        @param dx  x-axis value of vector to map
+        @param dy  y-axis value of vector to map
+        @return    mapped vector
+    */
+    SkVector mapVector(SkScalar dx, SkScalar dy) const {
+        SkVector vec = { dx, dy };
+        this->mapVectors(&vec, &vec, 1);
+        return vec;
+    }
+
+    /** Sets dst to bounds of src corners mapped by SkMatrix.
+        Returns true if mapped corners are dst corners.
+
+        Returned value is the same as calling rectStaysRect().
+
+        @param dst  storage for bounds of mapped SkPoint
+        @param src  SkRect to map
+        @return     true if dst is equivalent to mapped src
+    */
+    bool mapRect(SkRect* dst, const SkRect& src) const;
+
+    /** Sets rect to bounds of rect corners mapped by SkMatrix.
+        Returns true if mapped corners are computed rect corners.
+
+        Returned value is the same as calling rectStaysRect().
+
+        @param rect  rectangle to map, and storage for bounds of mapped corners
+        @return      true if result is equivalent to mapped rect
+    */
+    bool mapRect(SkRect* rect) const {
+        return this->mapRect(rect, *rect);
+    }
+
+    /** Returns bounds of src corners mapped by SkMatrix.
+
+        @param src  rectangle to map
+        @return     mapped bounds
+    */
+    SkRect mapRect(const SkRect& src) const {
+        SkRect dst;
+        (void)this->mapRect(&dst, src);
+        return dst;
+    }
+
+    /** Maps four corners of rect to dst. SkPoint are mapped by multiplying each
+        rect corner by SkMatrix. rect corner is processed in this order:
+        (rect.fLeft, rect.fTop), (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom),
+        (rect.fLeft, rect.fBottom).
+
+        rect may be empty: rect.fLeft may be greater than or equal to rect.fRight;
+        rect.fTop may be greater than or equal to rect.fBottom.
+
+        Given:
+
+                     | A B C |        | x |
+            Matrix = | D E F |,  pt = | y |
+                     | G H I |        | 1 |
+
+        where pt is initialized from each of (rect.fLeft, rect.fTop),
+        (rect.fRight, rect.fTop), (rect.fRight, rect.fBottom), (rect.fLeft, rect.fBottom),
+        each dst SkPoint is computed as:
+
+                          |A B C| |x|                               Ax+By+C   Dx+Ey+F
+            Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+                          |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
+
+        @param dst   storage for mapped corner SkPoint
+        @param rect  SkRect to map
+    */
+    void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
+        // This could potentially be faster if we only transformed each x and y of the rect once.
+        rect.toQuad(dst);
+        this->mapPoints(dst, 4);
+    }
+
+    /** Sets dst to bounds of src corners mapped by SkMatrix. If matrix contains
+        elements other than scale or translate: asserts if SK_DEBUG is defined;
+        otherwise, results are undefined.
+
+        @param dst  storage for bounds of mapped SkPoint
+        @param src  SkRect to map
+    */
+    void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
+
+    /** Returns geometric mean radius of ellipse formed by constructing circle of
+        size radius, and mapping constructed circle with SkMatrix. The result squared is
+        equal to the major axis length times the minor axis length.
+        Result is not meaningful if SkMatrix contains perspective elements.
+
+        @param radius  circle size to map
+        @return        average mapped radius
+    */
+    SkScalar mapRadius(SkScalar radius) const;
+
+    /** Returns true if a unit step on x-axis at some y-axis value mapped through SkMatrix
+        can be represented by a constant vector. Returns true if getType() returns
+        kIdentity_Mask, or combinations of: kTranslate_Mask, kScale_Mask, and kAffine_Mask.
+
+        May return true if getType() returns kPerspective_Mask, but only when SkMatrix
+        does not include rotation or skewing along the y-axis.
+
+        @return  true if SkMatrix does not have complex perspective
+    */
+    bool isFixedStepInX() const;
+
+    /** Returns vector representing a unit step on x-axis at y mapped through SkMatrix.
+        If isFixedStepInX() is false, returned value is undefined.
+
+        @param y  position of line parallel to x-axis
+        @return   vector advance of mapped unit step on x-axis
+    */
+    SkVector fixedStepInX(SkScalar y) const;
+
+    /** Returns true if SkMatrix equals m, using an efficient comparison.
+
+        Returns false when the sign of zero values is the different; when one
+        matrix has positive zero value and the other has negative zero value.
+
+        Returns true even when both SkMatrix contain NaN.
+
+        NaN never equals any value, including itself. To improve performance, NaN values
+        are treated as bit patterns that are equal if their bit patterns are equal.
+
+        @param m  SkMatrix to compare
+        @return   true if m and SkMatrix are represented by identical bit patterns
+    */
+    bool cheapEqualTo(const SkMatrix& m) const {
+        return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
+    }
+
+    /** Compares a and b; returns true if a and b are numerically equal. Returns true
+        even if sign of zero values are different. Returns false if either SkMatrix
+        contains NaN, even if the other SkMatrix also contains NaN.
+
+        @param a  SkMatrix to compare
+        @param b  SkMatrix to compare
+        @return   true if SkMatrix a and SkMatrix b are numerically equal
+    */
+    friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
+
+    /** Compares a and b; returns true if a and b are not numerically equal. Returns false
+        even if sign of zero values are different. Returns true if either SkMatrix
+        contains NaN, even if the other SkMatrix also contains NaN.
+
+        @param a  SkMatrix to compare
+        @param b  SkMatrix to compare
+        @return   true if SkMatrix a and SkMatrix b are numerically not equal
+    */
+    friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
+        return !(a == b);
+    }
+
+    /** Writes text representation of SkMatrix to standard output. Floating point values
+        are written with limited precision; it may not be possible to reconstruct
+        original SkMatrix from output.
+    */
+    void dump() const;
+
+    /** Returns the minimum scaling factor of SkMatrix by decomposing the scaling and
+        skewing elements.
+        Returns -1 if scale factor overflows or SkMatrix contains perspective.
+
+        @return  minimum scale factor
+    */
+    SkScalar getMinScale() const;
+
+    /** Returns the maximum scaling factor of SkMatrix by decomposing the scaling and
+        skewing elements.
+        Returns -1 if scale factor overflows or SkMatrix contains perspective.
+
+        @return  maximum scale factor
+    */
+    SkScalar getMaxScale() const;
+
+    /** Sets scaleFactors[0] to the minimum scaling factor, and scaleFactors[1] to the
+        maximum scaling factor. Scaling factors are computed by decomposing
+        the SkMatrix scaling and skewing elements.
+
+        Returns true if scaleFactors are found; otherwise, returns false and sets
+        scaleFactors to undefined values.
+
+        @param scaleFactors  storage for minimum and maximum scale factors
+        @return              true if scale factors were computed correctly
+    */
+    bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const;
+
+    /** Decomposes SkMatrix into scale components and whatever remains. Returns false if
+        SkMatrix could not be decomposed.
+
+        Sets scale to portion of SkMatrix that scale axes. Sets remaining to SkMatrix
+        with scaling factored out. remaining may be passed as nullptr
+        to determine if SkMatrix can be decomposed without computing remainder.
+
+        Returns true if scale components are found. scale and remaining are
+        unchanged if SkMatrix contains perspective; scale factors are not finite, or
+        are nearly zero.
+
+        On success: Matrix = scale * Remaining.
+
+        @param scale      axes scaling factors; may be nullptr
+        @param remaining  SkMatrix without scaling; may be nullptr
+        @return           true if scale can be computed
+    */
+    bool decomposeScale(SkSize* scale, SkMatrix* remaining = nullptr) const;
+
+    /** Returns reference to const identity SkMatrix. Returned SkMatrix is set to:
+
+            | 1 0 0 |
+            | 0 1 0 |
+            | 0 0 1 |
+
+        @return  const identity SkMatrix
+    */
+    static const SkMatrix& I();
+
+    /** Returns reference to a const SkMatrix with invalid values. Returned SkMatrix is set
+        to:
+
+            | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
+            | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
+            | SK_ScalarMax SK_ScalarMax SK_ScalarMax |
+
+        @return  const invalid SkMatrix
+    */
+    static const SkMatrix& InvalidMatrix();
+
+    /** Returns SkMatrix a multiplied by SkMatrix b.
+
+        Given:
+
+                | A B C |      | J K L |
+            a = | D E F |, b = | M N O |
+                | G H I |      | P Q R |
+
+        sets SkMatrix to:
+
+                    | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
+            a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
+                    | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
+
+        @param a  SkMatrix on left side of multiply expression
+        @param b  SkMatrix on right side of multiply expression
+        @return   SkMatrix computed from a times b
+    */
+    static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
+        SkMatrix result;
+        result.setConcat(a, b);
+        return result;
+    }
+
+    /** Sets internal cache to unknown state. Use to force update after repeated
+        modifications to SkMatrix element reference returned by operator[](int index).
+    */
+    void dirtyMatrixTypeCache() {
+        this->setTypeMask(kUnknown_Mask);
+    }
+
+    /** Initializes SkMatrix with scale and translate elements.
+
+            | sx  0 tx |
+            |  0 sy ty |
+            |  0  0  1 |
+
+        @param sx  horizontal scale factor to store
+        @param sy  vertical scale factor to store
+        @param tx  horizontal translation to store
+        @param ty  vertical translation to store
+    */
+    void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
+        fMat[kMScaleX] = sx;
+        fMat[kMSkewX]  = 0;
+        fMat[kMTransX] = tx;
+
+        fMat[kMSkewY]  = 0;
+        fMat[kMScaleY] = sy;
+        fMat[kMTransY] = ty;
+
+        fMat[kMPersp0] = 0;
+        fMat[kMPersp1] = 0;
+        fMat[kMPersp2] = 1;
+
+        unsigned mask = 0;
+        if (sx != 1 || sy != 1) {
+            mask |= kScale_Mask;
+        }
+        if (tx || ty) {
+            mask |= kTranslate_Mask;
+        }
+        this->setTypeMask(mask | kRectStaysRect_Mask);
+    }
+
+    /** Returns true if all elements of the matrix are finite. Returns false if any
+        element is infinity, or NaN.
+
+        @return  true if matrix has only finite elements
+    */
+    bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
+
+private:
+    /** Set if the matrix will map a rectangle to another rectangle. This
+        can be true if the matrix is scale-only, or rotates a multiple of
+        90 degrees.
+
+        This bit will be set on identity matrices
+    */
+    static constexpr int kRectStaysRect_Mask = 0x10;
+
+    /** Set if the perspective bit is valid even though the rest of
+        the matrix is Unknown.
+    */
+    static constexpr int kOnlyPerspectiveValid_Mask = 0x40;
+
+    static constexpr int kUnknown_Mask = 0x80;
+
+    static constexpr int kORableMasks = kTranslate_Mask |
+                                        kScale_Mask |
+                                        kAffine_Mask |
+                                        kPerspective_Mask;
+
+    static constexpr int kAllMasks = kTranslate_Mask |
+                                     kScale_Mask |
+                                     kAffine_Mask |
+                                     kPerspective_Mask |
+                                     kRectStaysRect_Mask;
+
+    SkScalar         fMat[9];
+    mutable uint32_t fTypeMask;
+
+    static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
+
+    uint8_t computeTypeMask() const;
+    uint8_t computePerspectiveTypeMask() const;
+
+    void setTypeMask(int mask) {
+        // allow kUnknown or a valid mask
+        SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
+                 ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
+                 == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
+        fTypeMask = SkToU8(mask);
+    }
+
+    void orTypeMask(int mask) {
+        SkASSERT((mask & kORableMasks) == mask);
+        fTypeMask = SkToU8(fTypeMask | mask);
+    }
+
+    void clearTypeMask(int mask) {
+        // only allow a valid mask
+        SkASSERT((mask & kAllMasks) == mask);
+        fTypeMask = fTypeMask & ~mask;
+    }
+
+    TypeMask getPerspectiveTypeMaskOnly() const {
+        if ((fTypeMask & kUnknown_Mask) &&
+            !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
+            fTypeMask = this->computePerspectiveTypeMask();
+        }
+        return (TypeMask)(fTypeMask & 0xF);
+    }
+
+    /** Returns true if we already know that the matrix is identity;
+        false otherwise.
+    */
+    bool isTriviallyIdentity() const {
+        if (fTypeMask & kUnknown_Mask) {
+            return false;
+        }
+        return ((fTypeMask & 0xF) == 0);
+    }
+
+    inline void updateTranslateMask() {
+        if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
+            fTypeMask |= kTranslate_Mask;
+        } else {
+            fTypeMask &= ~kTranslate_Mask;
+        }
+    }
+
+    typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
+                                 SkPoint* result);
+
+    static MapXYProc GetMapXYProc(TypeMask mask) {
+        SkASSERT((mask & ~kAllMasks) == 0);
+        return gMapXYProcs[mask & kAllMasks];
+    }
+
+    MapXYProc getMapXYProc() const {
+        return GetMapXYProc(this->getType());
+    }
+
+    typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
+                                  const SkPoint src[], int count);
+
+    static MapPtsProc GetMapPtsProc(TypeMask mask) {
+        SkASSERT((mask & ~kAllMasks) == 0);
+        return gMapPtsProcs[mask & kAllMasks];
+    }
+
+    MapPtsProc getMapPtsProc() const {
+        return GetMapPtsProc(this->getType());
+    }
+
+    bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
+
+    static bool Poly2Proc(const SkPoint[], SkMatrix*);
+    static bool Poly3Proc(const SkPoint[], SkMatrix*);
+    static bool Poly4Proc(const SkPoint[], SkMatrix*);
+
+    static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+    static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
+
+    static const MapXYProc gMapXYProcs[];
+
+    static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
+    static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
+    static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
+    static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
+                               int count);
+    static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
+
+    static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
+
+    static const MapPtsProc gMapPtsProcs[];
+
+    // return the number of bytes written, whether or not buffer is null
+    size_t writeToMemory(void* buffer) const;
+    /**
+     * Reads data from the buffer parameter
+     *
+     * @param buffer Memory to read from
+     * @param length Amount of memory available in the buffer
+     * @return number of bytes read (must be a multiple of 4) or
+     *         0 if there was not enough memory available
+     */
+    size_t readFromMemory(const void* buffer, size_t length);
+
+    friend class SkPerspIter;
+    friend class SkMatrixPriv;
+    friend class SkReader32;
+    friend class SerializationTest;
+};
+SK_END_REQUIRE_DENSE
+
+#endif

+ 495 - 0
skia/include/core/SkMatrix44.h

@@ -0,0 +1,495 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMatrix44_DEFINED
+#define SkMatrix44_DEFINED
+
+#include "SkMatrix.h"
+#include "SkScalar.h"
+
+#include <atomic>
+#include <cstring>
+
+#ifdef SK_MSCALAR_IS_DOUBLE
+#ifdef SK_MSCALAR_IS_FLOAT
+    #error "can't define MSCALAR both as DOUBLE and FLOAT"
+#endif
+    typedef double SkMScalar;
+
+    static inline double SkFloatToMScalar(float x) {
+        return static_cast<double>(x);
+    }
+    static inline float SkMScalarToFloat(double x) {
+        return static_cast<float>(x);
+    }
+    static inline double SkDoubleToMScalar(double x) {
+        return x;
+    }
+    static inline double SkMScalarToDouble(double x) {
+        return x;
+    }
+    static inline double SkMScalarAbs(double x) {
+        return fabs(x);
+    }
+    static const SkMScalar SK_MScalarPI = 3.141592653589793;
+
+    #define SkMScalarFloor(x)           sk_double_floor(x)
+    #define SkMScalarCeil(x)            sk_double_ceil(x)
+    #define SkMScalarRound(x)           sk_double_round(x)
+
+    #define SkMScalarFloorToInt(x)      sk_double_floor2int(x)
+    #define SkMScalarCeilToInt(x)       sk_double_ceil2int(x)
+    #define SkMScalarRoundToInt(x)      sk_double_round2int(x)
+
+
+#elif defined SK_MSCALAR_IS_FLOAT
+#ifdef SK_MSCALAR_IS_DOUBLE
+    #error "can't define MSCALAR both as DOUBLE and FLOAT"
+#endif
+    typedef float SkMScalar;
+
+    static inline float SkFloatToMScalar(float x) {
+        return x;
+    }
+    static inline float SkMScalarToFloat(float x) {
+        return x;
+    }
+    static inline float SkDoubleToMScalar(double x) {
+        return sk_double_to_float(x);
+    }
+    static inline double SkMScalarToDouble(float x) {
+        return static_cast<double>(x);
+    }
+    static inline float SkMScalarAbs(float x) {
+        return sk_float_abs(x);
+    }
+    static const SkMScalar SK_MScalarPI = 3.14159265f;
+
+    #define SkMScalarFloor(x)           sk_float_floor(x)
+    #define SkMScalarCeil(x)            sk_float_ceil(x)
+    #define SkMScalarRound(x)           sk_float_round(x)
+
+    #define SkMScalarFloorToInt(x)      sk_float_floor2int(x)
+    #define SkMScalarCeilToInt(x)       sk_float_ceil2int(x)
+    #define SkMScalarRoundToInt(x)      sk_float_round2int(x)
+
+#endif
+
+#define SkIntToMScalar(n)       static_cast<SkMScalar>(n)
+
+#define SkMScalarToScalar(x)    SkMScalarToFloat(x)
+#define SkScalarToMScalar(x)    SkFloatToMScalar(x)
+
+static const SkMScalar SK_MScalar1 = 1;
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct SkVector4 {
+    SkScalar fData[4];
+
+    SkVector4() {
+        this->set(0, 0, 0, 1);
+    }
+    SkVector4(const SkVector4& src) {
+        memcpy(fData, src.fData, sizeof(fData));
+    }
+    SkVector4(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+        fData[0] = x;
+        fData[1] = y;
+        fData[2] = z;
+        fData[3] = w;
+    }
+
+    SkVector4& operator=(const SkVector4& src) {
+        memcpy(fData, src.fData, sizeof(fData));
+        return *this;
+    }
+
+    bool operator==(const SkVector4& v) {
+        return fData[0] == v.fData[0] && fData[1] == v.fData[1] &&
+               fData[2] == v.fData[2] && fData[3] == v.fData[3];
+    }
+    bool operator!=(const SkVector4& v) {
+        return !(*this == v);
+    }
+    bool equals(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+        return fData[0] == x && fData[1] == y &&
+               fData[2] == z && fData[3] == w;
+    }
+
+    void set(SkScalar x, SkScalar y, SkScalar z, SkScalar w = SK_Scalar1) {
+        fData[0] = x;
+        fData[1] = y;
+        fData[2] = z;
+        fData[3] = w;
+    }
+};
+
+/** \class SkMatrix44
+
+    The SkMatrix44 class holds a 4x4 matrix.
+
+    SkMatrix44 is not thread safe unless you've first called SkMatrix44::getType().
+*/
+class SK_API SkMatrix44 {
+public:
+
+    enum Uninitialized_Constructor {
+        kUninitialized_Constructor
+    };
+    enum Identity_Constructor {
+        kIdentity_Constructor
+    };
+
+    SkMatrix44(Uninitialized_Constructor) {}  // ironically, cannot be constexpr
+
+    constexpr SkMatrix44(Identity_Constructor)
+        : fMat{{ 1, 0, 0, 0, },
+               { 0, 1, 0, 0, },
+               { 0, 0, 1, 0, },
+               { 0, 0, 0, 1, }}
+        , fTypeMask(kIdentity_Mask)
+    {}
+
+    constexpr SkMatrix44() : SkMatrix44{kIdentity_Constructor} {}
+
+    SkMatrix44(const SkMatrix44& src) {
+        memcpy(fMat, src.fMat, sizeof(fMat));
+        fTypeMask.store(src.fTypeMask, std::memory_order_relaxed);
+    }
+
+    SkMatrix44(const SkMatrix44& a, const SkMatrix44& b) {
+        this->setConcat(a, b);
+    }
+
+    SkMatrix44& operator=(const SkMatrix44& src) {
+        if (&src != this) {
+            memcpy(fMat, src.fMat, sizeof(fMat));
+            fTypeMask.store(src.fTypeMask, std::memory_order_relaxed);
+        }
+        return *this;
+    }
+
+    bool operator==(const SkMatrix44& other) const;
+    bool operator!=(const SkMatrix44& other) const {
+        return !(other == *this);
+    }
+
+    /* When converting from SkMatrix44 to SkMatrix, the third row and
+     * column is dropped.  When converting from SkMatrix to SkMatrix44
+     * the third row and column remain as identity:
+     * [ a b c ]      [ a b 0 c ]
+     * [ d e f ]  ->  [ d e 0 f ]
+     * [ g h i ]      [ 0 0 1 0 ]
+     *                [ g h 0 i ]
+     */
+    SkMatrix44(const SkMatrix&);
+    SkMatrix44& operator=(const SkMatrix& src);
+    operator SkMatrix() const;
+
+    /**
+     *  Return a reference to a const identity matrix
+     */
+    static const SkMatrix44& I();
+
+    enum TypeMask {
+        kIdentity_Mask      = 0,
+        kTranslate_Mask     = 0x01,  //!< set if the matrix has translation
+        kScale_Mask         = 0x02,  //!< set if the matrix has any scale != 1
+        kAffine_Mask        = 0x04,  //!< set if the matrix skews or rotates
+        kPerspective_Mask   = 0x08   //!< set if the matrix is in perspective
+    };
+
+    /**
+     *  Returns a bitfield describing the transformations the matrix may
+     *  perform. The bitfield is computed conservatively, so it may include
+     *  false positives. For example, when kPerspective_Mask is true, all
+     *  other bits may be set to true even in the case of a pure perspective
+     *  transform.
+     */
+    inline TypeMask getType() const {
+        if (fTypeMask.load(std::memory_order_relaxed) & kUnknown_Mask) {
+            fTypeMask.store(this->computeTypeMask(), std::memory_order_relaxed);
+        }
+        SkASSERT(!(fTypeMask & kUnknown_Mask));
+        return (TypeMask)fTypeMask.load(std::memory_order_relaxed);
+    }
+
+    /**
+     *  Return true if the matrix is identity.
+     */
+    inline bool isIdentity() const {
+        return kIdentity_Mask == this->getType();
+    }
+
+    /**
+     *  Return true if the matrix contains translate or is identity.
+     */
+    inline bool isTranslate() const {
+        return !(this->getType() & ~kTranslate_Mask);
+    }
+
+    /**
+     *  Return true if the matrix only contains scale or translate or is identity.
+     */
+    inline bool isScaleTranslate() const {
+        return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
+    }
+
+    /**
+     *  Returns true if the matrix only contains scale or is identity.
+     */
+    inline bool isScale() const {
+            return !(this->getType() & ~kScale_Mask);
+    }
+
+    inline bool hasPerspective() const {
+        return SkToBool(this->getType() & kPerspective_Mask);
+    }
+
+    void setIdentity();
+    inline void reset() { this->setIdentity();}
+
+    /**
+     *  get a value from the matrix. The row,col parameters work as follows:
+     *  (0, 0)  scale-x
+     *  (0, 3)  translate-x
+     *  (3, 0)  perspective-x
+     */
+    inline SkMScalar get(int row, int col) const {
+        SkASSERT((unsigned)row <= 3);
+        SkASSERT((unsigned)col <= 3);
+        return fMat[col][row];
+    }
+
+    /**
+     *  set a value in the matrix. The row,col parameters work as follows:
+     *  (0, 0)  scale-x
+     *  (0, 3)  translate-x
+     *  (3, 0)  perspective-x
+     */
+    inline void set(int row, int col, SkMScalar value) {
+        SkASSERT((unsigned)row <= 3);
+        SkASSERT((unsigned)col <= 3);
+        fMat[col][row] = value;
+        this->dirtyTypeMask();
+    }
+
+    inline double getDouble(int row, int col) const {
+        return SkMScalarToDouble(this->get(row, col));
+    }
+    inline void setDouble(int row, int col, double value) {
+        this->set(row, col, SkDoubleToMScalar(value));
+    }
+    inline float getFloat(int row, int col) const {
+        return SkMScalarToFloat(this->get(row, col));
+    }
+    inline void setFloat(int row, int col, float value) {
+        this->set(row, col, SkFloatToMScalar(value));
+    }
+
+    /** These methods allow one to efficiently read matrix entries into an
+     *  array. The given array must have room for exactly 16 entries. Whenever
+     *  possible, they will try to use memcpy rather than an entry-by-entry
+     *  copy.
+     *
+     *  Col major indicates that consecutive elements of columns will be stored
+     *  contiguously in memory.  Row major indicates that consecutive elements
+     *  of rows will be stored contiguously in memory.
+     */
+    void asColMajorf(float[]) const;
+    void asColMajord(double[]) const;
+    void asRowMajorf(float[]) const;
+    void asRowMajord(double[]) const;
+
+    /** These methods allow one to efficiently set all matrix entries from an
+     *  array. The given array must have room for exactly 16 entries. Whenever
+     *  possible, they will try to use memcpy rather than an entry-by-entry
+     *  copy.
+     *
+     *  Col major indicates that input memory will be treated as if consecutive
+     *  elements of columns are stored contiguously in memory.  Row major
+     *  indicates that input memory will be treated as if consecutive elements
+     *  of rows are stored contiguously in memory.
+     */
+    void setColMajorf(const float[]);
+    void setColMajord(const double[]);
+    void setRowMajorf(const float[]);
+    void setRowMajord(const double[]);
+
+#ifdef SK_MSCALAR_IS_FLOAT
+    void setColMajor(const SkMScalar data[]) { this->setColMajorf(data); }
+    void setRowMajor(const SkMScalar data[]) { this->setRowMajorf(data); }
+#else
+    void setColMajor(const SkMScalar data[]) { this->setColMajord(data); }
+    void setRowMajor(const SkMScalar data[]) { this->setRowMajord(data); }
+#endif
+
+    /* This sets the top-left of the matrix and clears the translation and
+     * perspective components (with [3][3] set to 1).  m_ij is interpreted
+     * as the matrix entry at row = i, col = j. */
+    void set3x3(SkMScalar m_00, SkMScalar m_10, SkMScalar m_20,
+                SkMScalar m_01, SkMScalar m_11, SkMScalar m_21,
+                SkMScalar m_02, SkMScalar m_12, SkMScalar m_22);
+    void set3x3RowMajorf(const float[]);
+
+    void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+    void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+    void postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz);
+
+    void setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+    void preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+    void postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz);
+
+    inline void setScale(SkMScalar scale) {
+        this->setScale(scale, scale, scale);
+    }
+    inline void preScale(SkMScalar scale) {
+        this->preScale(scale, scale, scale);
+    }
+    inline void postScale(SkMScalar scale) {
+        this->postScale(scale, scale, scale);
+    }
+
+    void setRotateDegreesAbout(SkMScalar x, SkMScalar y, SkMScalar z,
+                               SkMScalar degrees) {
+        this->setRotateAbout(x, y, z, degrees * SK_MScalarPI / 180);
+    }
+
+    /** Rotate about the vector [x,y,z]. If that vector is not unit-length,
+        it will be automatically resized.
+     */
+    void setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
+                        SkMScalar radians);
+    /** Rotate about the vector [x,y,z]. Does not check the length of the
+        vector, assuming it is unit-length.
+     */
+    void setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
+                            SkMScalar radians);
+
+    void setConcat(const SkMatrix44& a, const SkMatrix44& b);
+    inline void preConcat(const SkMatrix44& m) {
+        this->setConcat(*this, m);
+    }
+    inline void postConcat(const SkMatrix44& m) {
+        this->setConcat(m, *this);
+    }
+
+    friend SkMatrix44 operator*(const SkMatrix44& a, const SkMatrix44& b) {
+        return SkMatrix44(a, b);
+    }
+
+    /** If this is invertible, return that in inverse and return true. If it is
+        not invertible, return false and leave the inverse parameter in an
+        unspecified state.
+     */
+    bool invert(SkMatrix44* inverse) const;
+
+    /** Transpose this matrix in place. */
+    void transpose();
+
+    /** Apply the matrix to the src vector, returning the new vector in dst.
+        It is legal for src and dst to point to the same memory.
+     */
+    void mapScalars(const SkScalar src[4], SkScalar dst[4]) const;
+    inline void mapScalars(SkScalar vec[4]) const {
+        this->mapScalars(vec, vec);
+    }
+
+#ifdef SK_MSCALAR_IS_DOUBLE
+    void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const;
+#elif defined SK_MSCALAR_IS_FLOAT
+    inline void mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
+        this->mapScalars(src, dst);
+    }
+#endif
+    inline void mapMScalars(SkMScalar vec[4]) const {
+        this->mapMScalars(vec, vec);
+    }
+
+    friend SkVector4 operator*(const SkMatrix44& m, const SkVector4& src) {
+        SkVector4 dst;
+        m.mapScalars(src.fData, dst.fData);
+        return dst;
+    }
+
+    /**
+     *  map an array of [x, y, 0, 1] through the matrix, returning an array
+     *  of [x', y', z', w'].
+     *
+     *  @param src2     array of [x, y] pairs, with implied z=0 and w=1
+     *  @param count    number of [x, y] pairs in src2
+     *  @param dst4     array of [x', y', z', w'] quads as the output.
+     */
+    void map2(const float src2[], int count, float dst4[]) const;
+    void map2(const double src2[], int count, double dst4[]) const;
+
+    /** Returns true if transformating an axis-aligned square in 2d by this matrix
+        will produce another 2d axis-aligned square; typically means the matrix
+        is a scale with perhaps a 90-degree rotation. A 3d rotation through 90
+        degrees into a perpendicular plane collapses a square to a line, but
+        is still considered to be axis-aligned.
+
+        By default, tolerates very slight error due to float imprecisions;
+        a 90-degree rotation can still end up with 10^-17 of
+        "non-axis-aligned" result.
+     */
+    bool preserves2dAxisAlignment(SkMScalar epsilon = SK_ScalarNearlyZero) const;
+
+    void dump() const;
+
+    double determinant() const;
+
+private:
+    /* This is indexed by [col][row]. */
+    SkMScalar                       fMat[4][4];
+    mutable std::atomic<unsigned>   fTypeMask;
+
+    static constexpr int kUnknown_Mask = 0x80;
+
+    static constexpr int kAllPublic_Masks = 0xF;
+
+    void as3x4RowMajorf(float[]) const;
+    void set3x4RowMajorf(const float[]);
+
+    SkMScalar transX() const { return fMat[3][0]; }
+    SkMScalar transY() const { return fMat[3][1]; }
+    SkMScalar transZ() const { return fMat[3][2]; }
+
+    SkMScalar scaleX() const { return fMat[0][0]; }
+    SkMScalar scaleY() const { return fMat[1][1]; }
+    SkMScalar scaleZ() const { return fMat[2][2]; }
+
+    SkMScalar perspX() const { return fMat[0][3]; }
+    SkMScalar perspY() const { return fMat[1][3]; }
+    SkMScalar perspZ() const { return fMat[2][3]; }
+
+    int computeTypeMask() const;
+
+    inline void dirtyTypeMask() {
+        fTypeMask.store(kUnknown_Mask, std::memory_order_relaxed);
+    }
+
+    inline void setTypeMask(int mask) {
+        SkASSERT(0 == (~(kAllPublic_Masks | kUnknown_Mask) & mask));
+        fTypeMask.store(mask, std::memory_order_relaxed);
+    }
+
+    /**
+     *  Does not take the time to 'compute' the typemask. Only returns true if
+     *  we already know that this matrix is identity.
+     */
+    inline bool isTriviallyIdentity() const {
+        return 0 == fTypeMask.load(std::memory_order_relaxed);
+    }
+
+    inline const SkMScalar* values() const { return &fMat[0][0]; }
+
+    friend class SkColorSpace;
+};
+
+#endif

+ 175 - 0
skia/include/core/SkMetaData.h

@@ -0,0 +1,175 @@
+
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SkMetaData_DEFINED
+#define SkMetaData_DEFINED
+
+#include "SkScalar.h"
+
+class SkRefCnt;
+
+class SK_API SkMetaData {
+public:
+    /**
+     *  Used to manage the life-cycle of a ptr in the metadata. This is option
+     *  in setPtr, and is only invoked when either copying one metadata to
+     *  another, or when the metadata is destroyed.
+     *
+     *  setPtr(name, ptr, proc) {
+     *      fPtr = proc(ptr, true);
+     *  }
+     *
+     *  copy: A = B {
+     *      A.fPtr = B.fProc(B.fPtr, true);
+     *  }
+     *
+     *  ~SkMetaData {
+     *      fProc(fPtr, false);
+     *  }
+     */
+    typedef void* (*PtrProc)(void* ptr, bool doRef);
+
+    /**
+     *  Implements PtrProc for SkRefCnt pointers
+     */
+    static void* RefCntProc(void* ptr, bool doRef);
+
+    SkMetaData();
+    SkMetaData(const SkMetaData& src);
+    ~SkMetaData();
+
+    SkMetaData& operator=(const SkMetaData& src);
+
+    void reset();
+
+    bool findS32(const char name[], int32_t* value = nullptr) const;
+    bool findScalar(const char name[], SkScalar* value = nullptr) const;
+    const SkScalar* findScalars(const char name[], int* count,
+                                SkScalar values[] = nullptr) const;
+    const char* findString(const char name[]) const;
+    bool findPtr(const char name[], void** value = nullptr, PtrProc* = nullptr) const;
+    bool findBool(const char name[], bool* value = nullptr) const;
+    const void* findData(const char name[], size_t* byteCount = nullptr) const;
+
+    bool hasS32(const char name[], int32_t value) const {
+        int32_t v;
+        return this->findS32(name, &v) && v == value;
+    }
+    bool hasScalar(const char name[], SkScalar value) const {
+        SkScalar v;
+        return this->findScalar(name, &v) && v == value;
+    }
+    bool hasString(const char name[], const char value[]) const {
+        const char* v = this->findString(name);
+        return  (v == nullptr && value == nullptr) ||
+                (v != nullptr && value != nullptr && !strcmp(v, value));
+    }
+    bool hasPtr(const char name[], void* value) const {
+        void* v;
+        return this->findPtr(name, &v) && v == value;
+    }
+    bool hasBool(const char name[], bool value) const {
+        bool    v;
+        return this->findBool(name, &v) && v == value;
+    }
+    bool hasData(const char name[], const void* data, size_t byteCount) const {
+        size_t len;
+        const void* ptr = this->findData(name, &len);
+        return ptr && len == byteCount && !memcmp(ptr, data, len);
+    }
+
+    void setS32(const char name[], int32_t value);
+    void setScalar(const char name[], SkScalar value);
+    SkScalar* setScalars(const char name[], int count, const SkScalar values[] = nullptr);
+    void setString(const char name[], const char value[]);
+    void setPtr(const char name[], void* value, PtrProc proc = nullptr);
+    void setBool(const char name[], bool value);
+    // the data is copied from the input pointer.
+    void setData(const char name[], const void* data, size_t byteCount);
+
+    bool removeS32(const char name[]);
+    bool removeScalar(const char name[]);
+    bool removeString(const char name[]);
+    bool removePtr(const char name[]);
+    bool removeBool(const char name[]);
+    bool removeData(const char name[]);
+
+    // helpers for SkRefCnt
+    bool findRefCnt(const char name[], SkRefCnt** ptr = nullptr) {
+        return this->findPtr(name, reinterpret_cast<void**>(ptr));
+    }
+    bool hasRefCnt(const char name[], SkRefCnt* ptr) {
+        return this->hasPtr(name, ptr);
+    }
+    void setRefCnt(const char name[], SkRefCnt* ptr) {
+        this->setPtr(name, ptr, RefCntProc);
+    }
+    bool removeRefCnt(const char name[]) {
+        return this->removePtr(name);
+    }
+
+    enum Type {
+        kS32_Type,
+        kScalar_Type,
+        kString_Type,
+        kPtr_Type,
+        kBool_Type,
+        kData_Type,
+
+        kTypeCount
+    };
+
+    struct Rec;
+    class Iter;
+    friend class Iter;
+
+    class Iter {
+    public:
+        Iter() : fRec(nullptr) {}
+        Iter(const SkMetaData&);
+
+        /** Reset the iterator, so that calling next() will return the first
+            data element. This is done implicitly in the constructor.
+        */
+        void reset(const SkMetaData&);
+
+        /** Each time next is called, it returns the name of the next data element,
+            or null when there are no more elements. If non-null is returned, then the
+            element's type is returned (if not null), and the number of data values
+            is returned in count (if not null).
+        */
+        const char* next(Type*, int* count);
+
+    private:
+        Rec* fRec;
+    };
+
+public:
+    struct Rec {
+        Rec*        fNext;
+        uint16_t    fDataCount; // number of elements
+        uint8_t     fDataLen;   // sizeof a single element
+        uint8_t     fType;
+
+        const void* data() const { return (this + 1); }
+        void*       data() { return (this + 1); }
+        const char* name() const { return (const char*)this->data() + fDataLen * fDataCount; }
+        char*       name() { return (char*)this->data() + fDataLen * fDataCount; }
+
+        static Rec* Alloc(size_t);
+        static void Free(Rec*);
+    };
+    Rec*    fRec;
+
+    const Rec* find(const char name[], Type) const;
+    void* set(const char name[], const void* data, size_t len, Type, int count);
+    bool remove(const char name[], Type);
+};
+
+#endif

+ 9 - 0
skia/include/core/SkMilestone.h

@@ -0,0 +1,9 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SK_MILESTONE
+#define SK_MILESTONE 72
+#endif

+ 75 - 0
skia/include/core/SkMultiPictureDraw.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkMultiPictureDraw_DEFINED
+#define SkMultiPictureDraw_DEFINED
+
+#include "../private/SkTDArray.h"
+#include "SkMatrix.h"
+
+class SkCanvas;
+class SkPaint;
+class SkPicture;
+
+/** \class SkMultiPictureDraw
+
+    The MultiPictureDraw object accepts several picture/canvas pairs and
+    then attempts to optimally draw the pictures into the canvases, sharing
+    as many resources as possible.
+*/
+class SK_API SkMultiPictureDraw {
+public:
+    /**
+     *  Create an object to optimize the drawing of multiple pictures.
+     *  @param reserve Hint for the number of add calls expected to be issued
+     */
+    SkMultiPictureDraw(int reserve = 0);
+    ~SkMultiPictureDraw() { this->reset(); }
+
+    /**
+     *  Add a canvas/picture pair for later rendering.
+     *  @param canvas   the canvas in which to draw picture
+     *  @param picture  the picture to draw into canvas
+     *  @param matrix   if non-NULL, applied to the CTM when drawing
+     *  @param paint    if non-NULL, draw picture to a temporary buffer
+     *                  and then apply the paint when the result is drawn
+     */
+    void add(SkCanvas* canvas,
+             const SkPicture* picture,
+             const SkMatrix* matrix = nullptr,
+             const SkPaint* paint = nullptr);
+
+    /**
+     *  Perform all the previously added draws. This will reset the state
+     *  of this object. If flush is true, all canvases are flushed after
+     *  draw.
+     */
+    void draw(bool flush = false);
+
+    /**
+     *  Abandon all buffered draws and reset to the initial state.
+     */
+    void reset();
+
+private:
+    struct DrawData {
+        SkCanvas*        fCanvas;
+        const SkPicture* fPicture; // reffed
+        SkMatrix         fMatrix;
+        SkPaint*         fPaint;   // owned
+
+        void init(SkCanvas*, const SkPicture*, const SkMatrix*, const SkPaint*);
+        void draw();
+
+        static void Reset(SkTDArray<DrawData>&);
+    };
+
+    SkTDArray<DrawData> fThreadSafeDrawData;
+    SkTDArray<DrawData> fGPUDrawData;
+};
+
+#endif

+ 74 - 0
skia/include/core/SkOverdrawCanvas.h

@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkOverdrawCanvas_DEFINED
+#define SkOverdrawCanvas_DEFINED
+
+#include "SkCanvasVirtualEnforcer.h"
+#include "SkNWayCanvas.h"
+
+/**
+ *  Captures all drawing commands.  Rather than draw the actual content, this device
+ *  increments the alpha channel of each pixel every time it would have been touched
+ *  by a draw call.  This is useful for detecting overdraw.
+ */
+class SK_API SkOverdrawCanvas : public SkCanvasVirtualEnforcer<SkNWayCanvas> {
+public:
+    /* Does not take ownership of canvas */
+    SkOverdrawCanvas(SkCanvas*);
+
+    void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override;
+    void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override;
+    void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override;
+    void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
+                           const SkPaint&) override;
+    void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override;
+    void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode,
+                     const SkPaint&) override;
+    void onDrawPaint(const SkPaint&) override;
+    void onDrawRect(const SkRect&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
+    void onDrawOval(const SkRect&, const SkPaint&) override;
+    void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override;
+    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+    void onDrawRRect(const SkRRect&, const SkPaint&) override;
+    void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint&) override;
+    void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount,
+                              SkBlendMode, const SkPaint&) override;
+    void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
+                     int, SkBlendMode, const SkRect*, const SkPaint*) override;
+    void onDrawPath(const SkPath&, const SkPaint&) override;
+    void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override;
+    void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
+                         SrcRectConstraint) override;
+    void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override;
+    void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override;
+    void onDrawImageSet(const ImageSetEntry[], int count, SkFilterQuality, SkBlendMode) override;
+    void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override;
+    void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
+                          SrcRectConstraint) override;
+    void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override;
+    void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&,
+                             const SkPaint*) override;
+    void onDrawDrawable(SkDrawable*, const SkMatrix*) override;
+    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+
+    void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override;
+    void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
+
+private:
+    void drawPosTextCommon(const void*, size_t, const SkScalar[], int, const SkPoint&,
+                           const SkPaint&);
+
+    inline SkPaint overdrawPaint(const SkPaint& paint);
+
+    SkPaint   fPaint;
+
+    typedef SkCanvasVirtualEnforcer<SkNWayCanvas> INHERITED;
+};
+
+#endif

+ 1427 - 0
skia/include/core/SkPaint.h

@@ -0,0 +1,1427 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkPaint.h and docs/SkPaint_Reference.bmh
+   on 2018-08-28 10:32:58. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkPaint_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkPaint_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkPaint.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkPaint_DEFINED
+#define SkPaint_DEFINED
+
+#include "../private/SkTo.h"
+#include "SkBlendMode.h"
+#include "SkColor.h"
+#include "SkFilterQuality.h"
+#include "SkFontMetrics.h"
+#include "SkFontTypes.h"
+#include "SkMatrix.h"
+#include "SkRefCnt.h"
+
+#define SK_SUPPORT_LEGACY_FONTMETRICS_IN_PAINT
+
+class GrTextBlob;
+class SkAutoDescriptor;
+class SkColorFilter;
+class SkColorSpace;
+class SkData;
+class SkDescriptor;
+class SkDrawLooper;
+class SkGlyph;
+class SkGlyphRunBuilder;
+class SkGlyphRun;
+class SkGlyphRunListPainter;
+struct SkRect;
+class SkGlyphCache;
+class SkImageFilter;
+class SkMaskFilter;
+class SkPath;
+class SkPathEffect;
+struct SkPoint;
+class SkRunFont;
+class SkShader;
+class SkSurfaceProps;
+class SkTextBlob;
+class SkTextBlobRunIterator;
+class SkTypeface;
+
+#ifndef SK_SUPPORT_LEGACY_PAINT_TEXTMEASURE
+#define SK_SUPPORT_LEGACY_PAINT_TEXTMEASURE
+#endif
+
+/** \class SkPaint
+    SkPaint controls options applied when drawing and measuring. SkPaint collects all
+    options outside of the SkCanvas clip and SkCanvas matrix.
+
+    Various options apply to text, strokes and fills, and images.
+
+    Some options may not be implemented on all platforms; in these cases, setting
+    the option has no effect. Some options are conveniences that duplicate SkCanvas
+    functionality; for instance, text size is identical to matrix scale.
+
+    SkPaint options are rarely exclusive; each option modifies a stage of the drawing
+    pipeline and multiple pipeline stages may be affected by a single SkPaint.
+
+    SkPaint collects effects and filters that describe single-pass and multiple-pass
+    algorithms that alter the drawing geometry, color, and transparency. For instance,
+    SkPaint does not directly implement dashing or blur, but contains the objects that do so.
+
+    The objects contained by SkPaint are opaque, and cannot be edited outside of the SkPaint
+    to affect it. The implementation is free to defer computations associated with the
+    SkPaint, or ignore them altogether. For instance, some GPU implementations draw all
+    SkPath geometries with anti-aliasing, regardless of how SkPaint::kAntiAlias_Flag
+    is set in SkPaint.
+
+    SkPaint describes a single color, a single font, a single image quality, and so on.
+    Multiple colors are drawn either by using multiple paints or with objects like
+    SkShader attached to SkPaint.
+*/
+class SK_API SkPaint {
+public:
+
+    /** Constructs SkPaint with default values.
+
+        @return  default initialized SkPaint
+    */
+    SkPaint();
+
+    /** Makes a shallow copy of SkPaint. SkTypeface, SkPathEffect, SkShader,
+        SkMaskFilter, SkColorFilter, SkDrawLooper, and SkImageFilter are shared
+        between the original paint and the copy. Objects containing SkRefCnt increment
+        their references by one.
+
+        The referenced objects SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
+        SkDrawLooper, and SkImageFilter cannot be modified after they are created.
+        This prevents objects with SkRefCnt from being modified once SkPaint refers to them.
+
+        @param paint  original to copy
+        @return       shallow copy of paint
+    */
+    SkPaint(const SkPaint& paint);
+
+    /** Implements a move constructor to avoid increasing the reference counts
+        of objects referenced by the paint.
+
+        After the call, paint is undefined, and can be safely destructed.
+
+        @param paint  original to move
+        @return       content of paint
+    */
+    SkPaint(SkPaint&& paint);
+
+    /** Decreases SkPaint SkRefCnt of owned objects: SkTypeface, SkPathEffect, SkShader,
+        SkMaskFilter, SkColorFilter, SkDrawLooper, and SkImageFilter. If the
+        objects containing SkRefCnt go to zero, they are deleted.
+    */
+    ~SkPaint();
+
+    /** Makes a shallow copy of SkPaint. SkTypeface, SkPathEffect, SkShader,
+        SkMaskFilter, SkColorFilter, SkDrawLooper, and SkImageFilter are shared
+        between the original paint and the copy. Objects containing SkRefCnt in the
+        prior destination are decreased by one, and the referenced objects are deleted if the
+        resulting count is zero. Objects containing SkRefCnt in the parameter paint
+        are increased by one. paint is unmodified.
+
+        @param paint  original to copy
+        @return       content of paint
+    */
+    SkPaint& operator=(const SkPaint& paint);
+
+    /** Moves the paint to avoid increasing the reference counts
+        of objects referenced by the paint parameter. Objects containing SkRefCnt in the
+        prior destination are decreased by one; those objects are deleted if the resulting count
+        is zero.
+
+        After the call, paint is undefined, and can be safely destructed.
+
+        @param paint  original to move
+        @return       content of paint
+    */
+    SkPaint& operator=(SkPaint&& paint);
+
+    /** Compares a and b, and returns true if a and b are equivalent. May return false
+        if SkTypeface, SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
+        SkDrawLooper, or SkImageFilter have identical contents but different pointers.
+
+        @param a  SkPaint to compare
+        @param b  SkPaint to compare
+        @return   true if SkPaint pair are equivalent
+    */
+    SK_API friend bool operator==(const SkPaint& a, const SkPaint& b);
+
+    /** Compares a and b, and returns true if a and b are not equivalent. May return true
+        if SkTypeface, SkPathEffect, SkShader, SkMaskFilter, SkColorFilter,
+        SkDrawLooper, or SkImageFilter have identical contents but different pointers.
+
+        @param a  SkPaint to compare
+        @param b  SkPaint to compare
+        @return   true if SkPaint pair are not equivalent
+    */
+    friend bool operator!=(const SkPaint& a, const SkPaint& b) {
+        return !(a == b);
+    }
+
+    /** Returns a hash generated from SkPaint values and pointers.
+        Identical hashes guarantee that the paints are
+        equivalent, but differing hashes do not guarantee that the paints have differing
+        contents.
+
+        If operator==(const SkPaint& a, const SkPaint& b) returns true for two paints,
+        their hashes are also equal.
+
+        The hash returned is platform and implementation specific.
+
+        @return  a shallow hash
+    */
+    uint32_t getHash() const;
+
+    /** Sets all SkPaint contents to their initial values. This is equivalent to replacing
+        SkPaint with the result of SkPaint().
+    */
+    void reset();
+
+#ifdef SK_SUPPORT_LEGACY_NESTED_HINTINGENUM
+    /** \enum SkPaint::Hinting
+        Deprecated.
+        Hinting adjusts the glyph outlines so that the shape provides a uniform
+        look at a given point size on font engines that support it. Hinting may have a
+        muted effect or no effect at all depending on the platform.
+
+        The four levels roughly control corresponding features on platforms that use FreeType
+        as the font engine.
+    */
+    enum Hinting : uint8_t {
+        kNo_Hinting     = 0, //!< glyph outlines unchanged
+        kSlight_Hinting = 1, //!< minimal modification to improve constrast
+        kNormal_Hinting = 2, //!< glyph outlines modified to improve constrast
+        kFull_Hinting   = 3, //!< modifies glyph outlines for maximum constrast
+    };
+#endif
+
+    /** Sets level of glyph outline adjustment.
+        Does not check for valid values of hintingLevel.
+
+        @param hintingLevel  one of: SkFontHinting::kNone, SkFontHinting::kSlight,
+                                     SkFontHinting::kNormal, SkFontHinting::kFull
+    */
+    void setHinting(SkFontHinting hintingLevel);
+
+    /** Returns level of glyph outline adjustment.
+
+        @return  one of: SkFontHinting::kNone, SkFontHinting::kSlight, SkFontHinting::kNormal,
+                         SkFontHinting::kFull
+     */
+    SkFontHinting getHinting() const { return (SkFontHinting)fBitfields.fHinting; }
+
+    /** \enum SkPaint::Flags
+        The bit values stored in Flags.
+        The default value for Flags, normally zero, can be changed at compile time
+        with a custom definition of SkPaintDefaults_Flags.
+        All flags can be read and written explicitly; Flags allows manipulating
+        multiple settings at once.
+    */
+    enum Flags {
+        kAntiAlias_Flag          = 0x01,   //!< mask for setting anti-alias
+        kDither_Flag             = 0x04,   //!< mask for setting dither
+        kFakeBoldText_Flag       = 0x20,   //!< mask for setting fake bold
+        kLinearText_Flag         = 0x40,   //!< mask for setting linear text
+        kSubpixelText_Flag       = 0x80,   //!< mask for setting subpixel text
+        kLCDRenderText_Flag      = 0x200,  //!< mask for setting LCD text
+        kEmbeddedBitmapText_Flag = 0x400,  //!< mask for setting font embedded bitmaps
+        kAutoHinting_Flag        = 0x800,  //!< mask for setting auto-hinting
+                                           // 0x1000 used to be kVertical
+        kAllFlags                = 0xFFFF, //!< mask of all Flags
+    };
+
+    #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    /** Private.
+     */
+    enum ReserveFlags {
+        kUnderlineText_ReserveFlag  = 0x08, //!< to be deprecated soon
+        kStrikeThruText_ReserveFlag = 0x10, //!< to be deprecated soon
+    };
+    #endif
+
+    /** Returns paint settings described by SkPaint::Flags. Each setting uses one
+        bit, and can be tested with SkPaint::Flags members.
+
+        @return  zero, one, or more bits described by SkPaint::Flags
+    */
+    uint32_t getFlags() const { return fBitfields.fFlags; }
+
+    /** Replaces SkPaint::Flags with flags, the union of the SkPaint::Flags members.
+        All SkPaint::Flags members may be cleared, or one or more may be set.
+
+        @param flags  union of SkPaint::Flags for SkPaint
+    */
+    void setFlags(uint32_t flags);
+
+    /** Returns true if pixels on the active edges of SkPath may be drawn with partial transparency.
+
+        Equivalent to getFlags() masked with kAntiAlias_Flag.
+
+        @return  kAntiAlias_Flag state
+    */
+    bool isAntiAlias() const {
+        return SkToBool(this->getFlags() & kAntiAlias_Flag);
+    }
+
+    /** Requests, but does not require, that edge pixels draw opaque or with
+        partial transparency.
+
+        Sets kAntiAlias_Flag if aa is true.
+        Clears kAntiAlias_Flag if aa is false.
+
+        @param aa  setting for kAntiAlias_Flag
+    */
+    void setAntiAlias(bool aa);
+
+    /** Returns true if color error may be distributed to smooth color transition.
+
+        Equivalent to getFlags() masked with kDither_Flag.
+
+        @return  kDither_Flag state
+    */
+    bool isDither() const {
+        return SkToBool(this->getFlags() & kDither_Flag);
+    }
+
+    /** Requests, but does not require, to distribute color error.
+
+        Sets kDither_Flag if dither is true.
+        Clears kDither_Flag if dither is false.
+
+        @param dither  setting for kDither_Flag
+    */
+    void setDither(bool dither);
+
+    /** Returns true if text is converted to SkPath before drawing and measuring.
+
+        Equivalent to getFlags() masked with kLinearText_Flag.
+
+        @return  kLinearText_Flag state
+    */
+    bool isLinearText() const {
+        return SkToBool(this->getFlags() & kLinearText_Flag);
+    }
+
+    /** Requests, but does not require, that glyphs are converted to SkPath
+        before drawing and measuring.
+        By default, kLinearText_Flag is clear.
+
+        Sets kLinearText_Flag if linearText is true.
+        Clears kLinearText_Flag if linearText is false.
+
+        @param linearText  setting for kLinearText_Flag
+    */
+    void setLinearText(bool linearText);
+
+    /** Returns true if glyphs at different sub-pixel positions may differ on pixel edge coverage.
+
+        Equivalent to getFlags() masked with kSubpixelText_Flag.
+
+        @return  kSubpixelText_Flag state
+    */
+    bool isSubpixelText() const {
+        return SkToBool(this->getFlags() & kSubpixelText_Flag);
+    }
+
+    /** Requests, but does not require, that glyphs respect sub-pixel positioning.
+
+        Sets kSubpixelText_Flag if subpixelText is true.
+        Clears kSubpixelText_Flag if subpixelText is false.
+
+        @param subpixelText  setting for kSubpixelText_Flag
+    */
+    void setSubpixelText(bool subpixelText);
+
+    /** Returns true if glyphs may use LCD striping to improve glyph edges.
+
+        Returns true if SkPaint::Flags kLCDRenderText_Flag is set.
+
+        @return  kLCDRenderText_Flag state
+    */
+    bool isLCDRenderText() const {
+        return SkToBool(this->getFlags() & kLCDRenderText_Flag);
+    }
+
+    /** Requests, but does not require, that glyphs use LCD striping for glyph edges.
+
+        Sets kLCDRenderText_Flag if lcdText is true.
+        Clears kLCDRenderText_Flag if lcdText is false.
+
+        @param lcdText  setting for kLCDRenderText_Flag
+    */
+    void setLCDRenderText(bool lcdText);
+
+    /** Returns true if font engine may return glyphs from font bitmaps instead of from outlines.
+
+        Equivalent to getFlags() masked with kEmbeddedBitmapText_Flag.
+
+        @return  kEmbeddedBitmapText_Flag state
+    */
+    bool isEmbeddedBitmapText() const {
+        return SkToBool(this->getFlags() & kEmbeddedBitmapText_Flag);
+    }
+
+    /** Requests, but does not require, to use bitmaps in fonts instead of outlines.
+
+        Sets kEmbeddedBitmapText_Flag if useEmbeddedBitmapText is true.
+        Clears kEmbeddedBitmapText_Flag if useEmbeddedBitmapText is false.
+
+        @param useEmbeddedBitmapText  setting for kEmbeddedBitmapText_Flag
+    */
+    void setEmbeddedBitmapText(bool useEmbeddedBitmapText);
+
+    /** Returns true if SkPaint::Hinting is set to SkFontHinting::kNormal or
+        SkFontHinting::kFull, and if platform uses FreeType as the font manager.
+        If true, instructs the font manager to always hint glyphs.
+
+        Equivalent to getFlags() masked with kAutoHinting_Flag.
+
+        @return  kAutoHinting_Flag state
+    */
+    bool isAutohinted() const {
+        return SkToBool(this->getFlags() & kAutoHinting_Flag);
+    }
+
+    /** Sets whether to always hint glyphs.
+        If SkPaint::Hinting is set to SkFontHinting::kNormal or SkFontHinting::kFull
+        and useAutohinter is set, instructs the font manager to always hint glyphs.
+        auto-hinting has no effect if SkPaint::Hinting is set to SkFontHinting::kNone or
+        SkFontHinting::kSlight.
+
+        Only affects platforms that use FreeType as the font manager.
+
+        Sets kAutoHinting_Flag if useAutohinter is true.
+        Clears kAutoHinting_Flag if useAutohinter is false.
+
+        @param useAutohinter  setting for kAutoHinting_Flag
+    */
+    void setAutohinted(bool useAutohinter);
+
+    /** Returns true if approximate bold by increasing the stroke width when creating glyph bitmaps
+        from outlines.
+
+        Equivalent to getFlags() masked with kFakeBoldText_Flag.
+
+        @return  kFakeBoldText_Flag state
+    */
+    bool isFakeBoldText() const {
+        return SkToBool(this->getFlags() & kFakeBoldText_Flag);
+    }
+
+    /** Increases stroke width when creating glyph bitmaps to approximate a bold typeface.
+
+        Sets kFakeBoldText_Flag if fakeBoldText is true.
+        Clears kFakeBoldText_Flag if fakeBoldText is false.
+
+        @param fakeBoldText  setting for kFakeBoldText_Flag
+    */
+    void setFakeBoldText(bool fakeBoldText);
+
+    /** Returns SkFilterQuality, the image filtering level. A lower setting
+        draws faster; a higher setting looks better when the image is scaled.
+
+        @return  one of: kNone_SkFilterQuality, kLow_SkFilterQuality,
+                 kMedium_SkFilterQuality, kHigh_SkFilterQuality
+    */
+    SkFilterQuality getFilterQuality() const {
+        return (SkFilterQuality)fBitfields.fFilterQuality;
+    }
+
+    /** Sets SkFilterQuality, the image filtering level. A lower setting
+        draws faster; a higher setting looks better when the image is scaled.
+        Does not check to see if quality is valid.
+
+        @param quality  one of: kNone_SkFilterQuality, kLow_SkFilterQuality,
+                        kMedium_SkFilterQuality, kHigh_SkFilterQuality
+    */
+    void setFilterQuality(SkFilterQuality quality);
+
+    /** \enum SkPaint::Style
+        Set Style to fill, stroke, or both fill and stroke geometry.
+        The stroke and fill
+        share all paint attributes; for instance, they are drawn with the same color.
+
+        Use kStrokeAndFill_Style to avoid hitting the same pixels twice with a stroke draw and
+        a fill draw.
+    */
+    enum Style : uint8_t {
+        kFill_Style,          //!< set to fill geometry
+        kStroke_Style,        //!< set to stroke geometry
+        kStrokeAndFill_Style, //!< sets to stroke and fill geometry
+    };
+
+    /** May be used to verify that SkPaint::Style is a legal value.
+    */
+    static constexpr int kStyleCount = kStrokeAndFill_Style + 1;
+
+    /** Returns whether the geometry is filled, stroked, or filled and stroked.
+
+        @return  one of:kFill_Style, kStroke_Style, kStrokeAndFill_Style
+    */
+    Style getStyle() const { return (Style)fBitfields.fStyle; }
+
+    /** Sets whether the geometry is filled, stroked, or filled and stroked.
+        Has no effect if style is not a legal SkPaint::Style value.
+
+        @param style  one of: kFill_Style, kStroke_Style, kStrokeAndFill_Style
+    */
+    void setStyle(Style style);
+
+    /** Retrieves alpha and RGB, unpremultiplied, packed into 32 bits.
+        Use helpers SkColorGetA(), SkColorGetR(), SkColorGetG(), and SkColorGetB() to extract
+        a color component.
+
+        @return  unpremultiplied ARGB
+    */
+    SkColor getColor() const { return fColor4f.toSkColor(); }
+
+    /** Retrieves alpha and RGB, unpremultiplied, as four floating point values. RGB are
+        are extended sRGB values (sRGB gamut, and encoded with the sRGB transfer function).
+
+        @return  unpremultiplied RGBA
+    */
+    SkColor4f getColor4f() const { return fColor4f; }
+
+    /** Sets alpha and RGB used when stroking and filling. The color is a 32-bit value,
+        unpremultiplied, packing 8-bit components for alpha, red, blue, and green.
+
+        @param color  unpremultiplied ARGB
+    */
+    void setColor(SkColor color);
+
+    /** Sets alpha and RGB used when stroking and filling. The color is four floating
+        point values, unpremultiplied. The color values are interpreted as being in
+        the colorSpace. If colorSpace is nullptr, then color is assumed to be in the
+        sRGB color space.
+
+        @param color       unpremultiplied RGBA
+        @param colorSpace  SkColorSpace describing the encoding of color
+    */
+    void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace);
+
+    /** Retrieves alpha from the color used when stroking and filling.
+
+        @return  alpha ranging from zero, fully transparent, to 255, fully opaque
+    */
+    uint8_t getAlpha() const { return sk_float_round2int(fColor4f.fA * 255); }
+
+    /** Replaces alpha, leaving RGB
+        unchanged. An out of range value triggers an assert in the debug
+        build. a is a value from zero to 255.
+        a set to zero makes color fully transparent; a set to 255 makes color
+        fully opaque.
+
+        @param a  alpha component of color
+    */
+    void setAlpha(U8CPU a);
+
+    /** Sets color used when drawing solid fills. The color components range from 0 to 255.
+        The color is unpremultiplied; alpha sets the transparency independent of RGB.
+
+        @param a  amount of alpha, from fully transparent (0) to fully opaque (255)
+        @param r  amount of red, from no red (0) to full red (255)
+        @param g  amount of green, from no green (0) to full green (255)
+        @param b  amount of blue, from no blue (0) to full blue (255)
+    */
+    void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
+
+    /** Returns the thickness of the pen used by SkPaint to
+        outline the shape.
+
+        @return  zero for hairline, greater than zero for pen thickness
+    */
+    SkScalar getStrokeWidth() const { return fWidth; }
+
+    /** Sets the thickness of the pen used by the paint to
+        outline the shape.
+        Has no effect if width is less than zero.
+
+        @param width  zero thickness for hairline; greater than zero for pen thickness
+    */
+    void setStrokeWidth(SkScalar width);
+
+    /** Returns the limit at which a sharp corner is drawn beveled.
+
+        @return  zero and greater miter limit
+    */
+    SkScalar getStrokeMiter() const { return fMiterLimit; }
+
+    /** Sets the limit at which a sharp corner is drawn beveled.
+        Valid values are zero and greater.
+        Has no effect if miter is less than zero.
+
+        @param miter  zero and greater miter limit
+    */
+    void setStrokeMiter(SkScalar miter);
+
+    /** \enum SkPaint::Cap
+        Cap draws at the beginning and end of an open path contour.
+    */
+    enum Cap {
+        kButt_Cap,                  //!< no stroke extension
+        kRound_Cap,                 //!< adds circle
+        kSquare_Cap,                //!< adds square
+        kLast_Cap    = kSquare_Cap, //!< largest Cap value
+        kDefault_Cap = kButt_Cap,   //!< equivalent to kButt_Cap
+    };
+
+    /** May be used to verify that SkPaint::Cap is a legal value.
+    */
+    static constexpr int kCapCount = kLast_Cap + 1;
+
+    /** \enum SkPaint::Join
+        Join specifies how corners are drawn when a shape is stroked. Join
+        affects the four corners of a stroked rectangle, and the connected segments in a
+        stroked path.
+
+        Choose miter join to draw sharp corners. Choose round join to draw a circle with a
+        radius equal to the stroke width on top of the corner. Choose bevel join to minimally
+        connect the thick strokes.
+
+        The fill path constructed to describe the stroked path respects the join setting but may
+        not contain the actual join. For instance, a fill path constructed with round joins does
+        not necessarily include circles at each connected segment.
+    */
+    enum Join : uint8_t {
+        kMiter_Join,                 //!< extends to miter limit
+        kRound_Join,                 //!< adds circle
+        kBevel_Join,                 //!< connects outside edges
+        kLast_Join    = kBevel_Join, //!< equivalent to the largest value for Join
+        kDefault_Join = kMiter_Join, //!< equivalent to kMiter_Join
+    };
+
+    /** May be used to verify that SkPaint::Join is a legal value.
+    */
+    static constexpr int kJoinCount = kLast_Join + 1;
+
+    /** Returns the geometry drawn at the beginning and end of strokes.
+
+        @return  one of: kButt_Cap, kRound_Cap, kSquare_Cap
+    */
+    Cap getStrokeCap() const { return (Cap)fBitfields.fCapType; }
+
+    /** Sets the geometry drawn at the beginning and end of strokes.
+
+        @param cap  one of: kButt_Cap, kRound_Cap, kSquare_Cap;
+                    has no effect if cap is not valid
+    */
+    void setStrokeCap(Cap cap);
+
+    /** Returns the geometry drawn at the corners of strokes.
+
+        @return  one of: kMiter_Join, kRound_Join, kBevel_Join
+    */
+    Join getStrokeJoin() const { return (Join)fBitfields.fJoinType; }
+
+    /** Sets the geometry drawn at the corners of strokes.
+
+        @param join  one of: kMiter_Join, kRound_Join, kBevel_Join;
+                     otherwise, has no effect
+    */
+    void setStrokeJoin(Join join);
+
+    /** Returns the filled equivalent of the stroked path.
+
+        @param src       SkPath read to create a filled version
+        @param dst       resulting SkPath; may be the same as src, but may not be nullptr
+        @param cullRect  optional limit passed to SkPathEffect
+        @param resScale  if > 1, increase precision, else if (0 < resScale < 1) reduce precision
+                         to favor speed and size
+        @return          true if the path represents style fill, or false if it represents hairline
+    */
+    bool getFillPath(const SkPath& src, SkPath* dst, const SkRect* cullRect,
+                     SkScalar resScale = 1) const;
+
+    /** Returns the filled equivalent of the stroked path.
+
+        Replaces dst with the src path modified by SkPathEffect and style stroke.
+        SkPathEffect, if any, is not culled. stroke width is created with default precision.
+
+        @param src  SkPath read to create a filled version
+        @param dst  resulting SkPath dst may be the same as src, but may not be nullptr
+        @return     true if the path represents style fill, or false if it represents hairline
+    */
+    bool getFillPath(const SkPath& src, SkPath* dst) const {
+        return this->getFillPath(src, dst, nullptr, 1);
+    }
+
+    /** Returns optional colors used when filling a path, such as a gradient.
+
+        Does not alter SkShader SkRefCnt.
+
+        @return  SkShader if previously set, nullptr otherwise
+    */
+    SkShader* getShader() const { return fShader.get(); }
+
+    /** Returns optional colors used when filling a path, such as a gradient.
+
+        Increases SkShader SkRefCnt by one.
+
+        @return  SkShader if previously set, nullptr otherwise
+    */
+    sk_sp<SkShader> refShader() const;
+
+    /** Sets optional colors used when filling a path, such as a gradient.
+
+        Sets SkShader to shader, decreasing SkRefCnt of the previous SkShader.
+        Increments shader SkRefCnt by one.
+
+        @param shader  how geometry is filled with color; if nullptr, color is used instead
+    */
+    void setShader(sk_sp<SkShader> shader);
+
+    /** Returns SkColorFilter if set, or nullptr.
+        Does not alter SkColorFilter SkRefCnt.
+
+        @return  SkColorFilter if previously set, nullptr otherwise
+    */
+    SkColorFilter* getColorFilter() const { return fColorFilter.get(); }
+
+    /** Returns SkColorFilter if set, or nullptr.
+        Increases SkColorFilter SkRefCnt by one.
+
+        @return  SkColorFilter if set, or nullptr
+    */
+    sk_sp<SkColorFilter> refColorFilter() const;
+
+    /** Sets SkColorFilter to filter, decreasing SkRefCnt of the previous
+        SkColorFilter. Pass nullptr to clear SkColorFilter.
+
+        Increments filter SkRefCnt by one.
+
+        @param colorFilter  SkColorFilter to apply to subsequent draw
+    */
+    void setColorFilter(sk_sp<SkColorFilter> colorFilter);
+
+    /** Returns SkBlendMode.
+        By default, returns SkBlendMode::kSrcOver.
+
+        @return  mode used to combine source color with destination color
+    */
+    SkBlendMode getBlendMode() const { return (SkBlendMode)fBlendMode; }
+
+    /** Returns true if SkBlendMode is SkBlendMode::kSrcOver, the default.
+
+        @return  true if SkBlendMode is SkBlendMode::kSrcOver
+    */
+    bool isSrcOver() const { return (SkBlendMode)fBlendMode == SkBlendMode::kSrcOver; }
+
+    /** Sets SkBlendMode to mode.
+        Does not check for valid input.
+
+        @param mode  SkBlendMode used to combine source color and destination
+    */
+    void setBlendMode(SkBlendMode mode) { fBlendMode = (unsigned)mode; }
+
+    /** Returns SkPathEffect if set, or nullptr.
+        Does not alter SkPathEffect SkRefCnt.
+
+        @return  SkPathEffect if previously set, nullptr otherwise
+    */
+    SkPathEffect* getPathEffect() const { return fPathEffect.get(); }
+
+    /** Returns SkPathEffect if set, or nullptr.
+        Increases SkPathEffect SkRefCnt by one.
+
+        @return  SkPathEffect if previously set, nullptr otherwise
+    */
+    sk_sp<SkPathEffect> refPathEffect() const;
+
+    /** Sets SkPathEffect to pathEffect, decreasing SkRefCnt of the previous
+        SkPathEffect. Pass nullptr to leave the path geometry unaltered.
+
+        Increments pathEffect SkRefCnt by one.
+
+        @param pathEffect  replace SkPath with a modification when drawn
+    */
+    void setPathEffect(sk_sp<SkPathEffect> pathEffect);
+
+    /** Returns SkMaskFilter if set, or nullptr.
+        Does not alter SkMaskFilter SkRefCnt.
+
+        @return  SkMaskFilter if previously set, nullptr otherwise
+    */
+    SkMaskFilter* getMaskFilter() const { return fMaskFilter.get(); }
+
+    /** Returns SkMaskFilter if set, or nullptr.
+
+        Increases SkMaskFilter SkRefCnt by one.
+
+        @return  SkMaskFilter if previously set, nullptr otherwise
+    */
+    sk_sp<SkMaskFilter> refMaskFilter() const;
+
+    /** Sets SkMaskFilter to maskFilter, decreasing SkRefCnt of the previous
+        SkMaskFilter. Pass nullptr to clear SkMaskFilter and leave SkMaskFilter effect on
+        mask alpha unaltered.
+
+        Increments maskFilter SkRefCnt by one.
+
+        @param maskFilter  modifies clipping mask generated from drawn geometry
+    */
+    void setMaskFilter(sk_sp<SkMaskFilter> maskFilter);
+
+    /** Returns SkTypeface if set, or nullptr.
+        Does not alter SkTypeface SkRefCnt.
+
+        @return  SkTypeface if previously set, nullptr otherwise
+    */
+    SkTypeface* getTypeface() const { return fTypeface.get(); }
+
+    /** Increases SkTypeface SkRefCnt by one.
+
+        @return  SkTypeface if previously set, nullptr otherwise
+    */
+    sk_sp<SkTypeface> refTypeface() const;
+
+    /** Sets SkTypeface to typeface, decreasing SkRefCnt of the previous SkTypeface.
+        Pass nullptr to clear SkTypeface and use the default typeface. Increments
+        typeface SkRefCnt by one.
+
+        @param typeface  font and style used to draw text
+    */
+    void setTypeface(sk_sp<SkTypeface> typeface);
+
+    /** Returns SkImageFilter if set, or nullptr.
+        Does not alter SkImageFilter SkRefCnt.
+
+        @return  SkImageFilter if previously set, nullptr otherwise
+    */
+    SkImageFilter* getImageFilter() const { return fImageFilter.get(); }
+
+    /** Returns SkImageFilter if set, or nullptr.
+        Increases SkImageFilter SkRefCnt by one.
+
+        @return  SkImageFilter if previously set, nullptr otherwise
+    */
+    sk_sp<SkImageFilter> refImageFilter() const;
+
+    /** Sets SkImageFilter to imageFilter, decreasing SkRefCnt of the previous
+        SkImageFilter. Pass nullptr to clear SkImageFilter, and remove SkImageFilter effect
+        on drawing.
+
+        Increments imageFilter SkRefCnt by one.
+
+        @param imageFilter  how SkImage is sampled when transformed
+    */
+    void setImageFilter(sk_sp<SkImageFilter> imageFilter);
+
+    /** Returns SkDrawLooper if set, or nullptr.
+        Does not alter SkDrawLooper SkRefCnt.
+
+        @return  SkDrawLooper if previously set, nullptr otherwise
+    */
+    SkDrawLooper* getDrawLooper() const { return fDrawLooper.get(); }
+
+    /** Returns SkDrawLooper if set, or nullptr.
+        Increases SkDrawLooper SkRefCnt by one.
+
+        @return  SkDrawLooper if previously set, nullptr otherwise
+    */
+    sk_sp<SkDrawLooper> refDrawLooper() const;
+
+    /** Deprecated.
+        (see skbug.com/6259)
+    */
+    SkDrawLooper* getLooper() const { return fDrawLooper.get(); }
+
+    /** Sets SkDrawLooper to drawLooper, decreasing SkRefCnt of the previous
+        drawLooper.  Pass nullptr to clear SkDrawLooper and leave SkDrawLooper effect on
+        drawing unaltered.
+
+        Increments drawLooper SkRefCnt by one.
+
+        @param drawLooper  iterates through drawing one or more time, altering SkPaint
+    */
+    void setDrawLooper(sk_sp<SkDrawLooper> drawLooper);
+
+    /** Deprecated.
+        (see skbug.com/6259)
+    */
+    void setLooper(sk_sp<SkDrawLooper> drawLooper);
+
+    /** Returns text size in points.
+
+        @return  typographic height of text
+    */
+    SkScalar getTextSize() const { return fTextSize; }
+
+    /** Sets text size in points.
+        Has no effect if textSize is not greater than or equal to zero.
+
+        @param textSize  typographic height of text
+    */
+    void setTextSize(SkScalar textSize);
+
+    /** Returns text scale on x-axis.
+        Default value is 1.
+
+        @return  text horizontal scale
+    */
+    SkScalar getTextScaleX() const { return fTextScaleX; }
+
+    /** Sets text scale on x-axis.
+        Default value is 1.
+
+        @param scaleX  text horizontal scale
+    */
+    void setTextScaleX(SkScalar scaleX);
+
+    /** Returns text skew on x-axis.
+        Default value is zero.
+
+        @return  additional shear on x-axis relative to y-axis
+    */
+    SkScalar getTextSkewX() const { return fTextSkewX; }
+
+    /** Sets text skew on x-axis.
+        Default value is zero.
+
+        @param skewX  additional shear on x-axis relative to y-axis
+    */
+    void setTextSkewX(SkScalar skewX);
+
+    /** \enum SkPaint::TextEncoding
+        TextEncoding determines whether text specifies character codes and their encoded
+        size, or glyph indices. Characters are encoded as specified by the Unicode standard.
+
+        Character codes encoded size are specified by UTF-8, UTF-16, or UTF-32.
+        All character code formats are able to represent all of Unicode, differing only
+        in the total storage required.
+
+        UTF-8 (RFC 3629) encodes each character as one or more 8-bit bytes.
+
+        UTF-16 (RFC 2781) encodes each character as one or two 16-bit words.
+
+        UTF-32 encodes each character as one 32-bit word.
+
+        font manager uses font data to convert character code points into glyph indices.
+        A glyph index is a 16-bit word.
+
+        TextEncoding is set to kUTF8_TextEncoding by default.
+    */
+    enum TextEncoding : uint8_t {
+        kUTF8_TextEncoding,    //!< uses bytes to represent UTF-8 or ASCII
+        kUTF16_TextEncoding,   //!< uses two byte words to represent most of Unicode
+        kUTF32_TextEncoding,   //!< uses four byte words to represent all of Unicode
+        kGlyphID_TextEncoding, //!< uses two byte words to represent glyph indices
+    };
+
+    /** Returns SkPaint::TextEncoding.
+        SkPaint::TextEncoding determines how character code points are mapped to font glyph indices.
+
+        @return  one of: kUTF8_TextEncoding, kUTF16_TextEncoding, kUTF32_TextEncoding, or
+                 kGlyphID_TextEncoding
+    */
+    TextEncoding getTextEncoding() const {
+      return (TextEncoding)fBitfields.fTextEncoding;
+    }
+
+    /** Sets SkPaint::TextEncoding to encoding.
+        SkPaint::TextEncoding determines how character code points are mapped to font glyph indices.
+        Invalid values for encoding are ignored.
+
+        @param encoding  one of: kUTF8_TextEncoding, kUTF16_TextEncoding, kUTF32_TextEncoding, or
+                         kGlyphID_TextEncoding
+    */
+    void setTextEncoding(TextEncoding encoding);
+    // Experimental
+    void setTextEncoding(SkTextEncoding encoding) {
+        this->setTextEncoding((TextEncoding)encoding);
+    }
+
+#ifdef SK_SUPPORT_LEGACY_PAINT_TEXTMEASURE
+
+#ifdef SK_SUPPORT_LEGACY_FONTMETRICS_IN_PAINT
+    /**
+        SkFontMetrics is filled out by getFontMetrics(). SkFontMetrics contents reflect the values
+        computed by font manager using SkTypeface. Values are set to zero if they are
+        not available.
+
+        All vertical values are relative to the baseline, on a y-axis pointing down.
+        Zero is on the baseline, negative values are above the baseline, and positive
+        values are below the baseline.
+
+        fUnderlineThickness and fUnderlinePosition have a bit set in fFlags if their values
+        are valid, since their value may be zero.
+
+        fStrikeoutThickness and fStrikeoutPosition have a bit set in fFlags if their values
+        are valid, since their value may be zero.
+    */
+    typedef SkFontMetrics FontMetrics;
+#endif
+
+    /** Returns SkFontMetrics associated with SkTypeface.
+        The return value is the recommended spacing between lines: the sum of metrics
+        descent, ascent, and leading.
+        If metrics is not nullptr, SkFontMetrics is copied to metrics.
+        Results are scaled by text size but does not take into account
+        dimensions required by text scale x, text skew x, fake bold,
+        style stroke, and SkPathEffect.
+
+        @param metrics  storage for SkFontMetrics; may be nullptr
+        @return         recommended spacing between lines
+    */
+    SkScalar getFontMetrics(SkFontMetrics* metrics) const;
+
+    /** Returns the recommended spacing between lines: the sum of metrics
+        descent, ascent, and leading.
+        Result is scaled by text size but does not take into account
+        dimensions required by stroking and SkPathEffect.
+        Returns the same result as getFontMetrics().
+
+        @return  recommended spacing between lines
+    */
+    SkScalar getFontSpacing() const { return this->getFontMetrics(nullptr); }
+
+    /** Converts text into glyph indices.
+        Returns the number of glyph indices represented by text.
+        SkPaint::TextEncoding specifies how text represents characters or glyphs.
+        glyphs may be nullptr, to compute the glyph count.
+
+        Does not check text for valid character codes or valid glyph indices.
+
+        If byteLength equals zero, returns zero.
+        If byteLength includes a partial character, the partial character is ignored.
+
+        If SkPaint::TextEncoding is kUTF8_TextEncoding and
+        text contains an invalid UTF-8 sequence, zero is returned.
+
+        @param text        character storage encoded with SkPaint::TextEncoding
+        @param byteLength  length of character storage in bytes
+        @param glyphs      storage for glyph indices; may be nullptr
+        @return            number of glyphs represented by text of length byteLength
+    */
+    int textToGlyphs(const void* text, size_t byteLength,
+                     SkGlyphID glyphs[]) const;
+
+    /** Returns true if all text corresponds to a non-zero glyph index.
+        Returns false if any characters in text are not supported in
+        SkTypeface.
+
+        If SkPaint::TextEncoding is kGlyphID_TextEncoding,
+        returns true if all glyph indices in text are non-zero;
+        does not check to see if text contains valid glyph indices for SkTypeface.
+
+        Returns true if byteLength is zero.
+
+        @param text        array of characters or glyphs
+        @param byteLength  number of bytes in text array
+        @return            true if all text corresponds to a non-zero glyph index
+    */
+    bool containsText(const void* text, size_t byteLength) const;
+
+    /** Converts glyphs into text if possible.
+        Glyph values without direct Unicode equivalents are mapped to zero.
+        Uses the SkTypeface, but is unaffected
+        by SkPaint::TextEncoding; the text values returned are equivalent to kUTF32_TextEncoding.
+
+        Only supported on platforms that use FreeType as the font engine.
+
+        @param glyphs  array of indices into font
+        @param count   length of glyph array
+        @param text    storage for character codes, one per glyph
+    */
+    void glyphsToUnichars(const SkGlyphID glyphs[], int count, SkUnichar text[]) const;
+
+    /** Returns the number of glyphs in text.
+        Uses SkPaint::TextEncoding to count the glyphs.
+        Returns the same result as textToGlyphs().
+
+        @param text        character storage encoded with SkPaint::TextEncoding
+        @param byteLength  length of character storage in bytes
+        @return            number of glyphs represented by text of length byteLength
+    */
+    int countText(const void* text, size_t byteLength) const;
+
+    /** Returns the advance width of text.
+        The advance is the normal distance to move before drawing additional text.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the font metrics,
+        and text size, text scale x, text skew x, stroke width, and
+        SkPathEffect to scale the metrics and bounds.
+        Returns the bounding box of text if bounds is not nullptr.
+        The bounding box is computed as if the text was drawn at the origin.
+
+        @param text    character codes or glyph indices to be measured
+        @param length  number of bytes of text to measure
+        @param bounds  returns bounding box relative to (0, 0) if not nullptr
+        @return        advance width or height
+    */
+    SkScalar measureText(const void* text, size_t length, SkRect* bounds) const;
+
+    /** Returns the advance width of text.
+        The advance is the normal distance to move before drawing additional text.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the font metrics,
+        and text size to scale the metrics.
+        Does not scale the advance or bounds by fake bold or SkPathEffect.
+
+        @param text    character codes or glyph indices to be measured
+        @param length  number of bytes of text to measure
+        @return        advance width or height
+    */
+    SkScalar measureText(const void* text, size_t length) const {
+        return this->measureText(text, length, nullptr);
+    }
+#endif
+
+    /** Returns the bytes of text that fit within maxWidth.
+        The text fragment fits if its advance width is less than or equal to maxWidth.
+        Measures only while the advance is less than or equal to maxWidth.
+        Returns the advance or the text fragment in measuredWidth if it not nullptr.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the font metrics,
+        and text size to scale the metrics.
+        Does not scale the advance or bounds by fake bold or SkPathEffect.
+
+        @param text           character codes or glyph indices to be measured
+        @param length         number of bytes of text to measure
+        @param maxWidth       advance limit; text is measured while advance is less than maxWidth
+        @param measuredWidth  returns the width of the text less than or equal to maxWidth
+        @return               bytes of text that fit, always less than or equal to length
+    */
+    size_t  breakText(const void* text, size_t length, SkScalar maxWidth,
+                      SkScalar* measuredWidth = nullptr) const;
+
+#ifdef SK_SUPPORT_LEGACY_PAINT_TEXTMEASURE
+    /** Retrieves the advance and bounds for each glyph in text, and returns
+        the glyph count in text.
+        Both widths and bounds may be nullptr.
+        If widths is not nullptr, widths must be an array of glyph count entries.
+        if bounds is not nullptr, bounds must be an array of glyph count entries.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the font metrics,
+        and text size to scale the widths and bounds.
+        Does not scale the advance by fake bold or SkPathEffect.
+        Does include fake bold and SkPathEffect in the bounds.
+
+        @param text        character codes or glyph indices to be measured
+        @param byteLength  number of bytes of text to measure
+        @param widths      returns text advances for each glyph; may be nullptr
+        @param bounds      returns bounds for each glyph relative to (0, 0); may be nullptr
+        @return            glyph count in text
+    */
+    int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
+                      SkRect bounds[] = nullptr) const;
+
+    /** Returns the geometry as SkPath equivalent to the drawn text.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        All of the glyph paths are stored in path.
+        Uses x, y, to position path.
+
+        @param text    character codes or glyph indices
+        @param length  number of bytes of text
+        @param x       x-axis value of the origin of the text
+        @param y       y-axis value of the origin of the text
+        @param path    geometry of the glyphs
+    */
+    void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
+                     SkPath* path) const;
+
+    /** Returns the geometry as SkPath equivalent to the drawn text.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        All of the glyph paths are stored in path.
+        Uses pos array to position path.
+        pos contains a position for each glyph.
+
+        @param text    character codes or glyph indices
+        @param length  number of bytes of text
+        @param pos     positions of each glyph
+        @param path    geometry of the glyphs
+    */
+    void getPosTextPath(const void* text, size_t length,
+                        const SkPoint pos[], SkPath* path) const;
+
+#ifdef SK_SUPPORT_LEGACY_TEXTINTERCEPTS
+public:
+#else
+private:
+#endif
+    /** Returns the number of intervals that intersect bounds.
+        bounds describes a pair of lines parallel to the text advance.
+        The return count is zero or a multiple of two, and is at most twice the number of glyphs in
+        the string.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        Uses x, y to position intervals.
+
+        Pass nullptr for intervals to determine the size of the interval array.
+
+        intervals are cached to improve performance for multiple calls.
+
+        @param text       character codes or glyph indices
+        @param length     number of bytes of text
+        @param x          x-axis value of the origin of the text
+        @param y          y-axis value of the origin of the text
+        @param bounds     lower and upper line parallel to the advance
+        @param intervals  returned intersections; may be nullptr
+        @return           number of intersections; may be zero
+    */
+    int getTextIntercepts(const void* text, size_t length, SkScalar x, SkScalar y,
+                          const SkScalar bounds[2], SkScalar* intervals) const;
+
+    /** Returns the number of intervals that intersect bounds.
+        bounds describes a pair of lines parallel to the text advance.
+        The return count is zero or a multiple of two, and is at most twice the number of glyphs in
+        the string.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        Uses pos array to position intervals.
+
+        Pass nullptr for intervals to determine the size of the interval array.
+
+        intervals are cached to improve performance for multiple calls.
+
+        @param text       character codes or glyph indices
+        @param length     number of bytes of text
+        @param pos        positions of each glyph
+        @param bounds     lower and upper line parallel to the advance
+        @param intervals  returned intersections; may be nullptr
+        @return           number of intersections; may be zero
+    */
+    int getPosTextIntercepts(const void* text, size_t length, const SkPoint pos[],
+                             const SkScalar bounds[2], SkScalar* intervals) const;
+
+    /** Returns the number of intervals that intersect bounds.
+        bounds describes a pair of lines parallel to the text advance.
+        The return count is zero or a multiple of two, and is at most twice the number of glyphs in
+        the string.
+        Uses SkPaint::TextEncoding to decode text, SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        Uses xpos array, constY to position intervals.
+
+        Pass nullptr for intervals to determine the size of the interval array.
+
+        intervals are cached to improve performance for multiple calls.
+
+        @param text       character codes or glyph indices
+        @param length     number of bytes of text
+        @param xpos       positions of each glyph on x-axis
+        @param constY     position of each glyph on y-axis
+        @param bounds     lower and upper line parallel to the advance
+        @param intervals  returned intersections; may be nullptr
+        @return           number of intersections; may be zero
+    */
+    int getPosTextHIntercepts(const void* text, size_t length, const SkScalar xpos[],
+                              SkScalar constY, const SkScalar bounds[2], SkScalar* intervals) const;
+public:
+
+    /** Returns the number of intervals that intersect bounds.
+        bounds describes a pair of lines parallel to the text advance.
+        The return count is zero or a multiple of two, and is at most twice the number of glyphs in
+        the string.
+        Uses SkTypeface to get the glyph paths,
+        and text size, fake bold, and SkPathEffect to scale and modify the glyph paths.
+        Uses run array to position intervals.
+
+        SkPaint::TextEncoding must be set to SkPaint::kGlyphID_TextEncoding.
+
+        Pass nullptr for intervals to determine the size of the interval array.
+
+        intervals are cached to improve performance for multiple calls.
+
+        @param blob       glyphs, positions, and text paint attributes
+        @param bounds     lower and upper line parallel to the advance
+        @param intervals  returned intersections; may be nullptr
+        @return           number of intersections; may be zero
+    */
+    int getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2],
+                              SkScalar* intervals) const;
+
+    /** Returns the union of bounds of all glyphs.
+        Returned dimensions are computed by font manager from font data,
+        ignoring SkPaint::Hinting. Includes font metrics, but not fake bold or SkPathEffect.
+
+        If text size is large, text scale is one, and text skew is zero,
+        returns the bounds as:
+        { SkFontMetrics::fXMin, SkFontMetrics::fTop, SkFontMetrics::fXMax, SkFontMetrics::fBottom }.
+
+        @return  union of bounds of all glyphs
+    */
+    SkRect getFontBounds() const;
+#endif
+
+    /** Returns true if SkPaint prevents all drawing;
+        otherwise, the SkPaint may or may not allow drawing.
+
+        Returns true if, for example, SkBlendMode combined with alpha computes a
+        new alpha of zero.
+
+        @return  true if SkPaint prevents all drawing
+    */
+    bool nothingToDraw() const;
+
+    /**     (to be made private)
+        Returns true if SkPaint does not include elements requiring extensive computation
+        to compute SkBaseDevice bounds of drawn geometry. For instance, SkPaint with SkPathEffect
+        always returns false.
+
+        @return  true if SkPaint allows for fast computation of bounds
+    */
+    bool canComputeFastBounds() const;
+
+    /**     (to be made private)
+        Only call this if canComputeFastBounds() returned true. This takes a
+        raw rectangle (the raw bounds of a shape), and adjusts it for stylistic
+        effects in the paint (e.g. stroking). If needed, it uses the storage
+        parameter. It returns the adjusted bounds that can then be used
+        for SkCanvas::quickReject tests.
+
+        The returned SkRect will either be orig or storage, thus the caller
+        should not rely on storage being set to the result, but should always
+        use the returned value. It is legal for orig and storage to be the same
+        SkRect.
+            For example:
+            if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
+                SkRect storage;
+                if (canvas->quickReject(paint.computeFastBounds(path.getBounds(), &storage))) {
+                    return; // do not draw the path
+                }
+            }
+            // draw the path
+
+        @param orig     geometry modified by SkPaint when drawn
+        @param storage  computed bounds of geometry; may not be nullptr
+        @return         fast computed bounds
+    */
+    const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const {
+        // Things like stroking, etc... will do math on the bounds rect, assuming that it's sorted.
+        SkASSERT(orig.isSorted());
+        SkPaint::Style style = this->getStyle();
+        // ultra fast-case: filling with no effects that affect geometry
+        if (kFill_Style == style) {
+            uintptr_t effects = reinterpret_cast<uintptr_t>(this->getLooper());
+            effects |= reinterpret_cast<uintptr_t>(this->getMaskFilter());
+            effects |= reinterpret_cast<uintptr_t>(this->getPathEffect());
+            effects |= reinterpret_cast<uintptr_t>(this->getImageFilter());
+            if (!effects) {
+                return orig;
+            }
+        }
+
+        return this->doComputeFastBounds(orig, storage, style);
+    }
+
+    /**     (to be made private)
+
+        @param orig     geometry modified by SkPaint when drawn
+        @param storage  computed bounds of geometry
+        @return         fast computed bounds
+    */
+    const SkRect& computeFastStrokeBounds(const SkRect& orig,
+                                          SkRect* storage) const {
+        return this->doComputeFastBounds(orig, storage, kStroke_Style);
+    }
+
+    /**     (to be made private)
+        Computes the bounds, overriding the SkPaint SkPaint::Style. This can be used to
+        account for additional width required by stroking orig, without
+        altering SkPaint::Style set to fill.
+
+        @param orig     geometry modified by SkPaint when drawn
+        @param storage  computed bounds of geometry
+        @param style    overrides SkPaint::Style
+        @return         fast computed bounds
+    */
+    const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage,
+                                      Style style) const;
+
+private:
+    friend class SkGlyphRun;
+    friend class SkGlyphRunBuilder;
+    SkPaint(const SkPaint&, const SkRunFont&);
+
+    sk_sp<SkTypeface>     fTypeface;
+    sk_sp<SkPathEffect>   fPathEffect;
+    sk_sp<SkShader>       fShader;
+    sk_sp<SkMaskFilter>   fMaskFilter;
+    sk_sp<SkColorFilter>  fColorFilter;
+    sk_sp<SkDrawLooper>   fDrawLooper;
+    sk_sp<SkImageFilter>  fImageFilter;
+
+    SkScalar        fTextSize;
+    SkScalar        fTextScaleX;
+    SkScalar        fTextSkewX;
+    SkColor4f       fColor4f;
+    SkScalar        fWidth;
+    SkScalar        fMiterLimit;
+    uint32_t        fBlendMode; // just need 5-6 bits
+    union {
+        struct {
+            // all of these bitfields should add up to 32
+            unsigned        fFlags : 16;
+            unsigned        fCapType : 2;
+            unsigned        fJoinType : 2;
+            unsigned        fStyle : 2;
+            unsigned        fTextEncoding : 2;  // 3 values
+            unsigned        fHinting : 2;
+            unsigned        fFilterQuality : 2;
+            //unsigned      fFreeBits : 4;
+        } fBitfields;
+        uint32_t fBitfieldsUInt;
+    };
+
+    SkScalar measure_text(SkGlyphCache*, const char* text, size_t length,
+                          int* count, SkRect* bounds) const;
+
+    /*
+     * The luminance color is used to determine which Gamma Canonical color to map to.  This is
+     * really only used by backends which want to cache glyph masks, and need some way to know if
+     * they need to generate new masks based off a given color.
+     */
+    SkColor computeLuminanceColor() const;
+
+    /*  This is the size we use when we ask for a glyph's path. We then
+     *  post-transform it as we draw to match the request.
+     *  This is done to try to re-use cache entries for the path.
+     *
+     *  This value is somewhat arbitrary. In theory, it could be 1, since
+     *  we store paths as floats. However, we get the path from the font
+     *  scaler, and it may represent its paths as fixed-point (or 26.6),
+     *  so we shouldn't ask for something too big (might overflow 16.16)
+     *  or too small (underflow 26.6).
+     *
+     *  This value could track kMaxSizeForGlyphCache, assuming the above
+     *  constraints, but since we ask for unhinted paths, the two values
+     *  need not match per-se.
+     */
+    static constexpr int kCanonicalTextSizeForPaths  = 64;
+
+    static bool TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM, SkScalar maxLimit);
+
+    // Set flags/hinting/textSize up to use for drawing text as paths.
+    // Returns scale factor to restore the original textSize, since will will
+    // have change it to kCanonicalTextSizeForPaths.
+    SkScalar setupForAsPaths();
+
+    static SkScalar MaxCacheSize2(SkScalar maxLimit);
+
+    friend class GrTextBlob;
+    friend class GrTextContext;
+    friend class GrGLPathRendering;
+    friend class GrPathRendering;
+    friend class SkAutoGlyphCacheNoGamma;
+    friend class SkCanonicalizePaint;
+    friend class SkCanvas;
+    friend class SkDraw;
+    friend class SkFont;
+    friend class SkGlyphRunListPainter;
+    friend class SkPaintPriv;
+    friend class SkPDFDevice;
+    friend class SkScalerContext;  // for computeLuminanceColor()
+    friend class SkTextBaseIter;
+    friend class SkTextBlobCacheDiffCanvas;
+};
+
+#endif

+ 1779 - 0
skia/include/core/SkPath.h

@@ -0,0 +1,1779 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkPath.h and docs/SkPath_Reference.bmh
+   on 2018-09-13 13:59:55. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkPath_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkPath_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkPath.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkPath_DEFINED
+#define SkPath_DEFINED
+
+#include "SkMatrix.h"
+#include "../private/SkPathRef.h"
+#include "../private/SkTo.h"
+
+#include <initializer_list>
+
+class SkAutoPathBoundsUpdate;
+class SkData;
+class SkRRect;
+class SkWStream;
+
+/** \class SkPath
+    SkPath contain geometry. SkPath may be empty, or contain one or more verbs that
+    outline a figure. SkPath always starts with a move verb to a Cartesian coordinate,
+    and may be followed by additional verbs that add lines or curves.
+    Adding a close verb makes the geometry into a continuous loop, a closed contour.
+    SkPath may contain any number of contours, each beginning with a move verb.
+
+    SkPath contours may contain only a move verb, or may also contain lines,
+    quadratic beziers, conics, and cubic beziers. SkPath contours may be open or
+    closed.
+
+    When used to draw a filled area, SkPath describes whether the fill is inside or
+    outside the geometry. SkPath also describes the winding rule used to fill
+    overlapping contours.
+
+    Internally, SkPath lazily computes metrics likes bounds and convexity. Call
+    SkPath::updateBoundsCache to make SkPath thread safe.
+*/
+class SK_API SkPath {
+public:
+
+    /** \enum SkPath::Direction
+        Direction describes whether contour is clockwise or counterclockwise.
+        When SkPath contains multiple overlapping contours, Direction together with
+        FillType determines whether overlaps are filled or form holes.
+
+        Direction also determines how contour is measured. For instance, dashing
+        measures along SkPath to determine where to start and stop stroke; Direction
+        will change dashed results as it steps clockwise or counterclockwise.
+
+        Closed contours like SkRect, SkRRect, circle, and oval added with
+        kCW_Direction travel clockwise; the same added with kCCW_Direction
+        travel counterclockwise.
+    */
+    enum Direction : int {
+        kCW_Direction,  //!< contour travels clockwise
+        kCCW_Direction, //!< contour travels counterclockwise
+    };
+
+    /** Constructs an empty SkPath. By default, SkPath has no verbs, no SkPoint, and no weights.
+        SkPath::FillType is set to kWinding_FillType.
+
+        @return  empty SkPath
+    */
+    SkPath();
+
+    /** Constructs a copy of an existing path.
+        Copy constructor makes two paths identical by value. Internally, path and
+        the returned result share pointer values. The underlying verb array, SkPoint array
+        and weights are copied when modified.
+
+        Creating a SkPath copy is very efficient and never allocates memory.
+        SkPath are always copied by value from the interface; the underlying shared
+        pointers are not exposed.
+
+        @param path  SkPath to copy by value
+        @return      copy of SkPath
+    */
+    SkPath(const SkPath& path);
+
+    /** Releases ownership of any shared data and deletes data if SkPath is sole owner.
+    */
+    ~SkPath();
+
+    /** Constructs a copy of an existing path.
+        SkPath assignment makes two paths identical by value. Internally, assignment
+        shares pointer values. The underlying verb array, SkPoint array and weights
+        are copied when modified.
+
+        Copying SkPath by assignment is very efficient and never allocates memory.
+        SkPath are always copied by value from the interface; the underlying shared
+        pointers are not exposed.
+
+        @param path  verb array, SkPoint array, weights, and SkPath::FillType to copy
+        @return      SkPath copied by value
+    */
+    SkPath& operator=(const SkPath& path);
+
+    /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights
+        are equivalent.
+
+        @param a  SkPath to compare
+        @param b  SkPath to compare
+        @return   true if SkPath pair are equivalent
+    */
+    friend SK_API bool operator==(const SkPath& a, const SkPath& b);
+
+    /** Compares a and b; returns true if SkPath::FillType, verb array, SkPoint array, and weights
+        are not equivalent.
+
+        @param a  SkPath to compare
+        @param b  SkPath to compare
+        @return   true if SkPath pair are not equivalent
+    */
+    friend bool operator!=(const SkPath& a, const SkPath& b) {
+        return !(a == b);
+    }
+
+    /** Returns true if SkPath contain equal verbs and equal weights.
+        If SkPath contain one or more conics, the weights must match.
+
+        conicTo() may add different verbs depending on conic weight, so it is not
+        trivial to interpolate a pair of SkPath containing conics with different
+        conic weight values.
+
+        @param compare  SkPath to compare
+        @return         true if SkPath verb array and weights are equivalent
+    */
+    bool isInterpolatable(const SkPath& compare) const;
+
+    /** Interpolates between SkPath with SkPoint array of equal size.
+        Copy verb array and weights to out, and set out SkPoint array to a weighted
+        average of this SkPoint array and ending SkPoint array, using the formula:
+        (Path Point * weight) + ending Point * (1 - weight).
+
+        weight is most useful when between zero (ending SkPoint array) and
+        one (this Point_Array); will work with values outside of this
+        range.
+
+        interpolate() returns false and leaves out unchanged if SkPoint array is not
+        the same size as ending SkPoint array. Call isInterpolatable() to check SkPath
+        compatibility prior to calling interpolate().
+
+        @param ending  SkPoint array averaged with this SkPoint array
+        @param weight  contribution of this SkPoint array, and
+                       one minus contribution of ending SkPoint array
+        @param out     SkPath replaced by interpolated averages
+        @return        true if SkPath contain same number of SkPoint
+    */
+    bool interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const;
+
+    /** \enum SkPath::FillType
+        FillType selects the rule used to fill SkPath. SkPath set to kWinding_FillType
+        fills if the sum of contour edges is not zero, where clockwise edges add one, and
+        counterclockwise edges subtract one. SkPath set to kEvenOdd_FillType fills if the
+        number of contour edges is odd. Each FillType has an inverse variant that
+        reverses the rule:
+        kInverseWinding_FillType fills where the sum of contour edges is zero;
+        kInverseEvenOdd_FillType fills where the number of contour edges is even.
+    */
+    enum FillType {
+        kWinding_FillType,        //!< is enclosed by a non-zero sum of contour directions
+        kEvenOdd_FillType,        //!< is enclosed by an odd number of contours
+        kInverseWinding_FillType, //!< is enclosed by a zero sum of contour directions
+        kInverseEvenOdd_FillType, //!< is enclosed by an even number of contours
+    };
+
+    /** Returns FillType, the rule used to fill SkPath. FillType of a new SkPath is
+        kWinding_FillType.
+
+        @return  one of: kWinding_FillType, kEvenOdd_FillType,  kInverseWinding_FillType,
+                 kInverseEvenOdd_FillType
+    */
+    FillType getFillType() const { return (FillType)fFillType; }
+
+    /** Sets FillType, the rule used to fill SkPath. While there is no check
+        that ft is legal, values outside of FillType are not supported.
+
+        @param ft  one of: kWinding_FillType, kEvenOdd_FillType,  kInverseWinding_FillType,
+                   kInverseEvenOdd_FillType
+    */
+    void setFillType(FillType ft) {
+        fFillType = SkToU8(ft);
+    }
+
+    /** Returns if FillType describes area outside SkPath geometry. The inverse fill area
+        extends indefinitely.
+
+        @return  true if FillType is kInverseWinding_FillType or kInverseEvenOdd_FillType
+    */
+    bool isInverseFillType() const { return IsInverseFillType((FillType)fFillType); }
+
+    /** Replaces FillType with its inverse. The inverse of FillType describes the area
+        unmodified by the original FillType.
+    */
+    void toggleInverseFillType() {
+        fFillType ^= 2;
+    }
+
+    /** \enum SkPath::Convexity
+        SkPath is convex if it contains one contour and contour loops no more than
+        360 degrees, and contour angles all have same Direction. Convex SkPath
+        may have better performance and require fewer resources on GPU surface.
+
+        SkPath is concave when either at least one Direction change is clockwise and
+        another is counterclockwise, or the sum of the changes in Direction is not 360
+        degrees.
+
+        Initially SkPath Convexity is kUnknown_Convexity. SkPath Convexity is computed
+        if needed by destination SkSurface.
+    */
+    enum Convexity : uint8_t {
+        kUnknown_Convexity, //!< indicates Convexity has not been determined
+        kConvex_Convexity,  //!< one contour made of a simple geometry without indentations
+        kConcave_Convexity, //!< more than one contour, or a geometry with indentations
+    };
+
+    /** Computes SkPath::Convexity if required, and returns stored value.
+        SkPath::Convexity is computed if stored value is kUnknown_Convexity,
+        or if SkPath has been altered since SkPath::Convexity was computed or set.
+
+        @return  computed or stored SkPath::Convexity
+    */
+    Convexity getConvexity() const {
+        for (Convexity convexity = fConvexity.load(); kUnknown_Convexity != convexity; ) {
+            return convexity;
+        }
+        return this->internalGetConvexity();
+    }
+
+    /** Returns last computed SkPath::Convexity, or kUnknown_Convexity if
+        SkPath has been altered since SkPath::Convexity was computed or set.
+
+        @return  stored SkPath::Convexity
+    */
+    Convexity getConvexityOrUnknown() const { return (Convexity)fConvexity; }
+
+    /** Stores convexity so that it is later returned by getConvexity() or getConvexityOrUnknown().
+        convexity may differ from getConvexity(), although setting an incorrect value may
+        cause incorrect or inefficient drawing.
+
+        If convexity is kUnknown_Convexity: getConvexity() will
+        compute SkPath::Convexity, and getConvexityOrUnknown() will return kUnknown_Convexity.
+
+        If convexity is kConvex_Convexity or kConcave_Convexity, getConvexity()
+        and getConvexityOrUnknown() will return convexity until the path is
+        altered.
+
+        @param convexity  one of: kUnknown_Convexity, kConvex_Convexity, or kConcave_Convexity
+    */
+    void setConvexity(Convexity convexity);
+
+    /** Computes SkPath::Convexity if required, and returns true if value is kConvex_Convexity.
+        If setConvexity() was called with kConvex_Convexity or kConcave_Convexity, and
+        the path has not been altered, SkPath::Convexity is not recomputed.
+
+        @return  true if SkPath::Convexity stored or computed is kConvex_Convexity
+    */
+    bool isConvex() const {
+        return kConvex_Convexity == this->getConvexity();
+    }
+
+    /** Returns true if this path is recognized as an oval or circle.
+
+        bounds receives bounds of oval.
+
+        bounds is unmodified if oval is not found.
+
+        @param bounds  storage for bounding SkRect of oval; may be nullptr
+        @return        true if SkPath is recognized as an oval or circle
+    */
+    bool isOval(SkRect* bounds) const;
+
+    /** Returns true if path is representable as SkRRect.
+        Returns false if path is representable as oval, circle, or SkRect.
+
+        rrect receives bounds of SkRRect.
+
+        rrect is unmodified if SkRRect is not found.
+
+        @param rrect  storage for bounding SkRect of SkRRect; may be nullptr
+        @return       true if SkPath contains only SkRRect
+    */
+    bool isRRect(SkRRect* rrect) const;
+
+    /** Sets SkPath to its initial state.
+        Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType.
+        Internal storage associated with SkPath is released.
+
+        @return  reference to SkPath
+    */
+    SkPath& reset();
+
+    /** Sets SkPath to its initial state, preserving internal storage.
+        Removes verb array, SkPoint array, and weights, and sets FillType to kWinding_FillType.
+        Internal storage associated with SkPath is retained.
+
+        Use rewind() instead of reset() if SkPath storage will be reused and performance
+        is critical.
+
+        @return  reference to SkPath
+    */
+    SkPath& rewind();
+
+    /** Returns if SkPath is empty.
+        Empty SkPath may have FillType but has no SkPoint, SkPath::Verb, or conic weight.
+        SkPath() constructs empty SkPath; reset() and rewind() make SkPath empty.
+
+        @return  true if the path contains no SkPath::Verb array
+    */
+    bool isEmpty() const {
+        SkDEBUGCODE(this->validate();)
+        return 0 == fPathRef->countVerbs();
+    }
+
+    /** Returns if contour is closed.
+        Contour is closed if SkPath SkPath::Verb array was last modified by close(). When stroked,
+        closed contour draws SkPaint::Join instead of SkPaint::Cap at first and last SkPoint.
+
+        @return  true if the last contour ends with a kClose_Verb
+    */
+    bool isLastContourClosed() const;
+
+    /** Returns true for finite SkPoint array values between negative SK_ScalarMax and
+        positive SK_ScalarMax. Returns false for any SkPoint array value of
+        SK_ScalarInfinity, SK_ScalarNegativeInfinity, or SK_ScalarNaN.
+
+        @return  true if all SkPoint values are finite
+    */
+    bool isFinite() const {
+        SkDEBUGCODE(this->validate();)
+        return fPathRef->isFinite();
+    }
+
+    /** Returns true if the path is volatile; it will not be altered or discarded
+        by the caller after it is drawn. SkPath by default have volatile set false, allowing
+        SkSurface to attach a cache of data which speeds repeated drawing. If true, SkSurface
+        may not speed repeated drawing.
+
+        @return  true if caller will alter SkPath after drawing
+    */
+    bool isVolatile() const {
+        return SkToBool(fIsVolatile);
+    }
+
+    /** Specifies whether SkPath is volatile; whether it will be altered or discarded
+        by the caller after it is drawn. SkPath by default have volatile set false, allowing
+        SkBaseDevice to attach a cache of data which speeds repeated drawing.
+
+        Mark temporary paths, discarded or modified after use, as volatile
+        to inform SkBaseDevice that the path need not be cached.
+
+        Mark animating SkPath volatile to improve performance.
+        Mark unchanging SkPath non-volatile to improve repeated rendering.
+
+        raster surface SkPath draws are affected by volatile for some shadows.
+        GPU surface SkPath draws are affected by volatile for some shadows and concave geometries.
+
+        @param isVolatile  true if caller will alter SkPath after drawing
+    */
+    void setIsVolatile(bool isVolatile) {
+        fIsVolatile = isVolatile;
+    }
+
+    /** Tests if line between SkPoint pair is degenerate.
+        Line with no length or that moves a very short distance is degenerate; it is
+        treated as a point.
+
+        exact changes the equality test. If true, returns true only if p1 equals p2.
+        If false, returns true if p1 equals or nearly equals p2.
+
+        @param p1     line start point
+        @param p2     line end point
+        @param exact  if false, allow nearly equals
+        @return       true if line is degenerate; its length is effectively zero
+    */
+    static bool IsLineDegenerate(const SkPoint& p1, const SkPoint& p2, bool exact);
+
+    /** Tests if quad is degenerate.
+        Quad with no length or that moves a very short distance is degenerate; it is
+        treated as a point.
+
+        @param p1     quad start point
+        @param p2     quad control point
+        @param p3     quad end point
+        @param exact  if true, returns true only if p1, p2, and p3 are equal;
+                      if false, returns true if p1, p2, and p3 are equal or nearly equal
+        @return       true if quad is degenerate; its length is effectively zero
+    */
+    static bool IsQuadDegenerate(const SkPoint& p1, const SkPoint& p2,
+                                 const SkPoint& p3, bool exact);
+
+    /** Tests if cubic is degenerate.
+        Cubic with no length or that moves a very short distance is degenerate; it is
+        treated as a point.
+
+        @param p1     cubic start point
+        @param p2     cubic control point 1
+        @param p3     cubic control point 2
+        @param p4     cubic end point
+        @param exact  if true, returns true only if p1, p2, p3, and p4 are equal;
+                      if false, returns true if p1, p2, p3, and p4 are equal or nearly equal
+        @return       true if cubic is degenerate; its length is effectively zero
+    */
+    static bool IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
+                                  const SkPoint& p3, const SkPoint& p4, bool exact);
+
+    /** Returns true if SkPath contains only one line;
+        SkPath::Verb array has two entries: kMove_Verb, kLine_Verb.
+        If SkPath contains one line and line is not nullptr, line is set to
+        line start point and line end point.
+        Returns false if SkPath is not one line; line is unaltered.
+
+        @param line  storage for line. May be nullptr
+        @return      true if SkPath contains exactly one line
+    */
+    bool isLine(SkPoint line[2]) const;
+
+    /** Returns the number of points in SkPath.
+        SkPoint count is initially zero.
+
+        @return  SkPath SkPoint array length
+    */
+    int countPoints() const;
+
+    /** Returns SkPoint at index in SkPoint array. Valid range for index is
+        0 to countPoints() - 1.
+        Returns (0, 0) if index is out of range.
+
+        @param index  SkPoint array element selector
+        @return       SkPoint array value or (0, 0)
+    */
+    SkPoint getPoint(int index) const;
+
+    /** Returns number of points in SkPath. Up to max points are copied.
+        points may be nullptr; then, max must be zero.
+        If max is greater than number of points, excess points storage is unaltered.
+
+        @param points  storage for SkPath SkPoint array. May be nullptr
+        @param max     maximum to copy; must be greater than or equal to zero
+        @return        SkPath SkPoint array length
+    */
+    int getPoints(SkPoint points[], int max) const;
+
+    /** Returns the number of verbs: kMove_Verb, kLine_Verb, kQuad_Verb, kConic_Verb,
+        kCubic_Verb, and kClose_Verb; added to SkPath.
+
+        @return  length of verb array
+    */
+    int countVerbs() const;
+
+    /** Returns the number of verbs in the path. Up to max verbs are copied. The
+        verbs are copied as one byte per verb.
+
+        @param verbs  storage for verbs, may be nullptr
+        @param max    maximum number to copy into verbs
+        @return       the actual number of verbs in the path
+    */
+    int getVerbs(uint8_t verbs[], int max) const;
+
+    /** Exchanges the verb array, SkPoint array, weights, and SkPath::FillType with other.
+        Cached state is also exchanged. swap() internally exchanges pointers, so
+        it is lightweight and does not allocate memory.
+
+        swap() usage has largely been replaced by operator=(const SkPath& path).
+        SkPath do not copy their content on assignment until they are written to,
+        making assignment as efficient as swap().
+
+        @param other  SkPath exchanged by value
+    */
+    void swap(SkPath& other);
+
+    /** Returns minimum and maximum axes values of SkPoint array.
+        Returns (0, 0, 0, 0) if SkPath contains no points. Returned bounds width and height may
+        be larger or smaller than area affected when SkPath is drawn.
+
+        SkRect returned includes all SkPoint added to SkPath, including SkPoint associated with
+        kMove_Verb that define empty contours.
+
+        @return  bounds of all SkPoint in SkPoint array
+    */
+    const SkRect& getBounds() const {
+        return fPathRef->getBounds();
+    }
+
+    /** Updates internal bounds so that subsequent calls to getBounds() are instantaneous.
+        Unaltered copies of SkPath may also access cached bounds through getBounds().
+
+        For now, identical to calling getBounds() and ignoring the returned value.
+
+        Call to prepare SkPath subsequently drawn from multiple threads,
+        to avoid a race condition where each draw separately computes the bounds.
+    */
+    void updateBoundsCache() const {
+        // for now, just calling getBounds() is sufficient
+        this->getBounds();
+    }
+
+    /** Returns minimum and maximum axes values of the lines and curves in SkPath.
+        Returns (0, 0, 0, 0) if SkPath contains no points.
+        Returned bounds width and height may be larger or smaller than area affected
+        when SkPath is drawn.
+
+        Includes SkPoint associated with kMove_Verb that define empty
+        contours.
+
+        Behaves identically to getBounds() when SkPath contains
+        only lines. If SkPath contains curves, computed bounds includes
+        the maximum extent of the quad, conic, or cubic; is slower than getBounds();
+        and unlike getBounds(), does not cache the result.
+
+        @return  tight bounds of curves in SkPath
+    */
+    SkRect computeTightBounds() const;
+
+    /** Returns true if rect is contained by SkPath.
+        May return false when rect is contained by SkPath.
+
+        For now, only returns true if SkPath has one contour and is convex.
+        rect may share points and edges with SkPath and be contained.
+        Returns true if rect is empty, that is, it has zero width or height; and
+        the SkPoint or line described by rect is contained by SkPath.
+
+        @param rect  SkRect, line, or SkPoint checked for containment
+        @return      true if rect is contained
+    */
+    bool conservativelyContainsRect(const SkRect& rect) const;
+
+    /** Grows SkPath verb array and SkPoint array to contain extraPtCount additional SkPoint.
+        May improve performance and use less memory by
+        reducing the number and size of allocations when creating SkPath.
+
+        @param extraPtCount  number of additional SkPoint to allocate
+    */
+    void incReserve(int extraPtCount);
+
+    /** Shrinks SkPath verb array and SkPoint array storage to discard unused capacity.
+        May reduce the heap overhead for SkPath known to be fully constructed.
+    */
+    void shrinkToFit();
+
+    /** Adds beginning of contour at SkPoint (x, y).
+
+        @param x  x-axis value of contour start
+        @param y  y-axis value of contour start
+        @return   reference to SkPath
+    */
+    SkPath& moveTo(SkScalar x, SkScalar y);
+
+    /** Adds beginning of contour at SkPoint p.
+
+        @param p  contour start
+        @return   reference to SkPath
+    */
+    SkPath& moveTo(const SkPoint& p) {
+        return this->moveTo(p.fX, p.fY);
+    }
+
+    /** Adds beginning of contour relative to last point.
+        If SkPath is empty, starts contour at (dx, dy).
+        Otherwise, start contour at last point offset by (dx, dy).
+        Function name stands for "relative move to".
+
+        @param dx  offset from last point to contour start on x-axis
+        @param dy  offset from last point to contour start on y-axis
+        @return    reference to SkPath
+    */
+    SkPath& rMoveTo(SkScalar dx, SkScalar dy);
+
+    /** Adds line from last point to (x, y). If SkPath is empty, or last SkPath::Verb is
+        kClose_Verb, last point is set to (0, 0) before adding line.
+
+        lineTo() appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
+        lineTo() then appends kLine_Verb to verb array and (x, y) to SkPoint array.
+
+        @param x  end of added line on x-axis
+        @param y  end of added line on y-axis
+        @return   reference to SkPath
+    */
+    SkPath& lineTo(SkScalar x, SkScalar y);
+
+    /** Adds line from last point to SkPoint p. If SkPath is empty, or last SkPath::Verb is
+        kClose_Verb, last point is set to (0, 0) before adding line.
+
+        lineTo() first appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
+        lineTo() then appends kLine_Verb to verb array and SkPoint p to SkPoint array.
+
+        @param p  end SkPoint of added line
+        @return   reference to SkPath
+    */
+    SkPath& lineTo(const SkPoint& p) {
+        return this->lineTo(p.fX, p.fY);
+    }
+
+    /** Adds line from last point to vector (dx, dy). If SkPath is empty, or last SkPath::Verb is
+        kClose_Verb, last point is set to (0, 0) before adding line.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
+        then appends kLine_Verb to verb array and line end to SkPoint array.
+        Line end is last point plus vector (dx, dy).
+        Function name stands for "relative line to".
+
+        @param dx  offset from last point to line end on x-axis
+        @param dy  offset from last point to line end on y-axis
+        @return    reference to SkPath
+    */
+    SkPath& rLineTo(SkScalar dx, SkScalar dy);
+
+    /** Adds quad from last point towards (x1, y1), to (x2, y2).
+        If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
+        before adding quad.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
+        then appends kQuad_Verb to verb array; and (x1, y1), (x2, y2)
+        to SkPoint array.
+
+        @param x1  control SkPoint of quad on x-axis
+        @param y1  control SkPoint of quad on y-axis
+        @param x2  end SkPoint of quad on x-axis
+        @param y2  end SkPoint of quad on y-axis
+        @return    reference to SkPath
+    */
+    SkPath& quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2);
+
+    /** Adds quad from last point towards SkPoint p1, to SkPoint p2.
+        If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
+        before adding quad.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
+        then appends kQuad_Verb to verb array; and SkPoint p1, p2
+        to SkPoint array.
+
+        @param p1  control SkPoint of added quad
+        @param p2  end SkPoint of added quad
+        @return    reference to SkPath
+    */
+    SkPath& quadTo(const SkPoint& p1, const SkPoint& p2) {
+        return this->quadTo(p1.fX, p1.fY, p2.fX, p2.fY);
+    }
+
+    /** Adds quad from last point towards vector (dx1, dy1), to vector (dx2, dy2).
+        If SkPath is empty, or last SkPath::Verb
+        is kClose_Verb, last point is set to (0, 0) before adding quad.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
+        if needed; then appends kQuad_Verb to verb array; and appends quad
+        control and quad end to SkPoint array.
+        Quad control is last point plus vector (dx1, dy1).
+        Quad end is last point plus vector (dx2, dy2).
+        Function name stands for "relative quad to".
+
+        @param dx1  offset from last point to quad control on x-axis
+        @param dy1  offset from last point to quad control on y-axis
+        @param dx2  offset from last point to quad end on x-axis
+        @param dy2  offset from last point to quad end on y-axis
+        @return     reference to SkPath
+    */
+    SkPath& rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2);
+
+    /** Adds conic from last point towards (x1, y1), to (x2, y2), weighted by w.
+        If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
+        before adding conic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
+
+        If w is finite and not one, appends kConic_Verb to verb array;
+        and (x1, y1), (x2, y2) to SkPoint array; and w to conic weights.
+
+        If w is one, appends kQuad_Verb to verb array, and
+        (x1, y1), (x2, y2) to SkPoint array.
+
+        If w is not finite, appends kLine_Verb twice to verb array, and
+        (x1, y1), (x2, y2) to SkPoint array.
+
+        @param x1  control SkPoint of conic on x-axis
+        @param y1  control SkPoint of conic on y-axis
+        @param x2  end SkPoint of conic on x-axis
+        @param y2  end SkPoint of conic on y-axis
+        @param w   weight of added conic
+        @return    reference to SkPath
+    */
+    SkPath& conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+                    SkScalar w);
+
+    /** Adds conic from last point towards SkPoint p1, to SkPoint p2, weighted by w.
+        If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to (0, 0)
+        before adding conic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed.
+
+        If w is finite and not one, appends kConic_Verb to verb array;
+        and SkPoint p1, p2 to SkPoint array; and w to conic weights.
+
+        If w is one, appends kQuad_Verb to verb array, and SkPoint p1, p2
+        to SkPoint array.
+
+        If w is not finite, appends kLine_Verb twice to verb array, and
+        SkPoint p1, p2 to SkPoint array.
+
+        @param p1  control SkPoint of added conic
+        @param p2  end SkPoint of added conic
+        @param w   weight of added conic
+        @return    reference to SkPath
+    */
+    SkPath& conicTo(const SkPoint& p1, const SkPoint& p2, SkScalar w) {
+        return this->conicTo(p1.fX, p1.fY, p2.fX, p2.fY, w);
+    }
+
+    /** Adds conic from last point towards vector (dx1, dy1), to vector (dx2, dy2),
+        weighted by w. If SkPath is empty, or last SkPath::Verb
+        is kClose_Verb, last point is set to (0, 0) before adding conic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
+        if needed.
+
+        If w is finite and not one, next appends kConic_Verb to verb array,
+        and w is recorded as conic weight; otherwise, if w is one, appends
+        kQuad_Verb to verb array; or if w is not finite, appends kLine_Verb
+        twice to verb array.
+
+        In all cases appends SkPoint control and end to SkPoint array.
+        control is last point plus vector (dx1, dy1).
+        end is last point plus vector (dx2, dy2).
+
+        Function name stands for "relative conic to".
+
+        @param dx1  offset from last point to conic control on x-axis
+        @param dy1  offset from last point to conic control on y-axis
+        @param dx2  offset from last point to conic end on x-axis
+        @param dy2  offset from last point to conic end on y-axis
+        @param w    weight of added conic
+        @return     reference to SkPath
+    */
+    SkPath& rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
+                     SkScalar w);
+
+    /** Adds cubic from last point towards (x1, y1), then towards (x2, y2), ending at
+        (x3, y3). If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
+        (0, 0) before adding cubic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
+        then appends kCubic_Verb to verb array; and (x1, y1), (x2, y2), (x3, y3)
+        to SkPoint array.
+
+        @param x1  first control SkPoint of cubic on x-axis
+        @param y1  first control SkPoint of cubic on y-axis
+        @param x2  second control SkPoint of cubic on x-axis
+        @param y2  second control SkPoint of cubic on y-axis
+        @param x3  end SkPoint of cubic on x-axis
+        @param y3  end SkPoint of cubic on y-axis
+        @return    reference to SkPath
+    */
+    SkPath& cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
+                    SkScalar x3, SkScalar y3);
+
+    /** Adds cubic from last point towards SkPoint p1, then towards SkPoint p2, ending at
+        SkPoint p3. If SkPath is empty, or last SkPath::Verb is kClose_Verb, last point is set to
+        (0, 0) before adding cubic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array, if needed;
+        then appends kCubic_Verb to verb array; and SkPoint p1, p2, p3
+        to SkPoint array.
+
+        @param p1  first control SkPoint of cubic
+        @param p2  second control SkPoint of cubic
+        @param p3  end SkPoint of cubic
+        @return    reference to SkPath
+    */
+    SkPath& cubicTo(const SkPoint& p1, const SkPoint& p2, const SkPoint& p3) {
+        return this->cubicTo(p1.fX, p1.fY, p2.fX, p2.fY, p3.fX, p3.fY);
+    }
+
+    /** Adds cubic from last point towards vector (dx1, dy1), then towards
+        vector (dx2, dy2), to vector (dx3, dy3).
+        If SkPath is empty, or last SkPath::Verb
+        is kClose_Verb, last point is set to (0, 0) before adding cubic.
+
+        Appends kMove_Verb to verb array and (0, 0) to SkPoint array,
+        if needed; then appends kCubic_Verb to verb array; and appends cubic
+        control and cubic end to SkPoint array.
+        Cubic control is last point plus vector (dx1, dy1).
+        Cubic end is last point plus vector (dx2, dy2).
+        Function name stands for "relative cubic to".
+
+        @param dx1  offset from last point to first cubic control on x-axis
+        @param dy1  offset from last point to first cubic control on y-axis
+        @param dx2  offset from last point to second cubic control on x-axis
+        @param dy2  offset from last point to second cubic control on y-axis
+        @param dx3  offset from last point to cubic end on x-axis
+        @param dy3  offset from last point to cubic end on y-axis
+        @return    reference to SkPath
+    */
+    SkPath& rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2,
+                     SkScalar dx3, SkScalar dy3);
+
+    /** Appends arc to SkPath. Arc added is part of ellipse
+        bounded by oval, from startAngle through sweepAngle. Both startAngle and
+        sweepAngle are measured in degrees, where zero degrees is aligned with the
+        positive x-axis, and positive sweeps extends arc clockwise.
+
+        arcTo() adds line connecting SkPath last SkPoint to initial arc SkPoint if forceMoveTo
+        is false and SkPath is not empty. Otherwise, added contour begins with first point
+        of arc. Angles greater than -360 and less than 360 are treated modulo 360.
+
+        @param oval         bounds of ellipse containing arc
+        @param startAngle   starting angle of arc in degrees
+        @param sweepAngle   sweep, in degrees. Positive is clockwise; treated modulo 360
+        @param forceMoveTo  true to start a new contour with arc
+        @return             reference to SkPath
+    */
+    SkPath& arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo);
+
+    /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
+        weighted to describe part of circle. Arc is contained by tangent from
+        last SkPath point to (x1, y1), and tangent from (x1, y1) to (x2, y2). Arc
+        is part of circle sized to radius, positioned so it touches both tangent lines.
+
+        If last Path Point does not start Arc, arcTo appends connecting Line to Path.
+        The length of Vector from (x1, y1) to (x2, y2) does not affect Arc.
+
+        Arc sweep is always less than 180 degrees. If radius is zero, or if
+        tangents are nearly parallel, arcTo appends Line from last Path Point to (x1, y1).
+
+        arcTo appends at most one Line and one conic.
+        arcTo implements the functionality of PostScript arct and HTML Canvas arcTo.
+
+        @param x1      x-axis value common to pair of tangents
+        @param y1      y-axis value common to pair of tangents
+        @param x2      x-axis value end of second tangent
+        @param y2      y-axis value end of second tangent
+        @param radius  distance from arc to circle center
+        @return        reference to SkPath
+    */
+    SkPath& arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius);
+
+    /** Appends arc to SkPath, after appending line if needed. Arc is implemented by conic
+        weighted to describe part of circle. Arc is contained by tangent from
+        last SkPath point to p1, and tangent from p1 to p2. Arc
+        is part of circle sized to radius, positioned so it touches both tangent lines.
+
+        If last SkPath SkPoint does not start arc, arcTo() appends connecting line to SkPath.
+        The length of vector from p1 to p2 does not affect arc.
+
+        Arc sweep is always less than 180 degrees. If radius is zero, or if
+        tangents are nearly parallel, arcTo() appends line from last SkPath SkPoint to p1.
+
+        arcTo() appends at most one line and one conic.
+        arcTo() implements the functionality of PostScript arct and HTML Canvas arcTo.
+
+        @param p1      SkPoint common to pair of tangents
+        @param p2      end of second tangent
+        @param radius  distance from arc to circle center
+        @return        reference to SkPath
+    */
+    SkPath& arcTo(const SkPoint p1, const SkPoint p2, SkScalar radius) {
+        return this->arcTo(p1.fX, p1.fY, p2.fX, p2.fY, radius);
+    }
+
+    /** \enum SkPath::ArcSize
+        Four oval parts with radii (rx, ry) start at last SkPath SkPoint and ends at (x, y).
+        ArcSize and Direction select one of the four oval parts.
+    */
+    enum ArcSize {
+        kSmall_ArcSize, //!< smaller of arc pair
+        kLarge_ArcSize, //!< larger of arc pair
+    };
+
+    /** Appends arc to SkPath. Arc is implemented by one or more conics weighted to
+        describe part of oval with radii (rx, ry) rotated by xAxisRotate degrees. Arc
+        curves from last SkPath SkPoint to (x, y), choosing one of four possible routes:
+        clockwise or counterclockwise, and smaller or larger.
+
+        Arc sweep is always less than 360 degrees. arcTo() appends line to (x, y) if
+        either radii are zero, or if last SkPath SkPoint equals (x, y). arcTo() scales radii
+        (rx, ry) to fit last SkPath SkPoint and (x, y) if both are greater than zero but
+        too small.
+
+        arcTo() appends up to four conic curves.
+        arcTo() implements the functionality of SVG arc, although SVG sweep-flag value
+        is opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise,
+        while kCW_Direction cast to int is zero.
+
+        @param rx           radius on x-axis before x-axis rotation
+        @param ry           radius on y-axis before x-axis rotation
+        @param xAxisRotate  x-axis rotation in degrees; positive values are clockwise
+        @param largeArc     chooses smaller or larger arc
+        @param sweep        chooses clockwise or counterclockwise arc
+        @param x            end of arc
+        @param y            end of arc
+        @return             reference to SkPath
+    */
+    SkPath& arcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
+                  Direction sweep, SkScalar x, SkScalar y);
+
+    /** Appends arc to SkPath. Arc is implemented by one or more conic weighted to describe
+        part of oval with radii (r.fX, r.fY) rotated by xAxisRotate degrees. Arc curves
+        from last SkPath SkPoint to (xy.fX, xy.fY), choosing one of four possible routes:
+        clockwise or counterclockwise,
+        and smaller or larger.
+
+        Arc sweep is always less than 360 degrees. arcTo() appends line to xy if either
+        radii are zero, or if last SkPath SkPoint equals (xy.fX, xy.fY). arcTo() scales radii r to
+        fit last SkPath SkPoint and xy if both are greater than zero but too small to describe
+        an arc.
+
+        arcTo() appends up to four conic curves.
+        arcTo() implements the functionality of SVG arc, although SVG sweep-flag value is
+        opposite the integer value of sweep; SVG sweep-flag uses 1 for clockwise, while
+        kCW_Direction cast to int is zero.
+
+        @param r            radii on axes before x-axis rotation
+        @param xAxisRotate  x-axis rotation in degrees; positive values are clockwise
+        @param largeArc     chooses smaller or larger arc
+        @param sweep        chooses clockwise or counterclockwise arc
+        @param xy           end of arc
+        @return             reference to SkPath
+    */
+    SkPath& arcTo(const SkPoint r, SkScalar xAxisRotate, ArcSize largeArc, Direction sweep,
+               const SkPoint xy) {
+        return this->arcTo(r.fX, r.fY, xAxisRotate, largeArc, sweep, xy.fX, xy.fY);
+    }
+
+    /** Appends arc to SkPath, relative to last SkPath SkPoint. Arc is implemented by one or
+        more conic, weighted to describe part of oval with radii (rx, ry) rotated by
+        xAxisRotate degrees. Arc curves from last SkPath SkPoint to relative end SkPoint:
+        (dx, dy), choosing one of four possible routes: clockwise or
+        counterclockwise, and smaller or larger. If SkPath is empty, the start arc SkPoint
+        is (0, 0).
+
+        Arc sweep is always less than 360 degrees. arcTo() appends line to end SkPoint
+        if either radii are zero, or if last SkPath SkPoint equals end SkPoint.
+        arcTo() scales radii (rx, ry) to fit last SkPath SkPoint and end SkPoint if both are
+        greater than zero but too small to describe an arc.
+
+        arcTo() appends up to four conic curves.
+        arcTo() implements the functionality of svg arc, although SVG "sweep-flag" value is
+        opposite the integer value of sweep; SVG "sweep-flag" uses 1 for clockwise, while
+        kCW_Direction cast to int is zero.
+
+        @param rx           radius before x-axis rotation
+        @param ry           radius before x-axis rotation
+        @param xAxisRotate  x-axis rotation in degrees; positive values are clockwise
+        @param largeArc     chooses smaller or larger arc
+        @param sweep        chooses clockwise or counterclockwise arc
+        @param dx           x-axis offset end of arc from last SkPath SkPoint
+        @param dy           y-axis offset end of arc from last SkPath SkPoint
+        @return             reference to SkPath
+    */
+    SkPath& rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc,
+                   Direction sweep, SkScalar dx, SkScalar dy);
+
+    /** Appends kClose_Verb to SkPath. A closed contour connects the first and last SkPoint
+        with line, forming a continuous loop. Open and closed contour draw the same
+        with SkPaint::kFill_Style. With SkPaint::kStroke_Style, open contour draws
+        SkPaint::Cap at contour start and end; closed contour draws
+        SkPaint::Join at contour start and end.
+
+        close() has no effect if SkPath is empty or last SkPath SkPath::Verb is kClose_Verb.
+
+        @return  reference to SkPath
+    */
+    SkPath& close();
+
+    /** Returns true if fill is inverted and SkPath with fill represents area outside
+        of its geometric bounds.
+
+        @param fill  one of: kWinding_FillType, kEvenOdd_FillType,
+                     kInverseWinding_FillType, kInverseEvenOdd_FillType
+        @return      true if SkPath fills outside its bounds
+    */
+    static bool IsInverseFillType(FillType fill) {
+        static_assert(0 == kWinding_FillType, "fill_type_mismatch");
+        static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch");
+        static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch");
+        static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch");
+        return (fill & 2) != 0;
+    }
+
+    /** Returns equivalent SkPath::FillType representing SkPath fill inside its bounds.
+        .
+
+        @param fill  one of: kWinding_FillType, kEvenOdd_FillType,
+                     kInverseWinding_FillType, kInverseEvenOdd_FillType
+        @return      fill, or kWinding_FillType or kEvenOdd_FillType if fill is inverted
+    */
+    static FillType ConvertToNonInverseFillType(FillType fill) {
+        static_assert(0 == kWinding_FillType, "fill_type_mismatch");
+        static_assert(1 == kEvenOdd_FillType, "fill_type_mismatch");
+        static_assert(2 == kInverseWinding_FillType, "fill_type_mismatch");
+        static_assert(3 == kInverseEvenOdd_FillType, "fill_type_mismatch");
+        return (FillType)(fill & 1);
+    }
+
+    /** Approximates conic with quad array. Conic is constructed from start SkPoint p0,
+        control SkPoint p1, end SkPoint p2, and weight w.
+        Quad array is stored in pts; this storage is supplied by caller.
+        Maximum quad count is 2 to the pow2.
+        Every third point in array shares last SkPoint of previous quad and first SkPoint of
+        next quad. Maximum pts storage size is given by:
+        (1 + 2 * (1 << pow2)) * sizeof(SkPoint).
+
+        Returns quad count used the approximation, which may be smaller
+        than the number requested.
+
+        conic weight determines the amount of influence conic control point has on the curve.
+        w less than one represents an elliptical section. w greater than one represents
+        a hyperbolic section. w equal to one represents a parabolic section.
+
+        Two quad curves are sufficient to approximate an elliptical conic with a sweep
+        of up to 90 degrees; in this case, set pow2 to one.
+
+        @param p0    conic start SkPoint
+        @param p1    conic control SkPoint
+        @param p2    conic end SkPoint
+        @param w     conic weight
+        @param pts   storage for quad array
+        @param pow2  quad count, as power of two, normally 0 to 5 (1 to 32 quad curves)
+        @return      number of quad curves written to pts
+    */
+    static int ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
+                                   SkScalar w, SkPoint pts[], int pow2);
+
+    /** Returns true if SkPath is equivalent to SkRect when filled.
+        If false: rect, isClosed, and direction are unchanged.
+        If true: rect, isClosed, and direction are written to if not nullptr.
+
+        rect may be smaller than the SkPath bounds. SkPath bounds may include kMove_Verb points
+        that do not alter the area drawn by the returned rect.
+
+        @param rect       storage for bounds of SkRect; may be nullptr
+        @param isClosed   storage set to true if SkPath is closed; may be nullptr
+        @param direction  storage set to SkRect direction; may be nullptr
+        @return           true if SkPath contains SkRect
+    */
+    bool isRect(SkRect* rect, bool* isClosed = nullptr, Direction* direction = nullptr) const;
+
+    /** Returns true if SkPath is equivalent to nested SkRect pair when filled.
+        If false, rect and dirs are unchanged.
+        If true, rect and dirs are written to if not nullptr:
+        setting rect[0] to outer SkRect, and rect[1] to inner SkRect;
+        setting dirs[0] to SkPath::Direction of outer SkRect, and dirs[1] to SkPath::Direction of
+        inner SkRect.
+
+        @param rect  storage for SkRect pair; may be nullptr
+        @param dirs  storage for SkPath::Direction pair; may be nullptr
+        @return      true if SkPath contains nested SkRect pair
+    */
+    bool isNestedFillRects(SkRect rect[2], Direction dirs[2] = nullptr) const;
+
+    /** Adds SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb,
+        starting with top-left corner of SkRect; followed by top-right, bottom-right,
+        and bottom-left if dir is kCW_Direction; or followed by bottom-left,
+        bottom-right, and top-right if dir is kCCW_Direction.
+
+        @param rect  SkRect to add as a closed contour
+        @param dir   SkPath::Direction to wind added contour
+        @return      reference to SkPath
+    */
+    SkPath& addRect(const SkRect& rect, Direction dir = kCW_Direction);
+
+    /** Adds SkRect to SkPath, appending kMove_Verb, three kLine_Verb, and kClose_Verb.
+        If dir is kCW_Direction, SkRect corners are added clockwise; if dir is
+        kCCW_Direction, SkRect corners are added counterclockwise.
+        start determines the first corner added.
+
+        @param rect   SkRect to add as a closed contour
+        @param dir    SkPath::Direction to wind added contour
+        @param start  initial corner of SkRect to add
+        @return       reference to SkPath
+    */
+    SkPath& addRect(const SkRect& rect, Direction dir, unsigned start);
+
+    /** Adds SkRect (left, top, right, bottom) to SkPath,
+        appending kMove_Verb, three kLine_Verb, and kClose_Verb,
+        starting with top-left corner of SkRect; followed by top-right, bottom-right,
+        and bottom-left if dir is kCW_Direction; or followed by bottom-left,
+        bottom-right, and top-right if dir is kCCW_Direction.
+
+        @param left    smaller x-axis value of SkRect
+        @param top     smaller y-axis value of SkRect
+        @param right   larger x-axis value of SkRect
+        @param bottom  larger y-axis value of SkRect
+        @param dir     SkPath::Direction to wind added contour
+        @return        reference to SkPath
+    */
+    SkPath& addRect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom,
+                    Direction dir = kCW_Direction);
+
+    /** Adds oval to path, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
+        Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
+        and half oval height. Oval begins at (oval.fRight, oval.centerY()) and continues
+        clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
+
+        @param oval  bounds of ellipse added
+        @param dir   SkPath::Direction to wind ellipse
+        @return      reference to SkPath
+    */
+    SkPath& addOval(const SkRect& oval, Direction dir = kCW_Direction);
+
+    /** Adds oval to SkPath, appending kMove_Verb, four kConic_Verb, and kClose_Verb.
+        Oval is upright ellipse bounded by SkRect oval with radii equal to half oval width
+        and half oval height. Oval begins at start and continues
+        clockwise if dir is kCW_Direction, counterclockwise if dir is kCCW_Direction.
+
+        @param oval   bounds of ellipse added
+        @param dir    SkPath::Direction to wind ellipse
+        @param start  index of initial point of ellipse
+        @return       reference to SkPath
+    */
+    SkPath& addOval(const SkRect& oval, Direction dir, unsigned start);
+
+    /** Adds circle centered at (x, y) of size radius to SkPath, appending kMove_Verb,
+        four kConic_Verb, and kClose_Verb. Circle begins at: (x + radius, y), continuing
+        clockwise if dir is kCW_Direction, and counterclockwise if dir is kCCW_Direction.
+
+        Has no effect if radius is zero or negative.
+
+        @param x       center of circle
+        @param y       center of circle
+        @param radius  distance from center to edge
+        @param dir     SkPath::Direction to wind circle
+        @return        reference to SkPath
+    */
+    SkPath& addCircle(SkScalar x, SkScalar y, SkScalar radius,
+                      Direction dir = kCW_Direction);
+
+    /** Appends arc to SkPath, as the start of new contour. Arc added is part of ellipse
+        bounded by oval, from startAngle through sweepAngle. Both startAngle and
+        sweepAngle are measured in degrees, where zero degrees is aligned with the
+        positive x-axis, and positive sweeps extends arc clockwise.
+
+        If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
+        zero, append oval instead of arc. Otherwise, sweepAngle values are treated
+        modulo 360, and arc may or may not draw depending on numeric rounding.
+
+        @param oval        bounds of ellipse containing arc
+        @param startAngle  starting angle of arc in degrees
+        @param sweepAngle  sweep, in degrees. Positive is clockwise; treated modulo 360
+        @return            reference to SkPath
+    */
+    SkPath& addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle);
+
+    /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
+        equal to rect; each corner is 90 degrees of an ellipse with radii (rx, ry). If
+        dir is kCW_Direction, SkRRect starts at top-left of the lower-left corner and
+        winds clockwise. If dir is kCCW_Direction, SkRRect starts at the bottom-left
+        of the upper-left corner and winds counterclockwise.
+
+        If either rx or ry is too large, rx and ry are scaled uniformly until the
+        corners fit. If rx or ry is less than or equal to zero, addRoundRect() appends
+        SkRect rect to SkPath.
+
+        After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
+
+        @param rect  bounds of SkRRect
+        @param rx    x-axis radius of rounded corners on the SkRRect
+        @param ry    y-axis radius of rounded corners on the SkRRect
+        @param dir   SkPath::Direction to wind SkRRect
+        @return      reference to SkPath
+    */
+    SkPath& addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
+                         Direction dir = kCW_Direction);
+
+    /** Appends SkRRect to SkPath, creating a new closed contour. SkRRect has bounds
+        equal to rect; each corner is 90 degrees of an ellipse with radii from the
+        array.
+
+        @param rect   bounds of SkRRect
+        @param radii  array of 8 SkScalar values, a radius pair for each corner
+        @param dir    SkPath::Direction to wind SkRRect
+        @return       reference to SkPath
+    */
+    SkPath& addRoundRect(const SkRect& rect, const SkScalar radii[],
+                         Direction dir = kCW_Direction);
+
+    /** Adds rrect to SkPath, creating a new closed contour. If
+        dir is kCW_Direction, rrect starts at top-left of the lower-left corner and
+        winds clockwise. If dir is kCCW_Direction, rrect starts at the bottom-left
+        of the upper-left corner and winds counterclockwise.
+
+        After appending, SkPath may be empty, or may contain: SkRect, oval, or SkRRect.
+
+        @param rrect  bounds and radii of rounded rectangle
+        @param dir    SkPath::Direction to wind SkRRect
+        @return       reference to SkPath
+    */
+    SkPath& addRRect(const SkRRect& rrect, Direction dir = kCW_Direction);
+
+    /** Adds rrect to SkPath, creating a new closed contour. If dir is kCW_Direction, rrect
+        winds clockwise; if dir is kCCW_Direction, rrect winds counterclockwise.
+        start determines the first point of rrect to add.
+
+        @param rrect  bounds and radii of rounded rectangle
+        @param dir    SkPath::Direction to wind SkRRect
+        @param start  index of initial point of SkRRect
+        @return       reference to SkPath
+    */
+    SkPath& addRRect(const SkRRect& rrect, Direction dir, unsigned start);
+
+    /** Adds contour created from line array, adding (count - 1) line segments.
+        Contour added starts at pts[0], then adds a line for every additional SkPoint
+        in pts array. If close is true, appends kClose_Verb to SkPath, connecting
+        pts[count - 1] and pts[0].
+
+        If count is zero, append kMove_Verb to path.
+        Has no effect if count is less than one.
+
+        @param pts    array of line sharing end and start SkPoint
+        @param count  length of SkPoint array
+        @param close  true to add line connecting contour end and start
+        @return       reference to SkPath
+    */
+    SkPath& addPoly(const SkPoint pts[], int count, bool close);
+
+    /** Adds contour created from list. Contour added starts at list[0], then adds a line
+        for every additional SkPoint in list. If close is true, appends kClose_Verb to SkPath,
+        connecting last and first SkPoint in list.
+
+        If list is empty, append kMove_Verb to path.
+
+        @param list   array of SkPoint
+        @param close  true to add line connecting contour end and start
+        @return       reference to SkPath
+    */
+    SkPath& addPoly(const std::initializer_list<SkPoint>& list, bool close) {
+        return this->addPoly(list.begin(), SkToInt(list.size()), close);
+    }
+
+    /** \enum SkPath::AddPathMode
+        AddPathMode chooses how addPath() appends. Adding one SkPath to another can extend
+        the last contour or start a new contour.
+    */
+    enum AddPathMode {
+        kAppend_AddPathMode, //!< appended to destination unaltered
+        kExtend_AddPathMode, //!< add line if prior contour is not closed
+    };
+
+    /** Appends src to SkPath, offset by (dx, dy).
+
+        If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
+        added unaltered. If mode is kExtend_AddPathMode, add line before appending
+        verbs, SkPoint, and conic weights.
+
+        @param src   SkPath verbs, SkPoint, and conic weights to add
+        @param dx    offset added to src SkPoint array x-axis coordinates
+        @param dy    offset added to src SkPoint array y-axis coordinates
+        @param mode  kAppend_AddPathMode or kExtend_AddPathMode
+        @return      reference to SkPath
+    */
+    SkPath& addPath(const SkPath& src, SkScalar dx, SkScalar dy,
+                    AddPathMode mode = kAppend_AddPathMode);
+
+    /** Appends src to SkPath.
+
+        If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
+        added unaltered. If mode is kExtend_AddPathMode, add line before appending
+        verbs, SkPoint, and conic weights.
+
+        @param src   SkPath verbs, SkPoint, and conic weights to add
+        @param mode  kAppend_AddPathMode or kExtend_AddPathMode
+        @return      reference to SkPath
+    */
+    SkPath& addPath(const SkPath& src, AddPathMode mode = kAppend_AddPathMode) {
+        SkMatrix m;
+        m.reset();
+        return this->addPath(src, m, mode);
+    }
+
+    /** Appends src to SkPath, transformed by matrix. Transformed curves may have different
+        verbs, SkPoint, and conic weights.
+
+        If mode is kAppend_AddPathMode, src verb array, SkPoint array, and conic weights are
+        added unaltered. If mode is kExtend_AddPathMode, add line before appending
+        verbs, SkPoint, and conic weights.
+
+        @param src     SkPath verbs, SkPoint, and conic weights to add
+        @param matrix  transform applied to src
+        @param mode    kAppend_AddPathMode or kExtend_AddPathMode
+        @return        reference to SkPath
+    */
+    SkPath& addPath(const SkPath& src, const SkMatrix& matrix,
+                    AddPathMode mode = kAppend_AddPathMode);
+
+    /** Appends src to SkPath, from back to front.
+        Reversed src always appends a new contour to SkPath.
+
+        @param src  SkPath verbs, SkPoint, and conic weights to add
+        @return     reference to SkPath
+    */
+    SkPath& reverseAddPath(const SkPath& src);
+
+    /** Offsets SkPoint array by (dx, dy). Offset SkPath replaces dst.
+        If dst is nullptr, SkPath is replaced by offset data.
+
+        @param dx   offset added to SkPoint array x-axis coordinates
+        @param dy   offset added to SkPoint array y-axis coordinates
+        @param dst  overwritten, translated copy of SkPath; may be nullptr
+    */
+    void offset(SkScalar dx, SkScalar dy, SkPath* dst) const;
+
+    /** Offsets SkPoint array by (dx, dy). SkPath is replaced by offset data.
+
+        @param dx  offset added to SkPoint array x-axis coordinates
+        @param dy  offset added to SkPoint array y-axis coordinates
+    */
+    void offset(SkScalar dx, SkScalar dy) {
+        this->offset(dx, dy, this);
+    }
+
+    /** Transforms verb array, SkPoint array, and weight by matrix.
+        transform may change verbs and increase their number.
+        Transformed SkPath replaces dst; if dst is nullptr, original data
+        is replaced.
+
+        @param matrix  SkMatrix to apply to SkPath
+        @param dst     overwritten, transformed copy of SkPath; may be nullptr
+    */
+    void transform(const SkMatrix& matrix, SkPath* dst) const;
+
+    /** Transforms verb array, SkPoint array, and weight by matrix.
+        transform may change verbs and increase their number.
+        SkPath is replaced by transformed data.
+
+        @param matrix  SkMatrix to apply to SkPath
+    */
+    void transform(const SkMatrix& matrix) {
+        this->transform(matrix, this);
+    }
+
+    /** Returns last point on SkPath in lastPt. Returns false if SkPoint array is empty,
+        storing (0, 0) if lastPt is not nullptr.
+
+        @param lastPt  storage for final SkPoint in SkPoint array; may be nullptr
+        @return        true if SkPoint array contains one or more SkPoint
+    */
+    bool getLastPt(SkPoint* lastPt) const;
+
+    /** Sets last point to (x, y). If SkPoint array is empty, append kMove_Verb to
+        verb array and append (x, y) to SkPoint array.
+
+        @param x  set x-axis value of last point
+        @param y  set y-axis value of last point
+    */
+    void setLastPt(SkScalar x, SkScalar y);
+
+    /** Sets the last point on the path. If SkPoint array is empty, append kMove_Verb to
+        verb array and append p to SkPoint array.
+
+        @param p  set value of last point
+    */
+    void setLastPt(const SkPoint& p) {
+        this->setLastPt(p.fX, p.fY);
+    }
+
+    /** \enum SkPath::SegmentMask
+        SegmentMask constants correspond to each drawing Verb type in SkPath; for
+        instance, if SkPath only contains lines, only the kLine_SegmentMask bit is set.
+    */
+    enum SegmentMask {
+        kLine_SegmentMask  = 1 << 0, //!< contains one or more lines
+        kQuad_SegmentMask  = 1 << 1, //!< contains one or more quads
+        kConic_SegmentMask = 1 << 2, //!< contains one or more conics
+        kCubic_SegmentMask = 1 << 3, //!< contains one or more cubics
+    };
+
+    /** Returns a mask, where each set bit corresponds to a SegmentMask constant
+        if SkPath contains one or more verbs of that type.
+        Returns zero if SkPath contains no lines, or curves: quads, conics, or cubics.
+
+        getSegmentMasks() returns a cached result; it is very fast.
+
+        @return  SegmentMask bits or zero
+    */
+    uint32_t getSegmentMasks() const { return fPathRef->getSegmentMasks(); }
+
+    /** \enum SkPath::Verb
+        Verb instructs SkPath how to interpret one or more SkPoint and optional conic weight;
+        manage contour, and terminate SkPath.
+    */
+    enum Verb {
+        kMove_Verb,  //!< starts new contour at next SkPoint
+        kLine_Verb,  //!< adds line from last point to next SkPoint
+        kQuad_Verb,  //!< adds quad from last point
+        kConic_Verb, //!< adds conic from last point
+        kCubic_Verb, //!< adds cubic from last point
+        kClose_Verb, //!< closes contour
+        kDone_Verb,  //!< terminates SkPath
+    };
+
+    /** \class SkPath::Iter
+        Iterates through verb array, and associated SkPoint array and conic weight.
+        Provides options to treat open contours as closed, and to ignore
+        degenerate data.
+    */
+    class SK_API Iter {
+    public:
+
+        /** Initializes SkPath::Iter with an empty SkPath. next() on SkPath::Iter returns
+            kDone_Verb.
+            Call setPath to initialize SkPath::Iter at a later time.
+
+            @return  SkPath::Iter of empty SkPath
+        */
+        Iter();
+
+        /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
+            path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
+            open contour. path is not altered.
+
+            @param path        SkPath to iterate
+            @param forceClose  true if open contours generate kClose_Verb
+            @return            SkPath::Iter of path
+        */
+        Iter(const SkPath& path, bool forceClose);
+
+        /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
+            path. If forceClose is true, SkPath::Iter will add kLine_Verb and kClose_Verb after each
+            open contour. path is not altered.
+
+            @param path        SkPath to iterate
+            @param forceClose  true if open contours generate kClose_Verb
+        */
+        void setPath(const SkPath& path, bool forceClose);
+
+        /** Returns next SkPath::Verb in verb array, and advances SkPath::Iter.
+            When verb array is exhausted, returns kDone_Verb.
+
+            Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
+
+            If doConsumeDegenerates is true, skip consecutive kMove_Verb entries, returning
+            only the last in the series; and skip very small lines, quads, and conics; and
+            skip kClose_Verb following kMove_Verb.
+            if doConsumeDegenerates is true and exact is true, only skip lines, quads, and
+            conics with zero lengths.
+
+            @param pts                   storage for SkPoint data describing returned SkPath::Verb
+            @param doConsumeDegenerates  if true, skip degenerate verbs
+            @param exact                 skip zero length curves
+            @return                      next SkPath::Verb from verb array
+        */
+        Verb next(SkPoint pts[4], bool doConsumeDegenerates = true, bool exact = false) {
+            if (doConsumeDegenerates) {
+                this->consumeDegenerateSegments(exact);
+            }
+            return this->doNext(pts);
+        }
+
+        /** Returns conic weight if next() returned kConic_Verb.
+
+            If next() has not been called, or next() did not return kConic_Verb,
+            result is undefined.
+
+            @return  conic weight for conic SkPoint returned by next()
+        */
+        SkScalar conicWeight() const { return *fConicWeights; }
+
+        /** Returns true if last kLine_Verb returned by next() was generated
+            by kClose_Verb. When true, the end point returned by next() is
+            also the start point of contour.
+
+            If next() has not been called, or next() did not return kLine_Verb,
+            result is undefined.
+
+            @return  true if last kLine_Verb was generated by kClose_Verb
+        */
+        bool isCloseLine() const { return SkToBool(fCloseLine); }
+
+        /** Returns true if subsequent calls to next() return kClose_Verb before returning
+            kMove_Verb. if true, contour SkPath::Iter is processing may end with kClose_Verb, or
+            SkPath::Iter may have been initialized with force close set to true.
+
+            @return  true if contour is closed
+        */
+        bool isClosedContour() const;
+
+    private:
+        const SkPoint*  fPts;
+        const uint8_t*  fVerbs;
+        const uint8_t*  fVerbStop;
+        const SkScalar* fConicWeights;
+        SkPoint         fMoveTo;
+        SkPoint         fLastPt;
+        bool            fForceClose;
+        bool            fNeedClose;
+        bool            fCloseLine;
+        enum SegmentState : uint8_t {
+            /** The current contour is empty. Starting processing or have just closed a contour. */
+            kEmptyContour_SegmentState,
+            /** Have seen a move, but nothing else. */
+            kAfterMove_SegmentState,
+            /** Have seen a primitive but not yet closed the path. Also the initial state. */
+            kAfterPrimitive_SegmentState
+        };
+        SegmentState    fSegmentState;
+
+        inline const SkPoint& cons_moveTo();
+        Verb autoClose(SkPoint pts[2]);
+        void consumeDegenerateSegments(bool exact);
+        Verb doNext(SkPoint pts[4]);
+
+    };
+
+    /** \class SkPath::RawIter
+        Iterates through verb array, and associated SkPoint array and conic weight.
+        verb array, SkPoint array, and conic weight are returned unaltered.
+    */
+    class SK_API RawIter {
+    public:
+
+        /** Initializes RawIter with an empty SkPath. next() on RawIter returns kDone_Verb.
+            Call setPath to initialize SkPath::Iter at a later time.
+
+            @return  RawIter of empty SkPath
+        */
+        RawIter() {}
+
+        /** Sets RawIter to return elements of verb array, SkPoint array, and conic weight in path.
+
+            @param path  SkPath to iterate
+            @return      RawIter of path
+        */
+        RawIter(const SkPath& path) {
+            setPath(path);
+        }
+
+        /** Sets SkPath::Iter to return elements of verb array, SkPoint array, and conic weight in
+            path.
+
+            @param path  SkPath to iterate
+        */
+        void setPath(const SkPath& path) {
+            fRawIter.setPathRef(*path.fPathRef.get());
+        }
+
+        /** Returns next SkPath::Verb in verb array, and advances RawIter.
+            When verb array is exhausted, returns kDone_Verb.
+            Zero to four SkPoint are stored in pts, depending on the returned SkPath::Verb.
+
+            @param pts  storage for SkPoint data describing returned SkPath::Verb
+            @return     next SkPath::Verb from verb array
+        */
+        Verb next(SkPoint pts[4]) {
+            return (Verb) fRawIter.next(pts);
+        }
+
+        /** Returns next SkPath::Verb, but does not advance RawIter.
+
+            @return  next SkPath::Verb from verb array
+        */
+        Verb peek() const {
+            return (Verb) fRawIter.peek();
+        }
+
+        /** Returns conic weight if next() returned kConic_Verb.
+
+            If next() has not been called, or next() did not return kConic_Verb,
+            result is undefined.
+
+            @return  conic weight for conic SkPoint returned by next()
+        */
+        SkScalar conicWeight() const {
+            return fRawIter.conicWeight();
+        }
+
+    private:
+        SkPathRef::Iter fRawIter;
+        friend class SkPath;
+
+    };
+
+    /** Returns true if the point (x, y) is contained by SkPath, taking into
+        account FillType.
+
+        @param x  x-axis value of containment test
+        @param y  y-axis value of containment test
+        @return   true if SkPoint is in SkPath
+    */
+    bool contains(SkScalar x, SkScalar y) const;
+
+    /** Writes text representation of SkPath to stream. If stream is nullptr, writes to
+        standard output. Set forceClose to true to get edges used to fill SkPath.
+        Set dumpAsHex true to generate exact binary representations
+        of floating point numbers used in SkPoint array and conic weights.
+
+        @param stream      writable SkWStream receiving SkPath text representation; may be nullptr
+        @param forceClose  true if missing kClose_Verb is output
+        @param dumpAsHex   true if SkScalar values are written as hexadecimal
+    */
+    void dump(SkWStream* stream, bool forceClose, bool dumpAsHex) const;
+
+    /** Writes text representation of SkPath to standard output. The representation may be
+        directly compiled as C++ code. Floating point values are written
+        with limited precision; it may not be possible to reconstruct original SkPath
+        from output.
+    */
+    void dump() const;
+
+    /** Writes text representation of SkPath to standard output. The representation may be
+        directly compiled as C++ code. Floating point values are written
+        in hexadecimal to preserve their exact bit pattern. The output reconstructs the
+        original SkPath.
+
+        Use instead of dump() when submitting
+    */
+    void dumpHex() const;
+
+    /** Writes SkPath to buffer, returning the number of bytes written.
+        Pass nullptr to obtain the storage size.
+
+        Writes SkPath::FillType, verb array, SkPoint array, conic weight, and
+        additionally writes computed information like SkPath::Convexity and bounds.
+
+        Use only be used in concert with readFromMemory();
+        the format used for SkPath in memory is not guaranteed.
+
+        @param buffer  storage for SkPath; may be nullptr
+        @return        size of storage required for SkPath; always a multiple of 4
+    */
+    size_t writeToMemory(void* buffer) const;
+
+    /** Writes SkPath to buffer, returning the buffer written to, wrapped in SkData.
+
+        serialize() writes SkPath::FillType, verb array, SkPoint array, conic weight, and
+        additionally writes computed information like SkPath::Convexity and bounds.
+
+        serialize() should only be used in concert with readFromMemory().
+        The format used for SkPath in memory is not guaranteed.
+
+        @return  SkPath data wrapped in SkData buffer
+    */
+    sk_sp<SkData> serialize() const;
+
+    /** Initializes SkPath from buffer of size length. Returns zero if the buffer is
+        data is inconsistent, or the length is too small.
+
+        Reads SkPath::FillType, verb array, SkPoint array, conic weight, and
+        additionally reads computed information like SkPath::Convexity and bounds.
+
+        Used only in concert with writeToMemory();
+        the format used for SkPath in memory is not guaranteed.
+
+        @param buffer  storage for SkPath
+        @param length  buffer size in bytes; must be multiple of 4
+        @return        number of bytes read, or zero on failure
+    */
+    size_t readFromMemory(const void* buffer, size_t length);
+
+    /** (See Skia bug 1762.)
+        Returns a non-zero, globally unique value. A different value is returned
+        if verb array, SkPoint array, or conic weight changes.
+
+        Setting SkPath::FillType does not change generation identifier.
+
+        Each time the path is modified, a different generation identifier will be returned.
+        SkPath::FillType does affect generation identifier on Android framework.
+
+        @return  non-zero, globally unique value
+    */
+    uint32_t getGenerationID() const;
+
+#ifdef SK_SUPPORT_DIRECT_PATHREF_VALIDATION
+    /** Returns if SkPath data is consistent. Corrupt SkPath data is detected if
+        internal values are out of range or internal storage does not match
+        array dimensions.
+
+        @return  true if SkPath data is consistent
+    */
+    bool isValid() const { return this->isValidImpl() && fPathRef->isValid(); }
+#else
+    /** Deprecated.
+     */
+    bool isValid() const { return this->isValidImpl(); }
+    /** Deprecated.
+     */
+    bool pathRefIsValid() const { return fPathRef->isValid(); }
+#endif
+
+private:
+    sk_sp<SkPathRef>                                     fPathRef;
+    int                                                  fLastMoveToIndex;
+    mutable SkAtomic<Convexity, sk_memory_order_relaxed> fConvexity;       // SkPath::Convexity
+   mutable SkAtomic<uint8_t, sk_memory_order_relaxed> fFirstDirection; // SkPathPriv::FirstDirection
+    uint8_t                                              fFillType    : 2;
+    uint8_t                                              fIsVolatile  : 1;
+    uint8_t                                              fIsBadForDAA : 1;
+
+    /** Resets all fields other than fPathRef to their initial 'empty' values.
+     *  Assumes the caller has already emptied fPathRef.
+     *  On Android increments fGenerationID without reseting it.
+     */
+    void resetFields();
+
+    /** Sets all fields other than fPathRef to the values in 'that'.
+     *  Assumes the caller has already set fPathRef.
+     *  Doesn't change fGenerationID or fSourcePath on Android.
+     */
+    void copyFields(const SkPath& that);
+
+    size_t writeToMemoryAsRRect(void* buffer) const;
+    size_t readAsRRect(const void*, size_t);
+    size_t readFromMemory_LE3(const void*, size_t);
+    size_t readFromMemory_EQ4(const void*, size_t);
+
+    friend class Iter;
+    friend class SkPathPriv;
+    friend class SkPathStroker;
+
+    /*  Append, in reverse order, the first contour of path, ignoring path's
+        last point. If no moveTo() call has been made for this contour, the
+        first point is automatically set to (0,0).
+    */
+    SkPath& reversePathTo(const SkPath&);
+
+    // called before we add points for lineTo, quadTo, cubicTo, checking to see
+    // if we need to inject a leading moveTo first
+    //
+    //  SkPath path; path.lineTo(...);   <--- need a leading moveTo(0, 0)
+    // SkPath path; ... path.close(); path.lineTo(...) <-- need a moveTo(previous moveTo)
+    //
+    inline void injectMoveToIfNeeded();
+
+    inline bool hasOnlyMoveTos() const;
+
+    Convexity internalGetConvexity() const;
+
+    /** Asserts if SkPath data is inconsistent.
+        Debugging check intended for internal use only.
+     */
+    SkDEBUGCODE(void validate() const { SkASSERT(this->isValidImpl()); } )
+    bool isValidImpl() const;
+    SkDEBUGCODE(void validateRef() const { fPathRef->validate(); } )
+
+    bool isRectContour(bool allowPartial, int* currVerb, const SkPoint** pts,
+                       bool* isClosed, Direction* direction, SkRect* rect) const;
+
+    // called by stroker to see if all points (in the last contour) are equal and worthy of a cap
+    bool isZeroLengthSincePoint(int startPtIndex) const;
+
+    /** Returns if the path can return a bound at no cost (true) or will have to
+        perform some computation (false).
+     */
+    bool hasComputedBounds() const {
+        SkDEBUGCODE(this->validate();)
+        return fPathRef->hasComputedBounds();
+    }
+
+
+    // 'rect' needs to be sorted
+    void setBounds(const SkRect& rect) {
+        SkPathRef::Editor ed(&fPathRef);
+
+        ed.setBounds(rect);
+    }
+
+    void setPt(int index, SkScalar x, SkScalar y);
+
+    friend class SkAutoPathBoundsUpdate;
+    friend class SkAutoDisableOvalCheck;
+    friend class SkAutoDisableDirectionCheck;
+    friend class SkPathWriter;
+    friend class SkOpBuilder;
+    friend class SkBench_AddPathTest; // perf test reversePathTo
+    friend class PathTest_Private; // unit test reversePathTo
+    friend class ForceIsRRect_Private; // unit test isRRect
+    friend class FuzzPath; // for legacy access to validateRef
+};
+
+#endif

+ 187 - 0
skia/include/core/SkPathEffect.h

@@ -0,0 +1,187 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPathEffect_DEFINED
+#define SkPathEffect_DEFINED
+
+#include "SkFlattenable.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+
+class SkPath;
+class SkStrokeRec;
+
+/** \class SkPathEffect
+
+    SkPathEffect is the base class for objects in the SkPaint that affect
+    the geometry of a drawing primitive before it is transformed by the
+    canvas' matrix and drawn.
+
+    Dashing is implemented as a subclass of SkPathEffect.
+*/
+class SK_API SkPathEffect : public SkFlattenable {
+public:
+    /**
+     *  Returns a patheffect that apples each effect (first and second) to the original path,
+     *  and returns a path with the sum of these.
+     *
+     *  result = first(path) + second(path)
+     *
+     */
+    static sk_sp<SkPathEffect> MakeSum(sk_sp<SkPathEffect> first, sk_sp<SkPathEffect> second);
+
+    /**
+     *  Returns a patheffect that applies the inner effect to the path, and then applies the
+     *  outer effect to the result of the inner's.
+     *
+     *  result = outer(inner(path))
+     */
+    static sk_sp<SkPathEffect> MakeCompose(sk_sp<SkPathEffect> outer, sk_sp<SkPathEffect> inner);
+
+    /**
+     *  Given a src path (input) and a stroke-rec (input and output), apply
+     *  this effect to the src path, returning the new path in dst, and return
+     *  true. If this effect cannot be applied, return false and ignore dst
+     *  and stroke-rec.
+     *
+     *  The stroke-rec specifies the initial request for stroking (if any).
+     *  The effect can treat this as input only, or it can choose to change
+     *  the rec as well. For example, the effect can decide to change the
+     *  stroke's width or join, or the effect can change the rec from stroke
+     *  to fill (or fill to stroke) in addition to returning a new (dst) path.
+     *
+     *  If this method returns true, the caller will apply (as needed) the
+     *  resulting stroke-rec to dst and then draw.
+     */
+    bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect* cullR) const;
+
+    /**
+     *  Compute a conservative bounds for its effect, given the src bounds.
+     *  The baseline implementation just assigns src to dst.
+     */
+    void computeFastBounds(SkRect* dst, const SkRect& src) const;
+
+    /** \class PointData
+
+        PointData aggregates all the information needed to draw the point
+        primitives returned by an 'asPoints' call.
+    */
+    class PointData {
+    public:
+        PointData()
+            : fFlags(0)
+            , fPoints(nullptr)
+            , fNumPoints(0) {
+            fSize.set(SK_Scalar1, SK_Scalar1);
+            // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets
+            // the kUseClip flag
+        }
+        ~PointData() {
+            delete [] fPoints;
+        }
+
+        // TODO: consider using passed-in flags to limit the work asPoints does.
+        // For example, a kNoPath flag could indicate don't bother generating
+        // stamped solutions.
+
+        // Currently none of these flags are supported.
+        enum PointFlags {
+            kCircles_PointFlag            = 0x01,   // draw points as circles (instead of rects)
+            kUsePath_PointFlag            = 0x02,   // draw points as stamps of the returned path
+            kUseClip_PointFlag            = 0x04,   // apply 'fClipRect' before drawing the points
+        };
+
+        uint32_t           fFlags;      // flags that impact the drawing of the points
+        SkPoint*           fPoints;     // the center point of each generated point
+        int                fNumPoints;  // number of points in fPoints
+        SkVector           fSize;       // the size to draw the points
+        SkRect             fClipRect;   // clip required to draw the points (if kUseClip is set)
+        SkPath             fPath;       // 'stamp' to be used at each point (if kUsePath is set)
+
+        SkPath             fFirst;      // If not empty, contains geometry for first point
+        SkPath             fLast;       // If not empty, contains geometry for last point
+    };
+
+    /**
+     *  Does applying this path effect to 'src' yield a set of points? If so,
+     *  optionally return the points in 'results'.
+     */
+    bool asPoints(PointData* results, const SkPath& src,
+                          const SkStrokeRec&, const SkMatrix&,
+                          const SkRect* cullR) const;
+
+    /**
+     *  If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType
+     *  and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled
+     *  in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or
+     *  greater to that of the effect, it will memcpy the values of the dash intervals into the
+     *  info. Thus the general approach will be call asADash once with default info to get DashType
+     *  and fCount. If effect can be represented as a dash pattern, allocate space for the intervals
+     *  in info, then call asADash again with the same info and the intervals will get copied in.
+     */
+
+    enum DashType {
+        kNone_DashType, //!< ignores the info parameter
+        kDash_DashType, //!< fills in all of the info parameter
+    };
+
+    struct DashInfo {
+        DashInfo() : fIntervals(nullptr), fCount(0), fPhase(0) {}
+        DashInfo(SkScalar* intervals, int32_t count, SkScalar phase)
+            : fIntervals(intervals), fCount(count), fPhase(phase) {}
+
+        SkScalar*   fIntervals;         //!< Length of on/off intervals for dashed lines
+                                        //   Even values represent ons, and odds offs
+        int32_t     fCount;             //!< Number of intervals in the dash. Should be even number
+        SkScalar    fPhase;             //!< Offset into the dashed interval pattern
+                                        //   mod the sum of all intervals
+    };
+
+    DashType asADash(DashInfo* info) const;
+
+    static void RegisterFlattenables();
+
+    static SkFlattenable::Type GetFlattenableType() {
+        return kSkPathEffect_Type;
+    }
+
+    SkFlattenable::Type getFlattenableType() const override {
+        return kSkPathEffect_Type;
+    }
+
+    static sk_sp<SkPathEffect> Deserialize(const void* data, size_t size,
+                                          const SkDeserialProcs* procs = nullptr) {
+        return sk_sp<SkPathEffect>(static_cast<SkPathEffect*>(
+                                  SkFlattenable::Deserialize(
+                                  kSkPathEffect_Type, data, size, procs).release()));
+    }
+
+protected:
+    SkPathEffect() {}
+
+    virtual bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const = 0;
+    virtual SkRect onComputeFastBounds(const SkRect& src) const {
+        return src;
+    }
+    virtual bool onAsPoints(PointData*, const SkPath&, const SkStrokeRec&, const SkMatrix&,
+                            const SkRect*) const {
+        return false;
+    }
+    virtual DashType onAsADash(DashInfo*) const {
+        return kNone_DashType;
+    }
+
+private:
+    // illegal
+    SkPathEffect(const SkPathEffect&);
+    SkPathEffect& operator=(const SkPathEffect&);
+
+    typedef SkFlattenable INHERITED;
+};
+
+#endif

+ 125 - 0
skia/include/core/SkPathMeasure.h

@@ -0,0 +1,125 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPathMeasure_DEFINED
+#define SkPathMeasure_DEFINED
+
+#include "../private/SkTDArray.h"
+#include "SkPath.h"
+
+struct SkConic;
+
+class SK_API SkPathMeasure : SkNoncopyable {
+public:
+    SkPathMeasure();
+    /** Initialize the pathmeasure with the specified path. The path must remain valid
+        for the lifetime of the measure object, or until setPath() is called with
+        a different path (or null), since the measure object keeps a pointer to the
+        path object (does not copy its data).
+
+        resScale controls the precision of the measure. values > 1 increase the
+        precision (and possible slow down the computation).
+    */
+    SkPathMeasure(const SkPath& path, bool forceClosed, SkScalar resScale = 1);
+    ~SkPathMeasure();
+
+    /** Reset the pathmeasure with the specified path. The path must remain valid
+        for the lifetime of the measure object, or until setPath() is called with
+        a different path (or null), since the measure object keeps a pointer to the
+        path object (does not copy its data).
+    */
+    void setPath(const SkPath*, bool forceClosed);
+
+    /** Return the total length of the current contour, or 0 if no path
+        is associated (e.g. resetPath(null))
+    */
+    SkScalar getLength();
+
+    /** Pins distance to 0 <= distance <= getLength(), and then computes
+        the corresponding position and tangent.
+        Returns false if there is no path, or a zero-length path was specified, in which case
+        position and tangent are unchanged.
+    */
+    bool SK_WARN_UNUSED_RESULT getPosTan(SkScalar distance, SkPoint* position,
+                                         SkVector* tangent);
+
+    enum MatrixFlags {
+        kGetPosition_MatrixFlag     = 0x01,
+        kGetTangent_MatrixFlag      = 0x02,
+        kGetPosAndTan_MatrixFlag    = kGetPosition_MatrixFlag | kGetTangent_MatrixFlag
+    };
+
+    /** Pins distance to 0 <= distance <= getLength(), and then computes
+        the corresponding matrix (by calling getPosTan).
+        Returns false if there is no path, or a zero-length path was specified, in which case
+        matrix is unchanged.
+    */
+    bool SK_WARN_UNUSED_RESULT getMatrix(SkScalar distance, SkMatrix* matrix,
+                                  MatrixFlags flags = kGetPosAndTan_MatrixFlag);
+
+    /** Given a start and stop distance, return in dst the intervening segment(s).
+        If the segment is zero-length, return false, else return true.
+        startD and stopD are pinned to legal values (0..getLength()). If startD > stopD
+        then return false (and leave dst untouched).
+        Begin the segment with a moveTo if startWithMoveTo is true
+    */
+    bool getSegment(SkScalar startD, SkScalar stopD, SkPath* dst, bool startWithMoveTo);
+
+    /** Return true if the current contour is closed()
+    */
+    bool isClosed();
+
+    /** Move to the next contour in the path. Return true if one exists, or false if
+        we're done with the path.
+    */
+    bool nextContour();
+
+#ifdef SK_DEBUG
+    void    dump();
+#endif
+
+private:
+    SkPath::Iter    fIter;
+    SkPath          fPath;
+    SkScalar        fTolerance;
+    SkScalar        fLength;            // relative to the current contour
+    unsigned        fFirstPtIndex;      // relative to the current contour
+    bool            fIsClosed;          // relative to the current contour
+    bool            fForceClosed;
+#if defined(IS_FUZZING_WITH_LIBFUZZER)
+    int             fSubdivisionsMax;
+#endif
+    struct Segment {
+        SkScalar    fDistance;  // total distance up to this point
+        unsigned    fPtIndex; // index into the fPts array
+        unsigned    fTValue : 30;
+        unsigned    fType : 2;  // actually the enum SkSegType
+                                // See SkPathMeasurePriv.h
+
+        SkScalar getScalarT() const;
+    };
+    SkTDArray<Segment>  fSegments;
+    SkTDArray<SkPoint>  fPts; // Points used to define the segments
+
+    static const Segment* NextSegment(const Segment*);
+
+    void     buildSegments();
+    SkScalar compute_quad_segs(const SkPoint pts[3], SkScalar distance,
+                                int mint, int maxt, unsigned ptIndex);
+    SkScalar compute_conic_segs(const SkConic&, SkScalar distance,
+                                int mint, const SkPoint& minPt,
+                                int maxt, const SkPoint& maxPt, unsigned ptIndex);
+    SkScalar compute_cubic_segs(const SkPoint pts[3], SkScalar distance,
+                                int mint, int maxt, unsigned ptIndex);
+    const Segment* distanceToSegment(SkScalar distance, SkScalar* t);
+    bool quad_too_curvy(const SkPoint pts[3]);
+    bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt,const SkPoint& lastPt);
+    bool cheap_dist_exceeds_limit(const SkPoint& pt, SkScalar x, SkScalar y);
+    bool cubic_too_curvy(const SkPoint pts[4]);
+};
+
+#endif

+ 284 - 0
skia/include/core/SkPicture.h

@@ -0,0 +1,284 @@
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkPicture.h and docs/SkPicture_Reference.bmh
+   on 2018-08-10 12:59:44. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkPicture_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkPicture_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkPicture.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkPicture_DEFINED
+#define SkPicture_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkRect.h"
+#include "SkTypes.h"
+
+class SkCanvas;
+class SkData;
+struct SkDeserialProcs;
+class SkImage;
+struct SkSerialProcs;
+class SkStream;
+class SkWStream;
+
+/** \class SkPicture
+    SkPicture records drawing commands made to SkCanvas. The command stream may be
+    played in whole or in part at a later time.
+
+    SkPicture is an abstract class. SkPicture may be generated by SkPictureRecorder
+    or SkDrawable, or from SkPicture previously saved to SkData or SkStream.
+
+    SkPicture may contain any SkCanvas drawing command, as well as one or more
+    SkCanvas matrix or SkCanvas clip. SkPicture has a cull SkRect, which is used as
+    a bounding box hint. To limit SkPicture bounds, use SkCanvas clip when
+    recording or drawing SkPicture.
+*/
+class SK_API SkPicture : public SkRefCnt {
+public:
+
+    /** Recreates SkPicture that was serialized into a stream. Returns constructed SkPicture
+        if successful; otherwise, returns nullptr. Fails if data does not permit
+        constructing valid SkPicture.
+
+        procs->fPictureProc permits supplying a custom function to decode SkPicture.
+        If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx
+        may be used to provide user context to procs->fPictureProc; procs->fPictureProc
+        is called with a pointer to data, data byte length, and user context.
+
+        @param stream  container for serial data
+        @param procs   custom serial data decoders; may be nullptr
+        @return        SkPicture constructed from stream data
+    */
+    static sk_sp<SkPicture> MakeFromStream(SkStream* stream,
+                                           const SkDeserialProcs* procs = nullptr);
+
+    /** Recreates SkPicture that was serialized into data. Returns constructed SkPicture
+        if successful; otherwise, returns nullptr. Fails if data does not permit
+        constructing valid SkPicture.
+
+        procs->fPictureProc permits supplying a custom function to decode SkPicture.
+        If procs->fPictureProc is nullptr, default decoding is used. procs->fPictureCtx
+        may be used to provide user context to procs->fPictureProc; procs->fPictureProc
+        is called with a pointer to data, data byte length, and user context.
+
+        @param data   container for serial data
+        @param procs  custom serial data decoders; may be nullptr
+        @return       SkPicture constructed from data
+    */
+    static sk_sp<SkPicture> MakeFromData(const SkData* data,
+                                         const SkDeserialProcs* procs = nullptr);
+
+    /**
+
+        @param data   pointer to serial data
+        @param size   size of data
+        @param procs  custom serial data decoders; may be nullptr
+        @return       SkPicture constructed from data
+    */
+    static sk_sp<SkPicture> MakeFromData(const void* data, size_t size,
+                                         const SkDeserialProcs* procs = nullptr);
+
+    /** \class SkPicture::AbortCallback
+        AbortCallback is an abstract class. An implementation of AbortCallback may
+        passed as a parameter to SkPicture::playback, to stop it before all drawing
+        commands have been processed.
+
+        If AbortCallback::abort returns true, SkPicture::playback is interrupted.
+    */
+    class SK_API AbortCallback {
+    public:
+
+        /** Has no effect.
+
+            @return  abstract class cannot be instantiated
+        */
+        AbortCallback() {}
+
+        /** Has no effect.
+        */
+        virtual ~AbortCallback() {}
+
+        /** Stops SkPicture playback when some condition is met. A subclass of
+            AbortCallback provides an override for abort() that can stop SkPicture::playback.
+
+            The part of SkPicture drawn when aborted is undefined. SkPicture instantiations are
+            free to stop drawing at different points during playback.
+
+            If the abort happens inside one or more calls to SkCanvas::save(), stack
+            of SkCanvas matrix and SkCanvas clip values is restored to its state before
+            SkPicture::playback was called.
+
+            @return  true to stop playback
+        */
+        virtual bool abort() = 0;
+    };
+
+    /** Replays the drawing commands on the specified canvas. In the case that the
+        commands are recorded, each command in the SkPicture is sent separately to canvas.
+
+        To add a single command to draw SkPicture to recording canvas, call
+        SkCanvas::drawPicture instead.
+
+        @param canvas    receiver of drawing commands
+        @param callback  allows interruption of playback
+    */
+    virtual void playback(SkCanvas* canvas, AbortCallback* callback = nullptr) const = 0;
+
+    /** Returns cull SkRect for this picture, passed in when SkPicture was created.
+        Returned SkRect does not specify clipping SkRect for SkPicture; cull is hint
+        of SkPicture bounds.
+
+        SkPicture is free to discard recorded drawing commands that fall outside
+        cull.
+
+        @return  bounds passed when SkPicture was created
+    */
+    virtual SkRect cullRect() const = 0;
+
+    /** Returns a non-zero value unique among SkPicture in Skia process.
+
+        @return  identifier for SkPicture
+    */
+    uint32_t uniqueID() const;
+
+    /** Returns storage containing SkData describing SkPicture, using optional custom
+        encoders.
+
+        procs->fPictureProc permits supplying a custom function to encode SkPicture.
+        If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx
+        may be used to provide user context to procs->fPictureProc; procs->fPictureProc
+        is called with a pointer to SkPicture and user context.
+
+        @param procs  custom serial data encoders; may be nullptr
+        @return       storage containing serialized SkPicture
+    */
+    sk_sp<SkData> serialize(const SkSerialProcs* procs = nullptr) const;
+
+    /** Writes picture to stream, using optional custom encoders.
+
+        procs->fPictureProc permits supplying a custom function to encode SkPicture.
+        If procs->fPictureProc is nullptr, default encoding is used. procs->fPictureCtx
+        may be used to provide user context to procs->fPictureProc; procs->fPictureProc
+        is called with a pointer to SkPicture and user context.
+
+        @param stream  writable serial data stream
+        @param procs   custom serial data encoders; may be nullptr
+    */
+    void serialize(SkWStream* stream, const SkSerialProcs* procs = nullptr) const;
+
+    /** Returns a placeholder SkPicture. Result does not draw, and contains only
+        cull SkRect, a hint of its bounds. Result is immutable; it cannot be changed
+        later. Result identifier is unique.
+
+        Returned placeholder can be intercepted during playback to insert other
+        commands into SkCanvas draw stream.
+
+        @param cull  placeholder dimensions
+        @return      placeholder with unique identifier
+    */
+    static sk_sp<SkPicture> MakePlaceholder(SkRect cull);
+
+    /** Returns the approximate number of operations in SkPicture. Returned value
+        may be greater or less than the number of SkCanvas calls
+        recorded: some calls may be recorded as more than one operation, other
+        calls may be optimized away.
+
+        @return  approximate operation count
+    */
+    virtual int approximateOpCount() const = 0;
+
+    /** Returns the approximate byte size of SkPicture. Does not include large objects
+        referenced by SkPicture.
+
+        @return  approximate size
+    */
+    virtual size_t approximateBytesUsed() const = 0;
+
+private:
+    // Subclass whitelist.
+    SkPicture();
+    friend class SkBigPicture;
+    friend class SkEmptyPicture;
+    friend class SkPicturePriv;
+    template <typename> friend class SkMiniPicture;
+
+    void serialize(SkWStream*, const SkSerialProcs*, class SkRefCntSet* typefaces) const;
+    static sk_sp<SkPicture> MakeFromStream(SkStream*, const SkDeserialProcs*,
+                                           class SkTypefacePlayback*);
+    friend class SkPictureData;
+
+    /** Return true if the SkStream/Buffer represents a serialized picture, and
+     fills out SkPictInfo. After this function returns, the data source is not
+     rewound so it will have to be manually reset before passing to
+     MakeFromStream or MakeFromBuffer. Note, MakeFromStream and
+     MakeFromBuffer perform this check internally so these entry points are
+     intended for stand alone tools.
+     If false is returned, SkPictInfo is unmodified.
+     */
+    static bool StreamIsSKP(SkStream*, struct SkPictInfo*);
+    static bool BufferIsSKP(class SkReadBuffer*, struct SkPictInfo*);
+    friend bool SkPicture_StreamIsSKP(SkStream*, struct SkPictInfo*);
+
+    // Returns NULL if this is not an SkBigPicture.
+    virtual const class SkBigPicture* asSkBigPicture() const { return nullptr; }
+
+    friend struct SkPathCounter;
+
+    // V35: Store SkRect (rather then width & height) in header
+    // V36: Remove (obsolete) alphatype from SkColorTable
+    // V37: Added shadow only option to SkDropShadowImageFilter (last version to record CLEAR)
+    // V38: Added PictureResolution option to SkPictureImageFilter
+    // V39: Added FilterLevel option to SkPictureImageFilter
+    // V40: Remove UniqueID serialization from SkImageFilter.
+    // V41: Added serialization of SkBitmapSource's filterQuality parameter
+    // V42: Added a bool to SkPictureShader serialization to indicate did-we-serialize-a-picture?
+    // V43: Added DRAW_IMAGE and DRAW_IMAGE_RECT opt codes to serialized data
+    // V44: Move annotations from paint to drawAnnotation
+    // V45: Add invNormRotation to SkLightingShader.
+    // V46: Add drawTextRSXform
+    // V47: Add occluder rect to SkBlurMaskFilter
+    // V48: Read and write extended SkTextBlobs.
+    // V49: Gradients serialized as SkColor4f + SkColorSpace
+    // V50: SkXfermode -> SkBlendMode
+    // V51: more SkXfermode -> SkBlendMode
+    // V52: Remove SkTextBlob::fRunCount
+    // V53: SaveLayerRec clip mask
+    // V54: ComposeShader can use a Mode or a Lerp
+    // V55: Drop blendmode[] from MergeImageFilter
+    // V56: Add TileMode in SkBlurImageFilter.
+    // V57: Sweep tiling info.
+    // V58: No more 2pt conical flipping.
+    // V59: No more LocalSpace option on PictureImageFilter
+    // V60: Remove flags in picture header
+    // V61: Change SkDrawPictureRec to take two colors rather than two alphas
+    // V62: Don't negate size of custom encoded images (don't write origin x,y either)
+    // V63: Store image bounds (including origin) instead of just width/height to support subsets
+    // V64: Remove occluder feature from blur maskFilter
+
+    // Only SKPs within the min/current picture version range (inclusive) can be read.
+    static const uint32_t     MIN_PICTURE_VERSION = 56;     // august 2017
+    static const uint32_t CURRENT_PICTURE_VERSION = 65;
+
+    static_assert(MIN_PICTURE_VERSION <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp");
+
+    static bool IsValidPictInfo(const struct SkPictInfo& info);
+    static sk_sp<SkPicture> Forwardport(const struct SkPictInfo&,
+                                        const class SkPictureData*,
+                                        class SkReadBuffer* buffer);
+
+    struct SkPictInfo createHeader() const;
+    class SkPictureData* backport() const;
+
+    mutable uint32_t fUniqueID;
+};
+
+#endif

+ 125 - 0
skia/include/core/SkPictureRecorder.h

@@ -0,0 +1,125 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPictureRecorder_DEFINED
+#define SkPictureRecorder_DEFINED
+
+#include "../private/SkNoncopyable.h"
+#include "SkBBHFactory.h"
+#include "SkPicture.h"
+#include "SkRefCnt.h"
+
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+namespace android {
+    class Picture;
+};
+#endif
+
+class GrContext;
+class SkCanvas;
+class SkDrawable;
+class SkMiniRecorder;
+class SkPictureRecord;
+class SkRecord;
+class SkRecorder;
+
+class SK_API SkPictureRecorder : SkNoncopyable {
+public:
+    SkPictureRecorder();
+    ~SkPictureRecorder();
+
+    enum RecordFlags {
+        // If you call drawPicture() or drawDrawable() on the recording canvas, this flag forces
+        // that object to playback its contents immediately rather than reffing the object.
+        kPlaybackDrawPicture_RecordFlag     = 1 << 0,
+    };
+
+    enum FinishFlags {
+    };
+
+    /** Returns the canvas that records the drawing commands.
+        @param bounds the cull rect used when recording this picture. Any drawing the falls outside
+                      of this rect is undefined, and may be drawn or it may not.
+        @param bbhFactory factory to create desired acceleration structure
+        @param recordFlags optional flags that control recording.
+        @return the canvas.
+    */
+    SkCanvas* beginRecording(const SkRect& bounds,
+                             SkBBHFactory* bbhFactory = nullptr,
+                             uint32_t recordFlags = 0);
+
+    SkCanvas* beginRecording(SkScalar width, SkScalar height,
+                             SkBBHFactory* bbhFactory = nullptr,
+                             uint32_t recordFlags = 0) {
+        return this->beginRecording(SkRect::MakeWH(width, height), bbhFactory, recordFlags);
+    }
+
+    /** Returns the recording canvas if one is active, or NULL if recording is
+        not active. This does not alter the refcnt on the canvas (if present).
+    */
+    SkCanvas* getRecordingCanvas();
+
+    /**
+     *  Signal that the caller is done recording. This invalidates the canvas returned by
+     *  beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
+     *  must call unref() when they are done using it.
+     *
+     *  The returned picture is immutable. If during recording drawables were added to the canvas,
+     *  these will have been "drawn" into a recording canvas, so that this resulting picture will
+     *  reflect their current state, but will not contain a live reference to the drawables
+     *  themselves.
+     */
+    sk_sp<SkPicture> finishRecordingAsPicture(uint32_t endFlags = 0);
+
+    /**
+     *  Signal that the caller is done recording, and update the cull rect to use for bounding
+     *  box hierarchy (BBH) generation. The behavior is the same as calling
+     *  finishRecordingAsPicture(), except that this method updates the cull rect initially passed
+     *  into beginRecording.
+     *  @param cullRect the new culling rectangle to use as the overall bound for BBH generation
+     *                  and subsequent culling operations.
+     *  @return the picture containing the recorded content.
+     */
+    sk_sp<SkPicture> finishRecordingAsPictureWithCull(const SkRect& cullRect,
+                                                      uint32_t endFlags = 0);
+
+    /**
+     *  Signal that the caller is done recording. This invalidates the canvas returned by
+     *  beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who
+     *  must call unref() when they are done using it.
+     *
+     *  Unlike finishRecordingAsPicture(), which returns an immutable picture, the returned drawable
+     *  may contain live references to other drawables (if they were added to the recording canvas)
+     *  and therefore this drawable will reflect the current state of those nested drawables anytime
+     *  it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()).
+     */
+    sk_sp<SkDrawable> finishRecordingAsDrawable(uint32_t endFlags = 0);
+
+private:
+    void reset();
+
+    /** Replay the current (partially recorded) operation stream into
+        canvas. This call doesn't close the current recording.
+    */
+#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
+    friend class android::Picture;
+#endif
+    friend class SkPictureRecorderReplayTester; // for unit testing
+    void partialReplay(SkCanvas* canvas) const;
+
+    bool                        fActivelyRecording;
+    uint32_t                    fFlags;
+    SkRect                      fCullRect;
+    sk_sp<SkBBoxHierarchy>      fBBH;
+    std::unique_ptr<SkRecorder> fRecorder;
+    sk_sp<SkRecord>             fRecord;
+    std::unique_ptr<SkMiniRecorder> fMiniRecorder;
+
+    typedef SkNoncopyable INHERITED;
+};
+
+#endif

+ 129 - 0
skia/include/core/SkPixelRef.h

@@ -0,0 +1,129 @@
+/*
+ * Copyright 2008 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPixelRef_DEFINED
+#define SkPixelRef_DEFINED
+
+#include "../private/SkMutex.h"
+#include "../private/SkTDArray.h"
+#include "SkBitmap.h"
+#include "SkFilterQuality.h"
+#include "SkImageInfo.h"
+#include "SkPixmap.h"
+#include "SkRefCnt.h"
+#include "SkSize.h"
+#include "SkString.h"
+
+#include <atomic>
+
+struct SkIRect;
+
+class GrTexture;
+class SkDiscardableMemory;
+
+/** \class SkPixelRef
+
+    This class is the smart container for pixel memory, and is used with SkBitmap.
+    This class can be shared/accessed between multiple threads.
+*/
+class SK_API SkPixelRef : public SkRefCnt {
+public:
+    SkPixelRef(int width, int height, void* addr, size_t rowBytes);
+    ~SkPixelRef() override;
+
+    int width() const { return fWidth; }
+    int height() const { return fHeight; }
+    void* pixels() const { return fPixels; }
+    size_t rowBytes() const { return fRowBytes; }
+
+    /** Returns a non-zero, unique value corresponding to the pixels in this
+        pixelref. Each time the pixels are changed (and notifyPixelsChanged is
+        called), a different generation ID will be returned.
+    */
+    uint32_t getGenerationID() const;
+
+    /**
+     *  Call this if you have changed the contents of the pixels. This will in-
+     *  turn cause a different generation ID value to be returned from
+     *  getGenerationID().
+     */
+    void notifyPixelsChanged();
+
+    /** Returns true if this pixelref is marked as immutable, meaning that the
+        contents of its pixels will not change for the lifetime of the pixelref.
+    */
+    bool isImmutable() const { return fMutability != kMutable; }
+
+    /** Marks this pixelref is immutable, meaning that the contents of its
+        pixels will not change for the lifetime of the pixelref. This state can
+        be set on a pixelref, but it cannot be cleared once it is set.
+    */
+    void setImmutable();
+
+    // Register a listener that may be called the next time our generation ID changes.
+    //
+    // We'll only call the listener if we're confident that we are the only SkPixelRef with this
+    // generation ID.  If our generation ID changes and we decide not to call the listener, we'll
+    // never call it: you must add a new listener for each generation ID change.  We also won't call
+    // the listener when we're certain no one knows what our generation ID is.
+    //
+    // This can be used to invalidate caches keyed by SkPixelRef generation ID.
+    struct GenIDChangeListener {
+        virtual ~GenIDChangeListener() {}
+        virtual void onChange() = 0;
+    };
+
+    // Takes ownership of listener.  Threadsafe.
+    void addGenIDChangeListener(GenIDChangeListener* listener);
+
+    // Call when this pixelref is part of the key to a resourcecache entry. This allows the cache
+    // to know automatically those entries can be purged when this pixelref is changed or deleted.
+    void notifyAddedToCache() {
+        fAddedToCache.store(true);
+    }
+
+    virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return nullptr; }
+
+protected:
+    void android_only_reset(int width, int height, size_t rowBytes);
+
+private:
+    int                 fWidth;
+    int                 fHeight;
+    void*               fPixels;
+    size_t              fRowBytes;
+
+    // Bottom bit indicates the Gen ID is unique.
+    bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); }
+    mutable std::atomic<uint32_t> fTaggedGenID;
+
+    SkMutex                         fGenIDChangeListenersMutex;
+    SkTDArray<GenIDChangeListener*> fGenIDChangeListeners;  // pointers are owned
+
+    // Set true by caches when they cache content that's derived from the current pixels.
+    std::atomic<bool> fAddedToCache;
+
+    enum Mutability {
+        kMutable,               // PixelRefs begin mutable.
+        kTemporarilyImmutable,  // Considered immutable, but can revert to mutable.
+        kImmutable,             // Once set to this state, it never leaves.
+    } fMutability : 8;          // easily fits inside a byte
+
+    void needsNewGenID();
+    void callGenIDChangeListeners();
+
+    void setTemporarilyImmutable();
+    void restoreMutability();
+    friend class SkSurface_Raster;   // For the two methods above.
+
+    void setImmutableWithID(uint32_t genID);
+    friend void SkBitmapCache_setImmutableWithID(SkPixelRef*, uint32_t);
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif

+ 706 - 0
skia/include/core/SkPixmap.h

@@ -0,0 +1,706 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Generated by tools/bookmaker from include/core/SkPixmap.h and docs/SkPixmap_Reference.bmh
+   on 2018-06-08 11:48:28. Additional documentation and examples can be found at:
+   https://skia.org/user/api/SkPixmap_Reference
+
+   You may edit either file directly. Structural changes to public interfaces require
+   editing both files. After editing docs/SkPixmap_Reference.bmh, run:
+       bookmaker -b docs -i include/core/SkPixmap.h -p
+   to create an updated version of this file.
+ */
+
+#ifndef SkPixmap_DEFINED
+#define SkPixmap_DEFINED
+
+#include "SkColor.h"
+#include "SkFilterQuality.h"
+#include "SkImageInfo.h"
+
+class SkData;
+struct SkMask;
+
+/** \class SkPixmap
+    SkPixmap provides a utility to pair SkImageInfo with pixels and row bytes.
+    SkPixmap is a low level class which provides convenience functions to access
+    raster destinations. SkCanvas can not draw SkPixmap, nor does SkPixmap provide
+    a direct drawing destination.
+
+    Use SkBitmap to draw pixels referenced by SkPixmap; use SkSurface to draw into
+    pixels referenced by SkPixmap.
+
+    SkPixmap does not try to manage the lifetime of the pixel memory. Use SkPixelRef
+    to manage pixel memory; SkPixelRef is safe across threads.
+*/
+class SK_API SkPixmap {
+public:
+
+    /** Creates an empty SkPixmap without pixels, with kUnknown_SkColorType, with
+        kUnknown_SkAlphaType, and with a width and height of zero. Use
+        reset() to associate pixels, SkColorType, SkAlphaType, width, and height
+        after SkPixmap has been created.
+
+        @return  empty SkPixmap
+    */
+    SkPixmap()
+        : fPixels(nullptr), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0))
+    {}
+
+    /** Creates SkPixmap from info width, height, SkAlphaType, and SkColorType.
+        addr points to pixels, or nullptr. rowBytes should be info.width() times
+        info.bytesPerPixel(), or larger.
+
+        No parameter checking is performed; it is up to the caller to ensure that
+        addr and rowBytes agree with info.
+
+        The memory lifetime of pixels is managed by the caller. When SkPixmap goes
+        out of scope, addr is unaffected.
+
+        SkPixmap may be later modified by reset() to change its size, pixel type, or
+        storage.
+
+        @param info      width, height, SkAlphaType, SkColorType of SkImageInfo
+        @param addr      pointer to pixels allocated by caller; may be nullptr
+        @param rowBytes  size of one row of addr; width times pixel size, or larger
+        @return          initialized SkPixmap
+    */
+    SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes)
+        : fPixels(addr), fRowBytes(rowBytes), fInfo(info)
+    {}
+
+    /** Sets width, height, row bytes to zero; pixel address to nullptr; SkColorType to
+        kUnknown_SkColorType; and SkAlphaType to kUnknown_SkAlphaType.
+
+        The prior pixels are unaffected; it is up to the caller to release pixels
+        memory if desired.
+    */
+    void reset();
+
+    /** Sets width, height, SkAlphaType, and SkColorType from info.
+        Sets pixel address from addr, which may be nullptr.
+        Sets row bytes from rowBytes, which should be info.width() times
+        info.bytesPerPixel(), or larger.
+
+        Does not check addr. Asserts if built with SK_DEBUG defined and if rowBytes is
+        too small to hold one row of pixels.
+
+        The memory lifetime pixels are managed by the caller. When SkPixmap goes
+        out of scope, addr is unaffected.
+
+        @param info      width, height, SkAlphaType, SkColorType of SkImageInfo
+        @param addr      pointer to pixels allocated by caller; may be nullptr
+        @param rowBytes  size of one row of addr; width times pixel size, or larger
+    */
+    void reset(const SkImageInfo& info, const void* addr, size_t rowBytes);
+
+    /** Changes SkColorSpace in SkImageInfo; preserves width, height, SkAlphaType, and
+        SkColorType in SkImage, and leaves pixel address and row bytes unchanged.
+        SkColorSpace reference count is incremented.
+
+        @param colorSpace  SkColorSpace moved to SkImageInfo
+    */
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+
+    /** Deprecated.
+    */
+    bool SK_WARN_UNUSED_RESULT reset(const SkMask& mask);
+
+    /** Sets subset width, height, pixel address to intersection of SkPixmap with area,
+        if intersection is not empty; and return true. Otherwise, leave subset unchanged
+        and return false.
+
+        Failing to read the return value generates a compile time warning.
+
+        @param subset  storage for width, height, pixel address of intersection
+        @param area    bounds to intersect with SkPixmap
+        @return        true if intersection of SkPixmap and area is not empty
+    */
+    bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const;
+
+    /** Returns width, height, SkAlphaType, SkColorType, and SkColorSpace.
+
+        @return  reference to SkImageInfo
+    */
+    const SkImageInfo& info() const { return fInfo; }
+
+    /** Returns row bytes, the interval from one pixel row to the next. Row bytes
+        is at least as large as: width() * info().bytesPerPixel().
+
+        Returns zero if colorType() is kUnknown_SkColorType.
+        It is up to the SkBitmap creator to ensure that row bytes is a useful value.
+
+        @return  byte length of pixel row
+    */
+    size_t rowBytes() const { return fRowBytes; }
+
+    /** Returns pixel address, the base address corresponding to the pixel origin.
+
+        It is up to the SkPixmap creator to ensure that pixel address is a useful value.
+
+        @return  pixel address
+    */
+    const void* addr() const { return fPixels; }
+
+    /** Returns pixel count in each pixel row. Should be equal or less than:
+        rowBytes() / info().bytesPerPixel().
+
+        @return  pixel width in SkImageInfo
+    */
+    int width() const { return fInfo.width(); }
+
+    /** Returns pixel row count.
+
+        @return  pixel height in SkImageInfo
+    */
+    int height() const { return fInfo.height(); }
+
+    /** Returns SkColorType, one of:
+        kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType,
+        kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType,
+        kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType,
+        kGray_8_SkColorType, kRGBA_F16_SkColorType.
+
+        @return  SkColorType in SkImageInfo
+    */
+    SkColorType colorType() const { return fInfo.colorType(); }
+
+    /** Returns SkAlphaType, one of:
+        kUnknown_SkAlphaType, kOpaque_SkAlphaType, kPremul_SkAlphaType,
+        kUnpremul_SkAlphaType.
+
+        @return  SkAlphaType in SkImageInfo
+    */
+    SkAlphaType alphaType() const { return fInfo.alphaType(); }
+
+    /** Returns SkColorSpace, the range of colors, associated with SkImageInfo. The
+        reference count of SkColorSpace is unchanged. The returned SkColorSpace is
+        immutable.
+
+        @return  SkColorSpace in SkImageInfo, or nullptr
+    */
+    SkColorSpace* colorSpace() const { return fInfo.colorSpace(); }
+
+    /** Returns true if SkAlphaType is kOpaque_SkAlphaType.
+        Does not check if SkColorType allows alpha, or if any pixel value has
+        transparency.
+
+        @return  true if SkImageInfo has opaque SkAlphaType
+    */
+    bool isOpaque() const { return fInfo.isOpaque(); }
+
+    /** Returns SkIRect { 0, 0, width(), height() }.
+
+        @return  integral rectangle from origin to width() and height()
+    */
+    SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
+
+    /** Returns number of pixels that fit on row. Should be greater than or equal to
+        width().
+
+        @return  maximum pixels per row
+    */
+    int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); }
+
+    /** Returns bit shift converting row bytes to row pixels.
+        Returns zero for kUnknown_SkColorType.
+
+        @return  one of: 0, 1, 2, 3; left shift to convert pixels to bytes
+    */
+    int shiftPerPixel() const { return fInfo.shiftPerPixel(); }
+
+    /** Returns minimum memory required for pixel storage.
+        Does not include unused memory on last row when rowBytesAsPixels() exceeds width().
+        Returns zero if result does not fit in size_t.
+        Returns zero if height() or width() is 0.
+        Returns height() times rowBytes() if colorType() is kUnknown_SkColorType.
+
+        @return  size in bytes of image buffer
+    */
+    size_t computeByteSize() const { return fInfo.computeByteSize(fRowBytes); }
+
+    /** Returns true if all pixels are opaque. SkColorType determines how pixels
+        are encoded, and whether pixel describes alpha. Returns true for SkColorType
+        without alpha in each pixel; for other SkColorType, returns true if all
+        pixels have alpha values equivalent to 1.0 or greater.
+
+        For SkColorType kRGB_565_SkColorType or kGray_8_SkColorType: always
+        returns true. For SkColorType kAlpha_8_SkColorType, kBGRA_8888_SkColorType,
+        kRGBA_8888_SkColorType: returns true if all pixel alpha values are 255.
+        For SkColorType kARGB_4444_SkColorType: returns true if all pixel alpha values are 15.
+        For kRGBA_F16_SkColorType: returns true if all pixel alpha values are 1.0 or
+        greater.
+
+        Returns false for kUnknown_SkColorType.
+
+        @return  true if all pixels have opaque values or SkColorType is opaque
+    */
+    bool computeIsOpaque() const;
+
+    /** Returns pixel at (x, y) as unpremultiplied color.
+        Returns black with alpha if SkColorType is kAlpha_8_SkColorType.
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined; and returns undefined values or may crash if
+        SK_RELEASE is defined. Fails if SkColorType is kUnknown_SkColorType or
+        pixel address is nullptr.
+
+        SkColorSpace in SkImageInfo is ignored. Some color precision may be lost in the
+        conversion to unpremultiplied color; original pixel data may have additional
+        precision.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   pixel converted to unpremultiplied color
+    */
+    SkColor getColor(int x, int y) const;
+
+    /** Look up the pixel at (x,y) and return its alpha component, normalized to [0..1].
+        This is roughly equivalent to SkGetColorA(getColor()), but can be more efficent
+        (and more precise if the pixels store more than 8 bits per component).
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   alpha converted to normalized float
+     */
+    float getAlphaf(int x, int y) const;
+
+    /** Returns readable pixel address at (x, y). Returns nullptr if SkPixelRef is nullptr.
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined. Returns nullptr if SkColorType is kUnknown_SkColorType.
+
+        Performs a lookup of pixel size; for better performance, call
+        one of: addr8, addr16, addr32, addr64, or addrF16().
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable generic pointer to pixel
+    */
+    const void* addr(int x, int y) const {
+        return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
+    }
+
+    /** Returns readable base pixel address. Result is addressable as unsigned 8-bit bytes.
+        Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or
+        kGray_8_SkColorType, and is built with SK_DEBUG defined.
+
+        One byte corresponds to one pixel.
+
+        @return  readable unsigned 8-bit pointer to pixels
+    */
+    const uint8_t* addr8() const {
+        SkASSERT(1 == fInfo.bytesPerPixel());
+        return reinterpret_cast<const uint8_t*>(fPixels);
+    }
+
+    /** Returns readable base pixel address. Result is addressable as unsigned 16-bit words.
+        Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or
+        kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
+
+        One word corresponds to one pixel.
+
+        @return  readable unsigned 16-bit pointer to pixels
+    */
+    const uint16_t* addr16() const {
+        SkASSERT(2 == fInfo.bytesPerPixel());
+        return reinterpret_cast<const uint16_t*>(fPixels);
+    }
+
+    /** Returns readable base pixel address. Result is addressable as unsigned 32-bit words.
+        Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or
+        kBGRA_8888_SkColorType, and is built with SK_DEBUG defined.
+
+        One word corresponds to one pixel.
+
+        @return  readable unsigned 32-bit pointer to pixels
+    */
+    const uint32_t* addr32() const {
+        SkASSERT(4 == fInfo.bytesPerPixel());
+        return reinterpret_cast<const uint32_t*>(fPixels);
+    }
+
+    /** Returns readable base pixel address. Result is addressable as unsigned 64-bit words.
+        Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
+        with SK_DEBUG defined.
+
+        One word corresponds to one pixel.
+
+        @return  readable unsigned 64-bit pointer to pixels
+    */
+    const uint64_t* addr64() const {
+        SkASSERT(8 == fInfo.bytesPerPixel());
+        return reinterpret_cast<const uint64_t*>(fPixels);
+    }
+
+    /** Returns readable base pixel address. Result is addressable as unsigned 16-bit words.
+        Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
+        with SK_DEBUG defined.
+
+        Each word represents one color component encoded as a half float.
+        Four words correspond to one pixel.
+
+        @return  readable unsigned 16-bit pointer to first component of pixels
+    */
+    const uint16_t* addrF16() const {
+        SkASSERT(8 == fInfo.bytesPerPixel());
+        SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
+        return reinterpret_cast<const uint16_t*>(fPixels);
+    }
+
+    /** Returns readable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined.
+
+        Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType or
+        kGray_8_SkColorType, and is built with SK_DEBUG defined.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable unsigned 8-bit pointer to pixel at (x, y)
+    */
+    const uint8_t* addr8(int x, int y) const {
+        SkASSERT((unsigned)x < (unsigned)fInfo.width());
+        SkASSERT((unsigned)y < (unsigned)fInfo.height());
+        return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0));
+    }
+
+    /** Returns readable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined.
+
+        Will trigger an assert() if SkColorType is not kRGB_565_SkColorType or
+        kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable unsigned 16-bit pointer to pixel at (x, y)
+    */
+    const uint16_t* addr16(int x, int y) const {
+        SkASSERT((unsigned)x < (unsigned)fInfo.width());
+        SkASSERT((unsigned)y < (unsigned)fInfo.height());
+        return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1));
+    }
+
+    /** Returns readable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined.
+
+        Will trigger an assert() if SkColorType is not kRGBA_8888_SkColorType or
+        kBGRA_8888_SkColorType, and is built with SK_DEBUG defined.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable unsigned 32-bit pointer to pixel at (x, y)
+    */
+    const uint32_t* addr32(int x, int y) const {
+        SkASSERT((unsigned)x < (unsigned)fInfo.width());
+        SkASSERT((unsigned)y < (unsigned)fInfo.height());
+        return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2));
+    }
+
+    /** Returns readable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined.
+
+        Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
+        with SK_DEBUG defined.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable unsigned 64-bit pointer to pixel at (x, y)
+    */
+    const uint64_t* addr64(int x, int y) const {
+        SkASSERT((unsigned)x < (unsigned)fInfo.width());
+        SkASSERT((unsigned)y < (unsigned)fInfo.height());
+        return (const uint64_t*)((const char*)this->addr64() + y * fRowBytes + (x << 3));
+    }
+
+    /** Returns readable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined.
+
+        Will trigger an assert() if SkColorType is not kRGBA_F16_SkColorType and is built
+        with SK_DEBUG defined.
+
+        Each unsigned 16-bit word represents one color component encoded as a half float.
+        Four words correspond to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   readable unsigned 16-bit pointer to pixel component at (x, y)
+    */
+    const uint16_t* addrF16(int x, int y) const {
+        SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
+        return reinterpret_cast<const uint16_t*>(this->addr64(x, y));
+    }
+
+    /** Returns writable base pixel address.
+
+        @return  writable generic base pointer to pixels
+    */
+    void* writable_addr() const { return const_cast<void*>(fPixels); }
+
+    /** Returns writable pixel address at (x, y).
+
+        Input is not validated: out of bounds values of x or y trigger an assert() if
+        built with SK_DEBUG defined. Returns zero if SkColorType is kUnknown_SkColorType.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable generic pointer to pixel
+    */
+    void* writable_addr(int x, int y) const {
+        return const_cast<void*>(this->addr(x, y));
+    }
+
+    /** Returns writable pixel address at (x, y). Result is addressable as unsigned
+        8-bit bytes. Will trigger an assert() if SkColorType is not kAlpha_8_SkColorType
+        or kGray_8_SkColorType, and is built with SK_DEBUG defined.
+
+        One byte corresponds to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable unsigned 8-bit pointer to pixels
+    */
+    uint8_t* writable_addr8(int x, int y) const {
+        return const_cast<uint8_t*>(this->addr8(x, y));
+    }
+
+    /** Returns writable_addr pixel address at (x, y). Result is addressable as unsigned
+        16-bit words. Will trigger an assert() if SkColorType is not kRGB_565_SkColorType
+        or kARGB_4444_SkColorType, and is built with SK_DEBUG defined.
+
+        One word corresponds to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable unsigned 16-bit pointer to pixel
+    */
+    uint16_t* writable_addr16(int x, int y) const {
+        return const_cast<uint16_t*>(this->addr16(x, y));
+    }
+
+    /** Returns writable pixel address at (x, y). Result is addressable as unsigned
+        32-bit words. Will trigger an assert() if SkColorType is not
+        kRGBA_8888_SkColorType or kBGRA_8888_SkColorType, and is built with SK_DEBUG
+        defined.
+
+        One word corresponds to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable unsigned 32-bit pointer to pixel
+    */
+    uint32_t* writable_addr32(int x, int y) const {
+        return const_cast<uint32_t*>(this->addr32(x, y));
+    }
+
+    /** Returns writable pixel address at (x, y). Result is addressable as unsigned
+        64-bit words. Will trigger an assert() if SkColorType is not
+        kRGBA_F16_SkColorType and is built with SK_DEBUG defined.
+
+        One word corresponds to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable unsigned 64-bit pointer to pixel
+    */
+    uint64_t* writable_addr64(int x, int y) const {
+        return const_cast<uint64_t*>(this->addr64(x, y));
+    }
+
+    /** Returns writable pixel address at (x, y). Result is addressable as unsigned
+        16-bit words. Will trigger an assert() if SkColorType is not
+        kRGBA_F16_SkColorType and is built with SK_DEBUG defined.
+
+        Each word represents one color component encoded as a half float.
+        Four words correspond to one pixel.
+
+        @param x  column index, zero or greater, and less than width()
+        @param y  row index, zero or greater, and less than height()
+        @return   writable unsigned 16-bit pointer to first component of pixel
+    */
+    uint16_t* writable_addrF16(int x, int y) const {
+        return reinterpret_cast<uint16_t*>(writable_addr64(x, y));
+    }
+
+    /** Copies a SkRect of pixels to dstPixels. Copy starts at (0, 0), and does not
+        exceed SkPixmap (width(), height()).
+
+        dstInfo specifies width, height, SkColorType, SkAlphaType, and
+        SkColorSpace of destination. dstRowBytes specifics the gap from one destination
+        row to the next. Returns true if pixels are copied. Returns false if
+        dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes().
+
+        Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
+        If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match.
+        If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must
+        match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        Returns false if SkPixmap width() or height() is zero or negative.
+
+        @param dstInfo      destination width, height, SkColorType, SkAlphaType, SkColorSpace
+        @param dstPixels    destination pixel storage
+        @param dstRowBytes  destination row length
+        @return             true if pixels are copied to dstPixels
+    */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
+        return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
+    }
+
+    /** Copies a SkRect of pixels to dstPixels. Copy starts at (srcX, srcY), and does not
+        exceed SkPixmap (width(), height()).
+
+        dstInfo specifies width, height, SkColorType, SkAlphaType, and
+        SkColorSpace of destination. dstRowBytes specifics the gap from one destination
+        row to the next. Returns true if pixels are copied. Returns false if
+        dstInfo address equals nullptr, or dstRowBytes is less than dstInfo.minRowBytes().
+
+        Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dstInfo.colorType() must match.
+        If SkPixmap colorType() is kGray_8_SkColorType, dstInfo.colorSpace() must match.
+        If SkPixmap alphaType() is kOpaque_SkAlphaType, dstInfo.alphaType() must
+        match. If SkPixmap colorSpace() is nullptr, dstInfo.colorSpace() must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false if SkPixmap width() or height() is zero or negative. Returns false if:
+        abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height().
+
+        @param dstInfo      destination width, height, SkColorType, SkAlphaType, SkColorSpace
+        @param dstPixels    destination pixel storage
+        @param dstRowBytes  destination row length
+        @param srcX         column index whose absolute value is less than width()
+        @param srcY         row index whose absolute value is less than height()
+        @return             true if pixels are copied to dstPixels
+    */
+    bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, int srcX,
+                    int srcY) const;
+
+    /** Copies a SkRect of pixels to dst. Copy starts at (srcX, srcY), and does not
+        exceed SkPixmap (width(), height()). dst specifies width, height, SkColorType,
+        SkAlphaType, and SkColorSpace of destination.  Returns true if pixels are copied.
+        Returns false if dst address equals nullptr, or dst.rowBytes() is less than
+        dst SkImageInfo::minRowBytes.
+
+        Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst.info().colorType must match.
+        If SkPixmap colorType() is kGray_8_SkColorType, dst.info().colorSpace must match.
+        If SkPixmap alphaType() is kOpaque_SkAlphaType, dst.info().alphaType must
+        match. If SkPixmap colorSpace() is nullptr, dst.info().colorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        srcX and srcY may be negative to copy only top or left of source. Returns
+        false SkPixmap width() or height() is zero or negative. Returns false if:
+        abs(srcX) >= Pixmap width(), or if abs(srcY) >= Pixmap height().
+
+        @param dst   SkImageInfo and pixel address to write to
+        @param srcX  column index whose absolute value is less than width()
+        @param srcY  row index whose absolute value is less than height()
+        @return      true if pixels are copied to dst
+    */
+    bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
+        return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
+    }
+
+    /** Copies pixels inside bounds() to dst. dst specifies width, height, SkColorType,
+        SkAlphaType, and SkColorSpace of destination.  Returns true if pixels are copied.
+        Returns false if dst address equals nullptr, or dst.rowBytes() is less than
+        dst SkImageInfo::minRowBytes.
+
+        Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
+        If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
+        If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
+        match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        Returns false if SkPixmap width() or height() is zero or negative.
+
+        @param dst  SkImageInfo and pixel address to write to
+        @return     true if pixels are copied to dst
+    */
+    bool readPixels(const SkPixmap& dst) const {
+        return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
+    }
+
+    /** Copies SkBitmap to dst, scaling pixels to fit dst.width() and dst.height(), and
+        converting pixels to match dst.colorType() and dst.alphaType(). Returns true if
+        pixels are copied. Returns false if dst address is nullptr, or dst.rowBytes() is
+        less than dst SkImageInfo::minRowBytes.
+
+        Pixels are copied only if pixel conversion is possible. If SkPixmap colorType() is
+        kGray_8_SkColorType, or kAlpha_8_SkColorType; dst SkColorType must match.
+        If SkPixmap colorType() is kGray_8_SkColorType, dst SkColorSpace must match.
+        If SkPixmap alphaType() is kOpaque_SkAlphaType, dst SkAlphaType must
+        match. If SkPixmap colorSpace() is nullptr, dst SkColorSpace must match. Returns
+        false if pixel conversion is not possible.
+
+        Returns false if SkBitmap width() or height() is zero or negative.
+
+        Scales the image, with filterQuality, to match dst.width() and dst.height().
+        filterQuality kNone_SkFilterQuality is fastest, typically implemented with
+        nearest neighbor filter. kLow_SkFilterQuality is typically implemented with
+        bilerp filter. kMedium_SkFilterQuality is typically implemented with
+        bilerp filter, and mip-map filter when size is reduced.
+        kHigh_SkFilterQuality is slowest, typically implemented with bicubic filter.
+
+        @param dst            SkImageInfo and pixel address to write to
+        @param filterQuality  one of: kNone_SkFilterQuality, kLow_SkFilterQuality,
+                              kMedium_SkFilterQuality, kHigh_SkFilterQuality
+        @return               true if pixels are scaled to fit dst
+    */
+    bool scalePixels(const SkPixmap& dst, SkFilterQuality filterQuality) const;
+
+    /** Writes color to pixels bounded by subset; returns true on success.
+        Returns false if colorType() is kUnknown_SkColorType, or if subset does
+        not intersect bounds().
+
+        @param color   unpremultiplied color to write
+        @param subset  bounding integer SkRect of written pixels
+        @return        true if pixels are changed
+    */
+    bool erase(SkColor color, const SkIRect& subset) const;
+
+    /** Writes color to pixels inside bounds(); returns true on success.
+        Returns false if colorType() is kUnknown_SkColorType, or if bounds()
+        is empty.
+
+        @param color  unpremultiplied color to write
+        @return       true if pixels are changed
+    */
+    bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
+
+    /** Writes color to pixels bounded by subset; returns true on success.
+        if subset is nullptr, writes colors pixels inside bounds(). Returns false if
+        colorType() is kUnknown_SkColorType, if subset is not nullptr and does
+        not intersect bounds(), or if subset is nullptr and bounds() is empty.
+
+        @param color   unpremultiplied color to write
+        @param subset  bounding integer SkRect of pixels to write; may be nullptr
+        @return        true if pixels are changed
+    */
+    bool erase(const SkColor4f& color, const SkIRect* subset = nullptr) const;
+
+private:
+    const void*     fPixels;
+    size_t          fRowBytes;
+    SkImageInfo     fInfo;
+
+    friend class SkPixmapPriv;
+};
+
+#endif

+ 45 - 0
skia/include/core/SkPngChunkReader.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkPngChunkReader_DEFINED
+#define SkPngChunkReader_DEFINED
+
+#include "SkTypes.h"
+#include "SkRefCnt.h"
+
+/**
+ *  SkPngChunkReader
+ *
+ *  Base class for optional callbacks to retrieve meta/chunk data out of a PNG
+ *  encoded image as it is being decoded.
+ *  Used by SkCodec.
+ */
+class SkPngChunkReader : public SkRefCnt {
+public:
+    /**
+     *  This will be called by the decoder when it sees an unknown chunk.
+     *
+     *  Use by SkCodec:
+     *  Depending on the location of the unknown chunks, this callback may be
+     *  called by
+     *      - the factory (NewFromStream/NewFromData)
+     *      - getPixels
+     *      - startScanlineDecode
+     *      - the first call to getScanlines/skipScanlines
+     *  The callback may be called from a different thread (e.g. if the SkCodec
+     *  is passed to another thread), and it may be called multiple times, if
+     *  the SkCodec is used multiple times.
+     *
+     *  @param tag Name for this type of chunk.
+     *  @param data Data to be interpreted by the subclass.
+     *  @param length Number of bytes of data in the chunk.
+     *  @return true to continue decoding, or false to indicate an error, which
+     *      will cause the decoder to not return the image.
+     */
+    virtual bool readChunk(const char tag[], const void* data, size_t length) = 0;
+};
+#endif // SkPngChunkReader_DEFINED

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini