From 9d22335ea093422d7bf212d31bfaa6adcb9b89f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viktor=20Chlumsk=C3=BD?= Date: Sat, 17 Oct 2020 13:12:23 +0200 Subject: [PATCH] Skia integration - preprocessing of shape geometry --- .gitattributes | 1 + .gitignore | 20 +- CHANGELOG.md | 19 + CMakeLists.txt | 9 +- Msdfgen.aps | Bin 0 -> 35156 bytes Msdfgen.rc | Bin 3954 -> 5924 bytes Msdfgen.vcxproj | 74 +- Msdfgen.vcxproj.filters | 6 + README.md | 3 +- ext/resolve-shape-geometry.cpp | 89 + ext/resolve-shape-geometry.h | 15 + main.cpp | 74 +- msdfgen-ext.h | 5 +- msdfgen.h | 4 +- skia/LICENSE | 29 + .../include/android/SkAndroidFrameworkUtils.h | 40 + skia/include/android/SkAnimatedImage.h | 154 + skia/include/android/SkBRDAllocator.h | 29 + skia/include/android/SkBitmapRegionDecoder.h | 92 + skia/include/atlastext/SkAtlasTextContext.h | 42 + skia/include/atlastext/SkAtlasTextFont.h | 35 + skia/include/atlastext/SkAtlasTextRenderer.h | 72 + skia/include/atlastext/SkAtlasTextTarget.h | 100 + skia/include/c/sk_canvas.h | 159 + skia/include/c/sk_colorspace.h | 25 + skia/include/c/sk_data.h | 70 + skia/include/c/sk_image.h | 71 + skia/include/c/sk_imageinfo.h | 62 + skia/include/c/sk_maskfilter.h | 47 + skia/include/c/sk_matrix.h | 49 + skia/include/c/sk_paint.h | 145 + skia/include/c/sk_path.h | 84 + skia/include/c/sk_picture.h | 70 + skia/include/c/sk_shader.h | 143 + skia/include/c/sk_surface.h | 73 + skia/include/c/sk_types.h | 256 ++ skia/include/codec/SkAndroidCodec.h | 287 ++ skia/include/codec/SkCodec.h | 921 ++++++ skia/include/codec/SkCodecAnimation.h | 43 + skia/include/codec/SkEncodedOrigin.h | 23 + skia/include/config/SkUserConfig.h | 130 + skia/include/core/SkAnnotation.h | 50 + skia/include/core/SkBBHFactory.h | 31 + skia/include/core/SkBitmap.h | 1195 +++++++ skia/include/core/SkBlendMode.h | 75 + skia/include/core/SkBlurTypes.h | 22 + skia/include/core/SkCanvas.h | 2779 +++++++++++++++++ skia/include/core/SkCanvasVirtualEnforcer.h | 93 + skia/include/core/SkClipOp.h | 33 + skia/include/core/SkColor.h | 389 +++ skia/include/core/SkColorFilter.h | 196 ++ skia/include/core/SkColorPriv.h | 163 + skia/include/core/SkColorSpace.h | 237 ++ skia/include/core/SkColorSpaceXformCanvas.h | 20 + skia/include/core/SkCoverageMode.h | 30 + skia/include/core/SkData.h | 182 ++ skia/include/core/SkDataTable.h | 119 + .../core/SkDeferredDisplayListRecorder.h | 165 + skia/include/core/SkDeque.h | 139 + skia/include/core/SkDocument.h | 91 + skia/include/core/SkDrawLooper.h | 129 + skia/include/core/SkDrawable.h | 150 + skia/include/core/SkEncodedImageFormat.h | 34 + skia/include/core/SkExecutor.h | 33 + skia/include/core/SkFilterQuality.h | 26 + skia/include/core/SkFlattenable.h | 107 + skia/include/core/SkFont.h | 488 +++ skia/include/core/SkFontArguments.h | 79 + skia/include/core/SkFontLCDConfig.h | 58 + skia/include/core/SkFontMetrics.h | 106 + skia/include/core/SkFontMgr.h | 163 + skia/include/core/SkFontParameters.h | 38 + skia/include/core/SkFontStyle.h | 80 + skia/include/core/SkFontTypes.h | 49 + skia/include/core/SkGraphics.h | 185 ++ skia/include/core/SkICC.h | 23 + skia/include/core/SkImage.h | 1026 ++++++ skia/include/core/SkImageEncoder.h | 68 + skia/include/core/SkImageFilter.h | 479 +++ skia/include/core/SkImageGenerator.h | 207 ++ skia/include/core/SkImageInfo.h | 623 ++++ skia/include/core/SkLights.h | 195 ++ skia/include/core/SkMallocPixelRef.h | 93 + skia/include/core/SkMaskFilter.h | 77 + skia/include/core/SkMath.h | 75 + skia/include/core/SkMatrix.h | 1863 +++++++++++ skia/include/core/SkMatrix44.h | 495 +++ skia/include/core/SkMetaData.h | 175 ++ skia/include/core/SkMilestone.h | 9 + skia/include/core/SkMultiPictureDraw.h | 75 + skia/include/core/SkOverdrawCanvas.h | 74 + skia/include/core/SkPaint.h | 1427 +++++++++ skia/include/core/SkPath.h | 1779 +++++++++++ skia/include/core/SkPathEffect.h | 187 ++ skia/include/core/SkPathMeasure.h | 125 + skia/include/core/SkPicture.h | 284 ++ skia/include/core/SkPictureRecorder.h | 125 + skia/include/core/SkPixelRef.h | 129 + skia/include/core/SkPixmap.h | 706 +++++ skia/include/core/SkPngChunkReader.h | 45 + skia/include/core/SkPoint.h | 562 ++++ skia/include/core/SkPoint3.h | 157 + skia/include/core/SkPostConfig.h | 309 ++ skia/include/core/SkPreConfig.h | 200 ++ skia/include/core/SkRRect.h | 529 ++++ skia/include/core/SkRSXform.h | 69 + skia/include/core/SkRWBuffer.h | 111 + skia/include/core/SkRasterHandleAllocator.h | 87 + skia/include/core/SkRect.h | 1560 +++++++++ skia/include/core/SkRefCnt.h | 414 +++ skia/include/core/SkRegion.h | 679 ++++ skia/include/core/SkScalar.h | 205 ++ skia/include/core/SkSerialProcs.h | 73 + skia/include/core/SkShader.h | 276 ++ skia/include/core/SkSize.h | 92 + skia/include/core/SkStream.h | 515 +++ skia/include/core/SkString.h | 299 ++ skia/include/core/SkStrokeRec.h | 154 + skia/include/core/SkSurface.h | 755 +++++ skia/include/core/SkSurfaceCharacterization.h | 186 ++ skia/include/core/SkSurfaceProps.h | 86 + skia/include/core/SkSwizzle.h | 19 + skia/include/core/SkTLazy.h | 209 ++ skia/include/core/SkTextBlob.h | 349 +++ skia/include/core/SkTime.h | 62 + skia/include/core/SkTraceMemoryDump.h | 90 + skia/include/core/SkTypeface.h | 450 +++ skia/include/core/SkTypes.h | 228 ++ skia/include/core/SkUnPreMultiply.h | 56 + skia/include/core/SkVertices.h | 281 ++ skia/include/core/SkYUVAIndex.h | 92 + skia/include/core/SkYUVASizeInfo.h | 61 + skia/include/docs/SkPDFDocument.h | 176 ++ skia/include/docs/SkXPSDocument.h | 27 + skia/include/effects/Sk1DPathEffect.h | 77 + skia/include/effects/Sk2DPathEffect.h | 105 + skia/include/effects/SkAlphaThresholdFilter.h | 32 + .../include/effects/SkArithmeticImageFilter.h | 35 + skia/include/effects/SkBlurDrawLooper.h | 22 + skia/include/effects/SkBlurImageFilter.h | 33 + skia/include/effects/SkBlurMaskFilter.h | 35 + .../effects/SkColorFilterImageFilter.h | 41 + skia/include/effects/SkColorMatrix.h | 66 + skia/include/effects/SkColorMatrixFilter.h | 25 + skia/include/effects/SkComposeImageFilter.h | 38 + skia/include/effects/SkCornerPathEffect.h | 43 + skia/include/effects/SkDashPathEffect.h | 39 + skia/include/effects/SkDiscretePathEffect.h | 53 + .../include/effects/SkDisplacementMapEffect.h | 63 + .../include/effects/SkDropShadowImageFilter.h | 56 + skia/include/effects/SkGradientShader.h | 259 ++ skia/include/effects/SkHighContrastFilter.h | 84 + skia/include/effects/SkImageSource.h | 51 + skia/include/effects/SkLayerDrawLooper.h | 151 + skia/include/effects/SkLightingImageFilter.h | 62 + skia/include/effects/SkLumaColorFilter.h | 52 + skia/include/effects/SkMagnifierImageFilter.h | 41 + .../effects/SkMatrixConvolutionImageFilter.h | 127 + skia/include/effects/SkMergeImageFilter.h | 43 + .../include/effects/SkMorphologyImageFilter.h | 99 + skia/include/effects/SkOffsetImageFilter.h | 41 + skia/include/effects/SkOpPathEffect.h | 38 + skia/include/effects/SkOverdrawColorFilter.h | 54 + skia/include/effects/SkPaintImageFilter.h | 46 + skia/include/effects/SkPerlinNoiseShader.h | 60 + skia/include/effects/SkPictureImageFilter.h | 57 + skia/include/effects/SkShaderMaskFilter.h | 24 + skia/include/effects/SkTableColorFilter.h | 42 + skia/include/effects/SkTableMaskFilter.h | 37 + skia/include/effects/SkTileImageFilter.h | 50 + skia/include/effects/SkToSRGBColorFilter.h | 43 + skia/include/effects/SkTrimPathEffect.h | 41 + skia/include/effects/SkXfermodeImageFilter.h | 34 + skia/include/encode/SkEncoder.h | 42 + skia/include/encode/SkJpegEncoder.h | 97 + skia/include/encode/SkPngEncoder.h | 99 + skia/include/encode/SkWebpEncoder.h | 48 + skia/include/gpu/GrBackendDrawableInfo.h | 44 + skia/include/gpu/GrBackendSemaphore.h | 66 + skia/include/gpu/GrBackendSurface.h | 367 +++ skia/include/gpu/GrBlend.h | 151 + skia/include/gpu/GrConfig.h | 176 ++ skia/include/gpu/GrContext.h | 436 +++ skia/include/gpu/GrContextOptions.h | 259 ++ skia/include/gpu/GrDriverBugWorkarounds.h | 51 + .../gpu/GrDriverBugWorkaroundsAutogen.h | 43 + skia/include/gpu/GrGpuResource.h | 358 +++ skia/include/gpu/GrRenderTarget.h | 136 + skia/include/gpu/GrResourceKey.h | 363 +++ skia/include/gpu/GrSamplerState.h | 69 + skia/include/gpu/GrSurface.h | 123 + skia/include/gpu/GrTexture.h | 86 + skia/include/gpu/GrTypes.h | 271 ++ skia/include/gpu/gl/GrGLAssembleInterface.h | 32 + skia/include/gpu/gl/GrGLConfig.h | 129 + skia/include/gpu/gl/GrGLConfig_chrome.h | 36 + skia/include/gpu/gl/GrGLExtensions.h | 78 + skia/include/gpu/gl/GrGLFunctions.h | 323 ++ skia/include/gpu/gl/GrGLInterface.h | 349 +++ skia/include/gpu/gl/GrGLTypes.h | 126 + skia/include/gpu/mock/GrMockTypes.h | 75 + skia/include/gpu/mtl/GrMtlTypes.h | 32 + skia/include/gpu/vk/GrVkBackendContext.h | 70 + skia/include/gpu/vk/GrVkExtensions.h | 63 + skia/include/gpu/vk/GrVkMemoryAllocator.h | 88 + skia/include/gpu/vk/GrVkTypes.h | 153 + skia/include/pathops/SkPathOps.h | 113 + skia/include/ports/SkFontConfigInterface.h | 115 + .../ports/SkFontMgr_FontConfigInterface.h | 20 + skia/include/ports/SkFontMgr_android.h | 45 + skia/include/ports/SkFontMgr_directory.h | 21 + skia/include/ports/SkFontMgr_empty.h | 21 + skia/include/ports/SkFontMgr_fontconfig.h | 22 + skia/include/ports/SkFontMgr_indirect.h | 99 + skia/include/ports/SkImageGeneratorCG.h | 20 + skia/include/ports/SkImageGeneratorWIC.h | 35 + skia/include/ports/SkRemotableFontMgr.h | 139 + skia/include/ports/SkTypeface_mac.h | 49 + skia/include/ports/SkTypeface_win.h | 71 + skia/include/private/GrAuditTrail.h | 183 ++ skia/include/private/GrCCClipPath.h | 81 + skia/include/private/GrCCPerOpListPaths.h | 32 + skia/include/private/GrColor.h | 108 + skia/include/private/GrOpList.h | 189 ++ skia/include/private/GrProxyRef.h | 151 + skia/include/private/GrRenderTargetProxy.h | 133 + skia/include/private/GrSharedEnums.h | 37 + skia/include/private/GrSingleOwner.h | 55 + skia/include/private/GrSkSLFPFactoryCache.h | 37 + skia/include/private/GrSurfaceProxy.h | 526 ++++ skia/include/private/GrTextureProxy.h | 145 + skia/include/private/GrTypesPriv.h | 1390 +++++++++ skia/include/private/GrVkTypesPriv.h | 49 + skia/include/private/SkArenaAlloc.h | 240 ++ skia/include/private/SkAtomics.h | 126 + skia/include/private/SkBitmaskEnum.h | 34 + skia/include/private/SkChecksum.h | 71 + skia/include/private/SkColorData.h | 444 +++ skia/include/private/SkDeferredDisplayList.h | 75 + skia/include/private/SkEncodedInfo.h | 249 ++ skia/include/private/SkFixed.h | 140 + skia/include/private/SkFloatBits.h | 91 + skia/include/private/SkFloatingPoint.h | 221 ++ skia/include/private/SkHalf.h | 85 + skia/include/private/SkImageInfoPriv.h | 119 + skia/include/private/SkLeanWindows.h | 34 + skia/include/private/SkMacros.h | 67 + skia/include/private/SkMalloc.h | 127 + skia/include/private/SkMessageBus.h | 125 + skia/include/private/SkMutex.h | 94 + skia/include/private/SkNoncopyable.h | 30 + skia/include/private/SkNx.h | 434 +++ skia/include/private/SkNx_neon.h | 734 +++++ skia/include/private/SkNx_sse.h | 819 +++++ skia/include/private/SkOnce.h | 51 + skia/include/private/SkPathRef.h | 582 ++++ skia/include/private/SkSafe32.h | 34 + skia/include/private/SkSafe_math.h | 52 + skia/include/private/SkSemaphore.h | 86 + skia/include/private/SkShadowFlags.h | 23 + skia/include/private/SkSpinlock.h | 47 + skia/include/private/SkTArray.h | 637 ++++ skia/include/private/SkTDArray.h | 372 +++ skia/include/private/SkTFitsIn.h | 74 + skia/include/private/SkTHash.h | 350 +++ skia/include/private/SkTInternalLList.h | 319 ++ skia/include/private/SkTLogic.h | 126 + skia/include/private/SkTSearch.h | 146 + skia/include/private/SkTemplates.h | 449 +++ skia/include/private/SkThreadID.h | 19 + skia/include/private/SkTo.h | 28 + skia/include/private/SkWeakRefCnt.h | 170 + skia/include/svg/SkSVGCanvas.h | 35 + skia/include/utils/Sk3D.h | 19 + skia/include/utils/SkAnimCodecPlayer.h | 60 + skia/include/utils/SkBase64.h | 39 + skia/include/utils/SkCamera.h | 154 + skia/include/utils/SkCanvasStateUtils.h | 78 + skia/include/utils/SkEventTracer.h | 74 + skia/include/utils/SkFrontBufferedStream.h | 39 + skia/include/utils/SkInterpolator.h | 138 + skia/include/utils/SkLua.h | 69 + skia/include/utils/SkLuaCanvas.h | 79 + skia/include/utils/SkNWayCanvas.h | 97 + skia/include/utils/SkNoDrawCanvas.h | 89 + skia/include/utils/SkNullCanvas.h | 18 + skia/include/utils/SkPaintFilterCanvas.h | 129 + skia/include/utils/SkParse.h | 32 + skia/include/utils/SkParsePath.h | 23 + skia/include/utils/SkRandom.h | 169 + skia/include/utils/SkShadowUtils.h | 56 + skia/include/utils/SkTextUtils.h | 37 + skia/include/utils/SkTraceEventPhase.h | 19 + skia/include/utils/mac/SkCGUtils.h | 86 + 294 files changed, 51516 insertions(+), 57 deletions(-) create mode 100644 Msdfgen.aps create mode 100644 ext/resolve-shape-geometry.cpp create mode 100644 ext/resolve-shape-geometry.h create mode 100644 skia/LICENSE create mode 100644 skia/include/android/SkAndroidFrameworkUtils.h create mode 100644 skia/include/android/SkAnimatedImage.h create mode 100644 skia/include/android/SkBRDAllocator.h create mode 100644 skia/include/android/SkBitmapRegionDecoder.h create mode 100644 skia/include/atlastext/SkAtlasTextContext.h create mode 100644 skia/include/atlastext/SkAtlasTextFont.h create mode 100644 skia/include/atlastext/SkAtlasTextRenderer.h create mode 100644 skia/include/atlastext/SkAtlasTextTarget.h create mode 100644 skia/include/c/sk_canvas.h create mode 100644 skia/include/c/sk_colorspace.h create mode 100644 skia/include/c/sk_data.h create mode 100644 skia/include/c/sk_image.h create mode 100644 skia/include/c/sk_imageinfo.h create mode 100644 skia/include/c/sk_maskfilter.h create mode 100644 skia/include/c/sk_matrix.h create mode 100644 skia/include/c/sk_paint.h create mode 100644 skia/include/c/sk_path.h create mode 100644 skia/include/c/sk_picture.h create mode 100644 skia/include/c/sk_shader.h create mode 100644 skia/include/c/sk_surface.h create mode 100644 skia/include/c/sk_types.h create mode 100644 skia/include/codec/SkAndroidCodec.h create mode 100644 skia/include/codec/SkCodec.h create mode 100644 skia/include/codec/SkCodecAnimation.h create mode 100644 skia/include/codec/SkEncodedOrigin.h create mode 100644 skia/include/config/SkUserConfig.h create mode 100644 skia/include/core/SkAnnotation.h create mode 100644 skia/include/core/SkBBHFactory.h create mode 100644 skia/include/core/SkBitmap.h create mode 100644 skia/include/core/SkBlendMode.h create mode 100644 skia/include/core/SkBlurTypes.h create mode 100644 skia/include/core/SkCanvas.h create mode 100644 skia/include/core/SkCanvasVirtualEnforcer.h create mode 100644 skia/include/core/SkClipOp.h create mode 100644 skia/include/core/SkColor.h create mode 100644 skia/include/core/SkColorFilter.h create mode 100644 skia/include/core/SkColorPriv.h create mode 100644 skia/include/core/SkColorSpace.h create mode 100644 skia/include/core/SkColorSpaceXformCanvas.h create mode 100644 skia/include/core/SkCoverageMode.h create mode 100644 skia/include/core/SkData.h create mode 100644 skia/include/core/SkDataTable.h create mode 100644 skia/include/core/SkDeferredDisplayListRecorder.h create mode 100644 skia/include/core/SkDeque.h create mode 100644 skia/include/core/SkDocument.h create mode 100644 skia/include/core/SkDrawLooper.h create mode 100644 skia/include/core/SkDrawable.h create mode 100644 skia/include/core/SkEncodedImageFormat.h create mode 100644 skia/include/core/SkExecutor.h create mode 100644 skia/include/core/SkFilterQuality.h create mode 100644 skia/include/core/SkFlattenable.h create mode 100644 skia/include/core/SkFont.h create mode 100644 skia/include/core/SkFontArguments.h create mode 100644 skia/include/core/SkFontLCDConfig.h create mode 100644 skia/include/core/SkFontMetrics.h create mode 100644 skia/include/core/SkFontMgr.h create mode 100644 skia/include/core/SkFontParameters.h create mode 100644 skia/include/core/SkFontStyle.h create mode 100644 skia/include/core/SkFontTypes.h create mode 100644 skia/include/core/SkGraphics.h create mode 100644 skia/include/core/SkICC.h create mode 100644 skia/include/core/SkImage.h create mode 100644 skia/include/core/SkImageEncoder.h create mode 100644 skia/include/core/SkImageFilter.h create mode 100644 skia/include/core/SkImageGenerator.h create mode 100644 skia/include/core/SkImageInfo.h create mode 100644 skia/include/core/SkLights.h create mode 100644 skia/include/core/SkMallocPixelRef.h create mode 100644 skia/include/core/SkMaskFilter.h create mode 100644 skia/include/core/SkMath.h create mode 100644 skia/include/core/SkMatrix.h create mode 100644 skia/include/core/SkMatrix44.h create mode 100644 skia/include/core/SkMetaData.h create mode 100644 skia/include/core/SkMilestone.h create mode 100644 skia/include/core/SkMultiPictureDraw.h create mode 100644 skia/include/core/SkOverdrawCanvas.h create mode 100644 skia/include/core/SkPaint.h create mode 100644 skia/include/core/SkPath.h create mode 100644 skia/include/core/SkPathEffect.h create mode 100644 skia/include/core/SkPathMeasure.h create mode 100644 skia/include/core/SkPicture.h create mode 100644 skia/include/core/SkPictureRecorder.h create mode 100644 skia/include/core/SkPixelRef.h create mode 100644 skia/include/core/SkPixmap.h create mode 100644 skia/include/core/SkPngChunkReader.h create mode 100644 skia/include/core/SkPoint.h create mode 100644 skia/include/core/SkPoint3.h create mode 100644 skia/include/core/SkPostConfig.h create mode 100644 skia/include/core/SkPreConfig.h create mode 100644 skia/include/core/SkRRect.h create mode 100644 skia/include/core/SkRSXform.h create mode 100644 skia/include/core/SkRWBuffer.h create mode 100644 skia/include/core/SkRasterHandleAllocator.h create mode 100644 skia/include/core/SkRect.h create mode 100644 skia/include/core/SkRefCnt.h create mode 100644 skia/include/core/SkRegion.h create mode 100644 skia/include/core/SkScalar.h create mode 100644 skia/include/core/SkSerialProcs.h create mode 100644 skia/include/core/SkShader.h create mode 100644 skia/include/core/SkSize.h create mode 100644 skia/include/core/SkStream.h create mode 100644 skia/include/core/SkString.h create mode 100644 skia/include/core/SkStrokeRec.h create mode 100644 skia/include/core/SkSurface.h create mode 100644 skia/include/core/SkSurfaceCharacterization.h create mode 100644 skia/include/core/SkSurfaceProps.h create mode 100644 skia/include/core/SkSwizzle.h create mode 100644 skia/include/core/SkTLazy.h create mode 100644 skia/include/core/SkTextBlob.h create mode 100644 skia/include/core/SkTime.h create mode 100644 skia/include/core/SkTraceMemoryDump.h create mode 100644 skia/include/core/SkTypeface.h create mode 100644 skia/include/core/SkTypes.h create mode 100644 skia/include/core/SkUnPreMultiply.h create mode 100644 skia/include/core/SkVertices.h create mode 100644 skia/include/core/SkYUVAIndex.h create mode 100644 skia/include/core/SkYUVASizeInfo.h create mode 100644 skia/include/docs/SkPDFDocument.h create mode 100644 skia/include/docs/SkXPSDocument.h create mode 100644 skia/include/effects/Sk1DPathEffect.h create mode 100644 skia/include/effects/Sk2DPathEffect.h create mode 100644 skia/include/effects/SkAlphaThresholdFilter.h create mode 100644 skia/include/effects/SkArithmeticImageFilter.h create mode 100644 skia/include/effects/SkBlurDrawLooper.h create mode 100644 skia/include/effects/SkBlurImageFilter.h create mode 100644 skia/include/effects/SkBlurMaskFilter.h create mode 100644 skia/include/effects/SkColorFilterImageFilter.h create mode 100644 skia/include/effects/SkColorMatrix.h create mode 100644 skia/include/effects/SkColorMatrixFilter.h create mode 100644 skia/include/effects/SkComposeImageFilter.h create mode 100644 skia/include/effects/SkCornerPathEffect.h create mode 100644 skia/include/effects/SkDashPathEffect.h create mode 100644 skia/include/effects/SkDiscretePathEffect.h create mode 100644 skia/include/effects/SkDisplacementMapEffect.h create mode 100644 skia/include/effects/SkDropShadowImageFilter.h create mode 100644 skia/include/effects/SkGradientShader.h create mode 100644 skia/include/effects/SkHighContrastFilter.h create mode 100644 skia/include/effects/SkImageSource.h create mode 100644 skia/include/effects/SkLayerDrawLooper.h create mode 100644 skia/include/effects/SkLightingImageFilter.h create mode 100644 skia/include/effects/SkLumaColorFilter.h create mode 100644 skia/include/effects/SkMagnifierImageFilter.h create mode 100644 skia/include/effects/SkMatrixConvolutionImageFilter.h create mode 100644 skia/include/effects/SkMergeImageFilter.h create mode 100644 skia/include/effects/SkMorphologyImageFilter.h create mode 100644 skia/include/effects/SkOffsetImageFilter.h create mode 100644 skia/include/effects/SkOpPathEffect.h create mode 100644 skia/include/effects/SkOverdrawColorFilter.h create mode 100644 skia/include/effects/SkPaintImageFilter.h create mode 100644 skia/include/effects/SkPerlinNoiseShader.h create mode 100644 skia/include/effects/SkPictureImageFilter.h create mode 100644 skia/include/effects/SkShaderMaskFilter.h create mode 100644 skia/include/effects/SkTableColorFilter.h create mode 100644 skia/include/effects/SkTableMaskFilter.h create mode 100644 skia/include/effects/SkTileImageFilter.h create mode 100644 skia/include/effects/SkToSRGBColorFilter.h create mode 100644 skia/include/effects/SkTrimPathEffect.h create mode 100644 skia/include/effects/SkXfermodeImageFilter.h create mode 100644 skia/include/encode/SkEncoder.h create mode 100644 skia/include/encode/SkJpegEncoder.h create mode 100644 skia/include/encode/SkPngEncoder.h create mode 100644 skia/include/encode/SkWebpEncoder.h create mode 100644 skia/include/gpu/GrBackendDrawableInfo.h create mode 100644 skia/include/gpu/GrBackendSemaphore.h create mode 100644 skia/include/gpu/GrBackendSurface.h create mode 100644 skia/include/gpu/GrBlend.h create mode 100644 skia/include/gpu/GrConfig.h create mode 100644 skia/include/gpu/GrContext.h create mode 100644 skia/include/gpu/GrContextOptions.h create mode 100644 skia/include/gpu/GrDriverBugWorkarounds.h create mode 100644 skia/include/gpu/GrDriverBugWorkaroundsAutogen.h create mode 100644 skia/include/gpu/GrGpuResource.h create mode 100644 skia/include/gpu/GrRenderTarget.h create mode 100644 skia/include/gpu/GrResourceKey.h create mode 100644 skia/include/gpu/GrSamplerState.h create mode 100644 skia/include/gpu/GrSurface.h create mode 100644 skia/include/gpu/GrTexture.h create mode 100644 skia/include/gpu/GrTypes.h create mode 100644 skia/include/gpu/gl/GrGLAssembleInterface.h create mode 100644 skia/include/gpu/gl/GrGLConfig.h create mode 100644 skia/include/gpu/gl/GrGLConfig_chrome.h create mode 100644 skia/include/gpu/gl/GrGLExtensions.h create mode 100644 skia/include/gpu/gl/GrGLFunctions.h create mode 100644 skia/include/gpu/gl/GrGLInterface.h create mode 100644 skia/include/gpu/gl/GrGLTypes.h create mode 100644 skia/include/gpu/mock/GrMockTypes.h create mode 100644 skia/include/gpu/mtl/GrMtlTypes.h create mode 100644 skia/include/gpu/vk/GrVkBackendContext.h create mode 100644 skia/include/gpu/vk/GrVkExtensions.h create mode 100644 skia/include/gpu/vk/GrVkMemoryAllocator.h create mode 100644 skia/include/gpu/vk/GrVkTypes.h create mode 100644 skia/include/pathops/SkPathOps.h create mode 100644 skia/include/ports/SkFontConfigInterface.h create mode 100644 skia/include/ports/SkFontMgr_FontConfigInterface.h create mode 100644 skia/include/ports/SkFontMgr_android.h create mode 100644 skia/include/ports/SkFontMgr_directory.h create mode 100644 skia/include/ports/SkFontMgr_empty.h create mode 100644 skia/include/ports/SkFontMgr_fontconfig.h create mode 100644 skia/include/ports/SkFontMgr_indirect.h create mode 100644 skia/include/ports/SkImageGeneratorCG.h create mode 100644 skia/include/ports/SkImageGeneratorWIC.h create mode 100644 skia/include/ports/SkRemotableFontMgr.h create mode 100644 skia/include/ports/SkTypeface_mac.h create mode 100644 skia/include/ports/SkTypeface_win.h create mode 100644 skia/include/private/GrAuditTrail.h create mode 100644 skia/include/private/GrCCClipPath.h create mode 100644 skia/include/private/GrCCPerOpListPaths.h create mode 100644 skia/include/private/GrColor.h create mode 100644 skia/include/private/GrOpList.h create mode 100644 skia/include/private/GrProxyRef.h create mode 100644 skia/include/private/GrRenderTargetProxy.h create mode 100644 skia/include/private/GrSharedEnums.h create mode 100644 skia/include/private/GrSingleOwner.h create mode 100644 skia/include/private/GrSkSLFPFactoryCache.h create mode 100644 skia/include/private/GrSurfaceProxy.h create mode 100644 skia/include/private/GrTextureProxy.h create mode 100644 skia/include/private/GrTypesPriv.h create mode 100644 skia/include/private/GrVkTypesPriv.h create mode 100644 skia/include/private/SkArenaAlloc.h create mode 100644 skia/include/private/SkAtomics.h create mode 100644 skia/include/private/SkBitmaskEnum.h create mode 100644 skia/include/private/SkChecksum.h create mode 100644 skia/include/private/SkColorData.h create mode 100644 skia/include/private/SkDeferredDisplayList.h create mode 100644 skia/include/private/SkEncodedInfo.h create mode 100644 skia/include/private/SkFixed.h create mode 100644 skia/include/private/SkFloatBits.h create mode 100644 skia/include/private/SkFloatingPoint.h create mode 100644 skia/include/private/SkHalf.h create mode 100644 skia/include/private/SkImageInfoPriv.h create mode 100644 skia/include/private/SkLeanWindows.h create mode 100644 skia/include/private/SkMacros.h create mode 100644 skia/include/private/SkMalloc.h create mode 100644 skia/include/private/SkMessageBus.h create mode 100644 skia/include/private/SkMutex.h create mode 100644 skia/include/private/SkNoncopyable.h create mode 100644 skia/include/private/SkNx.h create mode 100644 skia/include/private/SkNx_neon.h create mode 100644 skia/include/private/SkNx_sse.h create mode 100644 skia/include/private/SkOnce.h create mode 100644 skia/include/private/SkPathRef.h create mode 100644 skia/include/private/SkSafe32.h create mode 100644 skia/include/private/SkSafe_math.h create mode 100644 skia/include/private/SkSemaphore.h create mode 100644 skia/include/private/SkShadowFlags.h create mode 100644 skia/include/private/SkSpinlock.h create mode 100644 skia/include/private/SkTArray.h create mode 100644 skia/include/private/SkTDArray.h create mode 100644 skia/include/private/SkTFitsIn.h create mode 100644 skia/include/private/SkTHash.h create mode 100644 skia/include/private/SkTInternalLList.h create mode 100644 skia/include/private/SkTLogic.h create mode 100644 skia/include/private/SkTSearch.h create mode 100644 skia/include/private/SkTemplates.h create mode 100644 skia/include/private/SkThreadID.h create mode 100644 skia/include/private/SkTo.h create mode 100644 skia/include/private/SkWeakRefCnt.h create mode 100644 skia/include/svg/SkSVGCanvas.h create mode 100644 skia/include/utils/Sk3D.h create mode 100644 skia/include/utils/SkAnimCodecPlayer.h create mode 100644 skia/include/utils/SkBase64.h create mode 100644 skia/include/utils/SkCamera.h create mode 100644 skia/include/utils/SkCanvasStateUtils.h create mode 100644 skia/include/utils/SkEventTracer.h create mode 100644 skia/include/utils/SkFrontBufferedStream.h create mode 100644 skia/include/utils/SkInterpolator.h create mode 100644 skia/include/utils/SkLua.h create mode 100644 skia/include/utils/SkLuaCanvas.h create mode 100644 skia/include/utils/SkNWayCanvas.h create mode 100644 skia/include/utils/SkNoDrawCanvas.h create mode 100644 skia/include/utils/SkNullCanvas.h create mode 100644 skia/include/utils/SkPaintFilterCanvas.h create mode 100644 skia/include/utils/SkParse.h create mode 100644 skia/include/utils/SkParsePath.h create mode 100644 skia/include/utils/SkRandom.h create mode 100644 skia/include/utils/SkShadowUtils.h create mode 100644 skia/include/utils/SkTextUtils.h create mode 100644 skia/include/utils/SkTraceEventPhase.h create mode 100644 skia/include/utils/mac/SkCGUtils.h diff --git a/.gitattributes b/.gitattributes index 1c6eae04..3fc77eb7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ include/** linguist-vendored lib/** linguist-vendored freetype/** linguist-vendored +skia/** linguist-vendored diff --git a/.gitignore b/.gitignore index cebfdda8..e79bade8 100644 --- a/.gitignore +++ b/.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/ *.exe *.zip @@ -17,9 +17,11 @@ x64/ *.suo *.VC.opendb *.VC.db -bin/*.lib +/bin/*.lib output.png render.png out/ build/ build_xcode/ +skia/win32/ +skia/win64/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 18dcfdb4..9b1b46f6 100644 --- a/CHANGELOG.md +++ b/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) - Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel diff --git a/CMakeLists.txt b/CMakeLists.txt index c75631fe..8422328e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,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_USE_OPENMP "Build with OpenMP support for multithreaded code" OFF) 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_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) 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::msdfgen-ext ALIAS msdfgen-ext) set_target_properties(msdfgen-ext PROPERTIES diff --git a/Msdfgen.aps b/Msdfgen.aps new file mode 100644 index 0000000000000000000000000000000000000000..d85fd23a432fb061ce792a3f31b896a9cb3c527c GIT binary patch literal 35156 zcmeHQ32;=!*8U>F07i%kQoLUwkL9r?Az@#Im`o%P5==q_351Y@&5&S102LLbM9?bB zrNkZeX$d}kO1a>MmgNeFAZWSqV^L~}LRs<@OG@EC|M~jn-kD_PW+q`K5MC}h+`ip? z)?RMk?$bR05U(I&fd=bb-Sw%r!bDtwOZ6@iRh!;6x;B6>*8pjw3)9P%6)vtWoj1R% zqHv0JPpT@>Ous7BrLoPRCZl~jo5tTw;P0p^tFEl6Dk)1^0A-Y!o>`QcmXn==l;jk& z1&UIq<`rdorso&sdh&9n<)(Rx3R1JCc{F`6&hbr8%b7AIH9NgFd1!L75{RvvAv-@e zC(FUt^mBdF^JYx(*y!Zm5wL|^zOX{&G$KY7r8X zpPHYUhJJ}D{gH?$gUkQFQ%hUdMS81im+dCO*DfL*)#hbtsf8#(B`S~vD+Da}!{6bD zpRcyc%udUimaaB3slAn+Z|vZJu|u5Ll%dA>-lA|X>hY?M2m#M2eqG%LX?X(4ao&29 zhS4ZQI?Aw2?~755Qq04AeXh{wD!o^$#x)u$(QpzLD87X=RpTl(XBCPSFCH0clX8o^5Yw)Z6#;2Vrxo$ z0vZ{m@ohCrT55KhCkum_Ei*m!(wy9U46z<^J^8saFw}a;yevB>*Mni!(+p3Z8q}a< z=U{{tO3TX0^Qaw7^h8hARE)C1zD-tRq7d!VZ0olwHCcmgx=y$OJuNiz= zW1=yT#%W)nx@w8QgX#KzCbG3|Wnr4uM~}wa{aiA<_0^|u!i7Qcts3Er-)mt-NqJ3a zS$t2s1L=8g2c^>{C@tpDw&NoU5f?-Q@ft7E#*sHJ&fBN<)3i7R=7}=@0}~V{LKpkB zrhqL@K-}u;Y9Ta0+ZDeny2{alqf&76sGw_CHyW<^_u)SIF6ujp`cC`o`|fKL{wR#n zUQlFB-!;;A%^C&;qecay5s?3DcujU=w;Wn~NY)-YB-p)M@Y-u3;TNLN@O}=@$q(&+ zkoG_PpdIpamJEf3^=bI=--mtj3SN=F@R!WTe8GH$zy1=u@`_;Jz6SAczzuQ)M`Rne z$$NOuoA*5pZ`&p~azt>$4c>U0yVjj}#LEeskcWCbB(hWgc6t<03mR4%_Il_c!HE-s z_;{O!O+g;(_L%JJwO5vv^^{GUu2euhxKhfN^^{)w_DZ+M9;<`jqel;=&TF88DXj+X z%p*b^o4MYlQ>RV}yoUmv>hLFi6TwG>rUg}BtkQ10DL~v!+R4OIc+(GA{a*cki0Km) z?0#q!JEqpl%>qrW3r)qVFGo}9G!?JK^S}T8`-Py2GzCsd|1lUNGSmDC#*Arp{;%V8 z`3#>4K2v!8^=9Qi3$sjjU4t4yjRJe^S+g1|LzC^lAN%DEydiw&g74Nh-Vp5H-z@xZ z#EnMxnV2bad(M@fbLR?X&a`ZBZpqNI zXQ(nXnm_p-#6g*YDUydg*}ZYMY~&azFHbOKis0Zu0p$p-JvNGeI?|2qx8hb|{ac51 zBB|z2ux_1I|8Bk2vO#)!C^9sPKgU%c<73H3zGNXwe!@@kC>|9&s_@fKf~+h-e!k%2 zj|Cie1-C)S{O4hw(Y*o{rre*v6LK8Kr3ZQlI37BFT=2vbRz0Ywuxv1IUN9L#;@=+a zg3WNz~gnM^OF)p<_-}>_I$e^j?N#=9z6@k?Vrp z2P|7=)x`%Nv}`hPVBLIPyrBG_!839I2P6kMl8apV9G}apc-4)b;8jig{BuEWt{^8z zaNvO8nP=ScH^`rDoC>VMDx>?Io$eIrCNi?yNa@xMfnlVkX+7w4=be@fR;{vZz`nt& zw;gVfKik>|_&`|ZlQ2n+?mwcG*Rz%df%UTgsDAHEnq<|54?eKkWFz=jqSCP8cUXD9 zBJqqLAPW{G$kL?<37B`hXMpr8FS5SlC~;+_t+#y-sQ>vmUw*+a^6%(PlG|^9%$n6k z3JW{Pj2UPY5Qn(^atBECzc&ef`9*O4`8IFf>t81AuG{XC!&?r@?wv96$tMU4?A#qA zTMi$T+wQt6DE|!`HpqqzvlI|!Ak7Uy`KwWU^F%Tn(EhFbPnrGem&bp_vvy79dRwPN zn-grloBH_9V_0*p_2)5?wIt>!IP(~a(|Wa9Ac7W%WWOIy+HNKYCyz+dYL&nF#v6gk zv03atcI;RoD6?=wv&g^o)vfX>zb#v!{6#1dnPdJ0MfyDwUL7K8e_h9xZ}5$LicbZf zDtz;e=(2h^b%?0^H{mAp9k~Dt1Pc^&(1V+9Y7z4HLN6ox7Hp9Tm>`&-uw{#-L$6-p z(jj8@=NuV@s;v{W#8vcR72WSc&@dK6ascR&YY_mA+AaD8evW}A7_+{9c- z;5thI3d}kK{b|0!SMmkE5PYHV)mN534cFWX3IuEuTzh!-*;6V%=f_zY?#A7687`B# zm@5-8QEtcWCjJUsA-F<;egEyZ3noq!aNX{*%LI4dZN+oGyzy;0EcV}pU1pwt1V#wg z7C7fU4&&r^{4Ou!Wv^T>Yxwuy1zhvvItTmH5hJX5{$0Dg`9jy@q~*UFR~s91ZG>wE zw0#=VWFt13_+c34m1~%WSq2+73ewW7GT_<(*Gw3H_0`_Iq3Li^@^?mO<2Us#-Zl2- zSeffAT<4-d_uw9XdG66T%F1;v_Ng3Gvpn8?*YdOK+}R(;U6+%RpYl-{%1gN^KkE(G zD(Me)0WR>D!&qYevS>ukoAQ1h4qGGHG7S136|97 z<$YeFX_S@qhGROmW!5LwE5>t-5t^mfc+}p$Bd^w!FA9q z0j~ye`9As*Ukcw(^abGi$^(z_W8`~GDTW4oZ_%%j<7&Ro=)*#P(J#NW-gm+21Qfm@ z{?|eW18N|S3utGK6F6RY9?zTj1SEteJ7r7IytMW6&kH!7;FyTzV*3DGdu=dUjgtRj zTx{0jxduNTV#WBS)CT5K6+WL`7a8RKGt=UK*&OzC_>m!L#Kd>0pBSy#B zQPhQ$9)371^3&cVNS_mq(H3@HCw|pL?G^kk}~Wcl2R~Dx-ML3 zjqT{$LLFEhf!jjJ_J0d+$jR&sNpa9-`5;c$UPGb1-v{^l7dSiRaR1GW$U zG6-t_Xhh3_EPW^CZIi0`=hX9Gh^qG-ntwyXeh_tO&aXO0@^)>LEWYcaqwDJsRQ}bf zzjdjFF+NJJBs&zhLq^in;`X;kWd3 z7qy+}mabng`5i@F0>SWGdb*3+PIODxFPQv}qAr18_+d+*qiYWYm7_VqMQta#S!8L0 zHgaIk0olWO+BR*Pg=eju9YtLN%_7UqxLJ?Hz};JOhkpJH*CDM21sY{|U1!w+`bL z$-MY^a!s#mq}MgqNW7k%(U#{2aJ_WrPRj=VYp3Co%SCM`I$V4lI`mPdQuLjofAy8P zQWnH5kVy%XBti9#qhI@#S6cqo^oe3$$g}JsQwJPHT>@d{I~7xn?zF)W3^6`feDCu- zn~@idl#BEX3v-?g#{u-E8ZyM|r#*FQSY@fTr;FN7bXa+Qf=`V8^e3Xm97EY`4H&-pFD{Q>L?`TiR^RPfYORyy|#oV*R3f_4d<6c6rSI)-DWzo*|U z_egNu!*4yl^QZ{-%lYZS{c*Gb-+%lj37a={TK0~N#{OCKmEDSk@~;*qBSSLu@LJ3_YiW7#Ix0yzH+5MZsTm?QtVE2 zljwIxcXO69&x+&TJbRx5+XKhEwomWVc-o!*)0##d+5WlrkoDc(=fH6i&z$2K&E31Z z(+F-0M^TqRlW1?i22-|I;VK!6v1X47-*=hFG~YaXu*anLM}K$v{WXpH@7ZI03uR^s z_&(&`4xZ<5)m2t{-E+0v=>@ihi`q_fW9gYbo`P|og8qty*;mAUyzKu+W3k z;I!>?#Cf(SzlquZ^L@yDM=2@RJ_Xu{?}oto1&enSbqNH+_e*~pZ=15^emw3i;W??? zOUpenYzsVJ?t6SMF^KWQ_0u6n^L+okb$%S{Jon0Qjf8tZQ&X*TKdJxQZwIFp*gh_5 zJJF4z%R0`oXZ`111I}r&&*PoXkKhrL&ide|Yhd}T@}`cDJYwxB;NA}Qg}if*0qZ~0 z**4s0xW_w+x&%U|*%och_?~w@2<<9bF zJz#y{SebhY`F+r~ZDVP>sO?0DOz#%lV)WygmE0S~_Rexpb5JoFCh}*RoOHz75l<%il$9Cpsir_I_jP%=bIr^Y%V) z_IVr!@^=p6_4f{xa?^mnf582M+y~FT(B4PRaRJ8%v<2(P#*K}k?k0oAJ0r?dYvT6OdmNkp_(RTR-_P#>ei!ij zfPDn}L+Z~tgl5pc9Ob5L*JHg5Z#P_WV{>Iu>>`;OJ5`3p4wd`Yt(OzWkI3=kGZhdf zP+BLB$h!O2ORRnm#_D%rte#I3tKW(3_`SG(y=8;)@=$Ex6tqjgl}1N&l*2eIKjKI8 z9nbIixn1VUl7uBPAz^|HO6V;K3GEdSAyC?bl!uP}5_C^`7k(RXzJT)vKmI5nBZ?{QP9e%Id6u2t#MXYtr?TrCrq` zYacbo$tzY^b>NOWT;)F*{rNs8gB{pm#yac+=k^&V<+D4<;>EEF@p@)+w3L-WN=qXH zq)i^=MV__Dh`Sk^jsBd=8mII2lSg!xDN|4j zZS@}K^K8dQ>P}wdY0)1sxwD)%PT!B5Gh<)4d2>J=np*yxw)C%`t^F-rj9{<=9WZ%WwbbD!=`P(;EKsTUYt%*zdB9W5Y1$ zKSbAN-hA^-g-Qjq5TLAY3S|#q1E-)}0)cSOq&OF~o#-=3*Fd^Bin;^>;hafvE^0f` zXOgagba51Q2?WA9lj2;|cB0QDT?6UjDC!ajgmWgvxv1?#pGmp~(#28KB@hVbOp0?+ zyEVGi0<9MKZ?k|-7c_Vsu?*6w^==H&;_T31;cDU~s#d&$NJoV-qhzwr@2m6lh-h`v zvQClUud(ZC5{kexCHR}jXCXPc_DO#wsEsbmTTeWnf~Qi9)t?yB>`FUMAxcB~8}D)6 z-fIJlG{~qLOC=)sQOZ7$O_v$k=%ye_TBJX>5O$ zda!aQ#B1p`Y%$uLGUn9MW{FWo+lG9ytnVi4O4T(AQx(5bb*WKXF7?rnwysfnw0@$d zEl_%TDyV8!uF}zN^UV{jUaC*knv*$7G)KHzW}(T+RLe%RcCqGR4bVDm%Azjs`X%C9 z9_fk`r8X&6Y+FNbtps|T){}2|RH!WFhL^W&+hcR|bgjF+mCi(5VUBhY(TLj14t3XO z^77`1s?FhTgTHFb+B$i*nLNp8->x<@F4Dkbit44a-7n8_jX6*!&knyl&uPp`70yd% zkP*nYPsr0eQ?=jl=1Fw&*m^N$Tb(>fetFJOItguoeC=1J>;IWr8`88cPg9F{G|lOc z;I+kt8eiTZjwL~|4~~j~R~y7(4%QJbANHjGt2oy0$s5tNm-X74eQRk4JKf@0C%upA o_CI#IMc+4_{qNBUcDgdt%Qv0<{@B$_58Usw-+tJn2ky83AHG7t`2YX_ literal 0 HcmV?d00001 diff --git a/Msdfgen.rc b/Msdfgen.rc index 1893993edeb4fe7d5ec8fb705ece50ea7fcfeb09..5332dddc914356086463f64b6b78941221463bff 100644 GIT binary patch literal 5924 zcmdUzOK;mo5Xa|Spx=R&FA19Zk>rpZZAn%IOO|0h&=v*+$Fdb6wj@Y$8yEfRY5V){ zYE4ok(?s!s1+iRmI6FJ?s>Z6IpR&!CN>9W*S@#!*k#YnJ3yy=y#;&Za4VVhyY}8H4qGdC z9NvvvC)$U0W?k!9-)h#hjt%YH>OgBepIXa)1=8i-wj&@dp2Pm)p?p{1F3gcN(95Qd zZ_v`r?vQ_lcBF?MQvbreiPTl(ls@XfUoti=^4~W2!|B(rOY6UU8VekG@3==-@}wK& z-p)6I<^$bw&4D|`;Gf8Oh5aLYmU=q}J}08y5m$=j=Q%#GOhnYgY3qknWR0MCXvg@J zkEkxu(-t}URaK>N%M=cNH6yx)LS?Pq%d z-7Yvs?BwyaZylZvfwu5<>B3uG5)@lqF)@Ju6IR#UigMXB$xX0tn2RDieAldTfVPTq zfW99gd&6Z1y+!LQKigi|{yO8<(VW+qRw?aJ#L=rQ zIr`dtc8DnD6(1>{FIg=w$7H=ty3>Tq`3mnnZ7X11G|RU)USQz8fC*4Eh~Buun$lebI_Q{n%xV2HdsD z7hPgMg7QauMW$#u8RV65*6_LIh@BelYs_a%$x}FZTz^e|U81M7T$}j&3H;zg=@lLL z^R!>XqpsKMH8B@Gvga9EOY;za_n9({6?V>#edW~-dX;7>aInJO>c+-cXo6(d*lCJ} zW*gC%Pc6i1nyQ!Pt&`{-_jFvxYw~ha_!{N`c2r*@9aP|3{m-1fb7~Lx-6e0=z*RLW zc*?{+Akhq&R4L!P4)YFceXvgjT;%T)bWwwPvXAv~5%z1NzZ!b;{cuFh6?b=zJN3k> z!|LH8s`AQdcf$Oz6({M)3>+NLS-)Wv={R3HSy+Ahf?1vYrXHoS5kBDM+6D6?Bj1Yo zJG8(bJKD0?9GT^1V=S_Qj<;6!i|=UEU%W&j4Sxc88k=_3Jjf=JI@nlmNiX_#>Cf0{ zh6eBPh*d_rZQ!@SC-#%;`U;qLZ{_8dqnO%+5h@~DXQ!8sU<5_ z>GkCEv#4qh!9?|zOS$}kA%9dw@qb^$antq8Rl2ZKcYX`GGjDFv#RxC&TOO?P$oua4 z$=3wwyg0KxRVqhe40!(nFFP Uaaio}Q({#SoBdaqwYw<&3!2K!YybcN delta 16 XcmZ3Y_epL;4Etm$cB#!8{D0U1HBkkz diff --git a/Msdfgen.vcxproj b/Msdfgen.vcxproj index 5b6cc73c..a01daa18 100644 --- a/Msdfgen.vcxproj +++ b/Msdfgen.vcxproj @@ -231,13 +231,13 @@ Level3 Disabled true - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions) MultiThreadedDebug - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) Console - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories) @@ -245,9 +245,9 @@ Level3 Disabled true - MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions) MultiThreadedDebug - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) Console @@ -255,7 +255,7 @@ MachineX86 - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories) @@ -264,13 +264,13 @@ Level3 Disabled true - include;freetype/include;%(AdditionalIncludeDirectories) - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions) MultiThreadedDebug Console - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories) @@ -278,12 +278,12 @@ Level3 Disabled true - MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) - include;freetype/include;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) MultiThreadedDebug - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/debug;%(AdditionalLibraryDirectories) @@ -293,15 +293,15 @@ true true true - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions) MultiThreaded - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) true true Console - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) No @@ -312,16 +312,16 @@ true true true - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;MSDFGEN_STANDALONE;%(PreprocessorDefinitions) MultiThreaded - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) true true true Console - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) No @@ -332,9 +332,9 @@ true true true - MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions) MultiThreaded - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) true @@ -345,7 +345,7 @@ MachineX86 - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) @@ -355,9 +355,9 @@ true true true - MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) MultiThreaded - include;freetype/include;%(AdditionalIncludeDirectories) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) true @@ -369,7 +369,7 @@ MachineX86 - freetype/win32;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) @@ -379,15 +379,15 @@ true true true - include;freetype/include;%(AdditionalIncludeDirectories) - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;%(PreprocessorDefinitions) MultiThreaded true true Console - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) false @@ -398,8 +398,8 @@ true true true - include;freetype/include;%(AdditionalIncludeDirectories) - MSDFGEN_STANDALONE;MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_STANDALONE;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) MultiThreaded true @@ -407,7 +407,7 @@ true true Console - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) false @@ -418,8 +418,8 @@ true true true - include;freetype/include;%(AdditionalIncludeDirectories) - MSDFGEN_USE_CPP11;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;%(PreprocessorDefinitions) MultiThreaded @@ -427,7 +427,7 @@ true - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) @@ -437,8 +437,8 @@ true true true - include;freetype/include;%(AdditionalIncludeDirectories) - MSDFGEN_USE_CPP11;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) + include;freetype/include;skia/include;skia/include/core;skia/include/config;%(AdditionalIncludeDirectories) + MSDFGEN_USE_CPP11;MSDFGEN_USE_SKIA;MSDFGEN_USE_OPENMP;%(PreprocessorDefinitions) MultiThreaded true @@ -447,7 +447,7 @@ true - freetype/win64;%(AdditionalLibraryDirectories) + freetype/win$(PlatformArchitecture);skia/win$(PlatformArchitecture)/release;%(AdditionalLibraryDirectories) @@ -481,6 +481,7 @@ + @@ -508,6 +509,7 @@ + diff --git a/Msdfgen.vcxproj.filters b/Msdfgen.vcxproj.filters index 55220f71..95b8b6a1 100644 --- a/Msdfgen.vcxproj.filters +++ b/Msdfgen.vcxproj.filters @@ -120,6 +120,9 @@ Core + + Extensions + @@ -200,6 +203,9 @@ Core + + Extensions + diff --git a/README.md b/README.md index e17091fa..958f2628 100644 --- a/README.md +++ b/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 [FreeType](http://www.freetype.org/), [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 a comprehensive standalone console program. To start using the program immediately, diff --git a/ext/resolve-shape-geometry.cpp b/ext/resolve-shape-geometry.cpp new file mode 100644 index 00000000..12e45a91 --- /dev/null +++ b/ext/resolve-shape-geometry.cpp @@ -0,0 +1,89 @@ + +#include "resolve-shape-geometry.h" + +#ifdef MSDFGEN_USE_SKIA + +#include +#include +#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::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::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) { + { + const LinearSegment *linearSegment = dynamic_cast(&**edge); + if (linearSegment) + skPath.lineTo(pointToSkiaPoint(linearSegment->p[1])); + } { + const QuadraticSegment *quadraticSegment = dynamic_cast(&**edge); + if (quadraticSegment) + skPath.quadTo(pointToSkiaPoint(quadraticSegment->p[1]), pointToSkiaPoint(quadraticSegment->p[2])); + } { + const CubicSegment *cubicSegment = dynamic_cast(&**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 diff --git a/ext/resolve-shape-geometry.h b/ext/resolve-shape-geometry.h new file mode 100644 index 00000000..1ab0a633 --- /dev/null +++ b/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 diff --git a/main.cpp b/main.cpp index 49c4bd03..272bbfc9 100644 --- a/main.cpp +++ b/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 * @@ -252,10 +252,24 @@ static const char * writeOutput(const BitmapConstRef &bitmap, const ch 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 = "\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" #ifdef _WIN32 ".exe" @@ -273,7 +287,8 @@ static const char *helpText = " -defineshape \n" "\tDefines input shape using the ad-hoc text definition.\n" " -font \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 \n" "\tLoads text shape description from a file.\n" " -stdin\n" @@ -281,6 +296,7 @@ static const char *helpText = " -svg \n" "\tLoads the last vector path found in the specified SVG file.\n" "\n" + // Keep alphabetical order! "OPTIONS\n" " -angle \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" " -legacy\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" "\tDisables resolution of overlapping contours.\n" " -noscanline\n" "\tDisables the scanline pass, which corrects the distance field's signs according to the selected fill rule.\n" +#endif " -o \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" "\tPrints relevant metrics of the shape to the standard output.\n" " -pxrange \n" @@ -323,9 +348,13 @@ static const char *helpText = " -range \n" "\tSets the width of the range between the lowest and highest signed distance in shape units.\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 \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" "\tSets the random seed for edge coloring heuristic.\n" " -size \n" @@ -362,8 +391,15 @@ int main(int argc, const char * const *argv) { METRICS } mode = MULTI; 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; Format format = AUTO; const char *input = NULL; @@ -477,11 +513,26 @@ int main(int argc, const char * const *argv) { argPos += 1; continue; } + ARG_CASE("-nopreprocess", 0) { + geometryPreproc = false; + argPos += 1; + continue; + } + ARG_CASE("-preprocess", 0) { + geometryPreproc = true; + argPos += 1; + continue; + } ARG_CASE("-nooverlap", 0) { overlapSupport = false; argPos += 1; continue; } + ARG_CASE("-overlap", 0) { + overlapSupport = true; + argPos += 1; + continue; + } ARG_CASE("-noscanline", 0) { scanlinePass = false; argPos += 1; @@ -493,6 +544,7 @@ int main(int argc, const char * const *argv) { continue; } ARG_CASE("-fillrule", 1) { + scanlinePass = true; 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], "positive")) fillRule = FILL_POSITIVE; @@ -749,6 +801,14 @@ int main(int argc, const char * const *argv) { // Validate and normalize shape if (!shape.validate()) 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(); if (yFlip) shape.inverseYAxis = !shape.inverseYAxis; diff --git a/msdfgen-ext.h b/msdfgen-ext.h index 7fb5f5de..48a13697 100644 --- a/msdfgen-ext.h +++ b/msdfgen-ext.h @@ -2,13 +2,15 @@ #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 * * The extension module provides ways to easily load input and save output using popular formats. * * Third party dependencies in extension module: + * - Skia by Google + * (to resolve self-intersecting paths) * - FreeType 2 * (to load input font files) * - TinyXML 2 by Lee Thomason @@ -18,6 +20,7 @@ * */ +#include "ext/resolve-shape-geometry.h" #include "ext/save-png.h" #include "ext/import-svg.h" #include "ext/import-font.h" diff --git a/msdfgen.h b/msdfgen.h index cebe6a5c..f248e39f 100644 --- a/msdfgen.h +++ b/msdfgen.h @@ -2,7 +2,7 @@ #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 * @@ -32,7 +32,7 @@ #include "core/save-tiff.h" #include "core/shape-description.h" -#define MSDFGEN_VERSION "1.7" +#define MSDFGEN_VERSION "1.8" namespace msdfgen { diff --git a/skia/LICENSE b/skia/LICENSE new file mode 100644 index 00000000..fc53e3ec --- /dev/null +++ b/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. + +-------------------------------------------------------------------------------- diff --git a/skia/include/android/SkAndroidFrameworkUtils.h b/skia/include/android/SkAndroidFrameworkUtils.h new file mode 100644 index 00000000..04a1c391 --- /dev/null +++ b/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 diff --git a/skia/include/android/SkAnimatedImage.h b/skia/include/android/SkAnimatedImage.h new file mode 100644 index 00000000..983a57bd --- /dev/null +++ b/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 Make(std::unique_ptr, + SkISize scaledSize, SkIRect cropRect, sk_sp postProcess); + + /** + * Simpler version that uses the default size, no cropping, and no postProcess. + */ + static sk_sp Make(std::unique_ptr); + + ~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 fCodec; + const SkISize fScaledSize; + const SkImageInfo fDecodeInfo; + const SkIRect fCropRect; + const sk_sp 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, SkISize scaledSize, + SkImageInfo decodeInfo, SkIRect cropRect, sk_sp postProcess); + SkAnimatedImage(std::unique_ptr); + + int computeNextFrame(int current, bool* animationEnded); + double finish(); + + typedef SkDrawable INHERITED; +}; + +#endif // SkAnimatedImage_DEFINED diff --git a/skia/include/android/SkBRDAllocator.h b/skia/include/android/SkBRDAllocator.h new file mode 100644 index 00000000..3ca30c9b --- /dev/null +++ b/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 diff --git a/skia/include/android/SkBitmapRegionDecoder.h b/skia/include/android/SkBitmapRegionDecoder.h new file mode 100644 index 00000000..b5a4c813 --- /dev/null +++ b/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, 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 prefColorSpace = nullptr) = 0; + + virtual SkEncodedImageFormat getEncodedFormat() = 0; + + virtual SkColorType computeOutputColorType(SkColorType requestedColorType) = 0; + + virtual sk_sp computeOutputColorSpace(SkColorType outputColorType, + sk_sp 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 diff --git a/skia/include/atlastext/SkAtlasTextContext.h b/skia/include/atlastext/SkAtlasTextContext.h new file mode 100644 index 00000000..bb5de529 --- /dev/null +++ b/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 Make(sk_sp); + + 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); + + std::unique_ptr fInternalContext; +}; + +#endif diff --git a/skia/include/atlastext/SkAtlasTextFont.h b/skia/include/atlastext/SkAtlasTextFont.h new file mode 100644 index 00000000..a9e641f7 --- /dev/null +++ b/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 Make(sk_sp typeface, SkScalar size) { + return sk_sp(new SkAtlasTextFont(std::move(typeface), size)); + } + + SkTypeface* typeface() const { return fTypeface.get(); } + + sk_sp refTypeface() const { return fTypeface; } + + SkScalar size() const { return fSize; } + +private: + SkAtlasTextFont(sk_sp typeface, SkScalar size) + : fTypeface(std::move(typeface)), fSize(size) {} + + sk_sp fTypeface; + SkScalar fSize; +}; + +#endif diff --git a/skia/include/atlastext/SkAtlasTextRenderer.h b/skia/include/atlastext/SkAtlasTextRenderer.h new file mode 100644 index 00000000..c4d74e89 --- /dev/null +++ b/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 diff --git a/skia/include/atlastext/SkAtlasTextTarget.h b/skia/include/atlastext/SkAtlasTextTarget.h new file mode 100644 index 00000000..70fac4e6 --- /dev/null +++ b/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 + +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 Make(sk_sp, + 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, int width, int height, void* handle); + + const SkMatrix& ctm() const { return *static_cast(fMatrixStack.back()); } + + void* const fHandle; + const sk_sp fContext; + const int fWidth; + const int fHeight; + +private: + SkDeque fMatrixStack; + int fSaveCnt; + + SkMatrix* accessCTM() const { + return static_cast(const_cast(fMatrixStack.back())); + } + + SkAtlasTextTarget() = delete; + SkAtlasTextTarget(const SkAtlasTextContext&) = delete; + SkAtlasTextTarget& operator=(const SkAtlasTextContext&) = delete; +}; + +#endif diff --git a/skia/include/c/sk_canvas.h b/skia/include/c/sk_canvas.h new file mode 100644 index 00000000..1e1dd24f --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_colorspace.h b/skia/include/c/sk_colorspace.h new file mode 100644 index 00000000..f96d9bc0 --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_data.h b/skia/include/c/sk_data.h new file mode 100644 index 00000000..863c619f --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_image.h b/skia/include/c/sk_image.h new file mode 100644 index 00000000..e90649d7 --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_imageinfo.h b/skia/include/c/sk_imageinfo.h new file mode 100644 index 00000000..08f88b01 --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_maskfilter.h b/skia/include/c/sk_maskfilter.h new file mode 100644 index 00000000..5c22a063 --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_matrix.h b/skia/include/c/sk_matrix.h new file mode 100644 index 00000000..83f0122b --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_paint.h b/skia/include/c/sk_paint.h new file mode 100644 index 00000000..ef7e624a --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_path.h b/skia/include/c/sk_path.h new file mode 100644 index 00000000..74abca0d --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_picture.h b/skia/include/c/sk_picture.h new file mode 100644 index 00000000..7a032141 --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_shader.h b/skia/include/c/sk_shader.h new file mode 100644 index 00000000..702cda7f --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_surface.h b/skia/include/c/sk_surface.h new file mode 100644 index 00000000..d634185e --- /dev/null +++ b/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 diff --git a/skia/include/c/sk_types.h b/skia/include/c/sk_types.h new file mode 100644 index 00000000..852526f2 --- /dev/null +++ b/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 +#include + +#ifdef __cplusplus + #define SK_C_PLUS_PLUS_BEGIN_GUARD extern "C" { + #define SK_C_PLUS_PLUS_END_GUARD } +#else + #include + #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 diff --git a/skia/include/codec/SkAndroidCodec.h b/skia/include/codec/SkAndroidCodec.h new file mode 100644 index 00000000..750e2351 --- /dev/null +++ b/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 MakeFromCodec(std::unique_ptr, + 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 MakeFromStream(std::unique_ptr, + 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 MakeFromData(sk_sp, 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 computeOutputColorSpace(SkColorType outputColorType, + sk_sp 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 fCodec; +}; +#endif // SkAndroidCodec_DEFINED diff --git a/skia/include/codec/SkCodec.h b/skia/include/codec/SkCodec.h new file mode 100644 index 00000000..201cd74b --- /dev/null +++ b/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 + +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 MakeFromStream(std::unique_ptr, 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 MakeFromData(sk_sp, 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 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, + 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 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 diff --git a/skia/include/codec/SkCodecAnimation.h b/skia/include/codec/SkCodecAnimation.h new file mode 100644 index 00000000..9a4daff8 --- /dev/null +++ b/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 diff --git a/skia/include/codec/SkEncodedOrigin.h b/skia/include/codec/SkEncodedOrigin.h new file mode 100644 index 00000000..622ade15 --- /dev/null +++ b/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 diff --git a/skia/include/config/SkUserConfig.h b/skia/include/config/SkUserConfig.h new file mode 100644 index 00000000..a6497ca0 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkAnnotation.h b/skia/include/core/SkAnnotation.h new file mode 100644 index 00000000..35cc2b5d --- /dev/null +++ b/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 diff --git a/skia/include/core/SkBBHFactory.h b/skia/include/core/SkBBHFactory.h new file mode 100644 index 00000000..58bd754b --- /dev/null +++ b/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 diff --git a/skia/include/core/SkBitmap.h b/skia/include/core/SkBitmap.h new file mode 100644 index 00000000..0b7339db --- /dev/null +++ b/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 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 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 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 diff --git a/skia/include/core/SkBlendMode.h b/skia/include/core/SkBlendMode.h new file mode 100644 index 00000000..b62132ad --- /dev/null +++ b/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 diff --git a/skia/include/core/SkBlurTypes.h b/skia/include/core/SkBlurTypes.h new file mode 100644 index 00000000..257e1320 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkCanvas.h b/skia/include/core/SkCanvas.h new file mode 100644 index 00000000..82172d54 --- /dev/null +++ b/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 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 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 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 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& 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& 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& 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& 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& 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 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& 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& 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& 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& 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& 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& 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& 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& 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 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 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? ) + 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::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); + + /** + * 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 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 diff --git a/skia/include/core/SkCanvasVirtualEnforcer.h b/skia/include/core/SkCanvasVirtualEnforcer.h new file mode 100644 index 00000000..d451d609 --- /dev/null +++ b/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, which will make the build fail if you forget +// to override one of SkCanvas' key virtual hooks. +template +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 diff --git a/skia/include/core/SkClipOp.h b/skia/include/core/SkClipOp.h new file mode 100644 index 00000000..6ae16a8f --- /dev/null +++ b/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 diff --git a/skia/include/core/SkColor.h b/skia/include/core/SkColor.h new file mode 100644 index 00000000..99922c79 --- /dev/null +++ b/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. For convenience, this type can also be referred to + as SkColor4f. +*/ +template +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 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 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; + +template <> SK_API SkColor4f SkColor4f::FromColor(SkColor); +template <> SK_API SkColor SkColor4f::toSkColor() const; + +#endif diff --git a/skia/include/core/SkColorFilter.h b/skia/include/core/SkColorFilter.h new file mode 100644 index 00000000..4fbacf3e --- /dev/null +++ b/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 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 makeComposed(sk_sp inner) const; + + // DEPRECATED, call makeComposed instead + static sk_sp MakeComposeFilter(sk_sp outer, + sk_sp 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 MakeMatrixFilterRowMajor255(const SkScalar array[20]); + + /** Construct a colorfilter that applies the srgb gamma curve to the RGB channels */ + static sk_sp MakeLinearToSRGBGamma(); + + /** Construct a colorfilter that applies the inverse of the srgb gamma curve to the + * RGB channels + */ + static sk_sp 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 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize( + kSkColorFilter_Type, data, size, procs).release())); + } + +protected: + SkColorFilter() {} + + sk_sp makeColorSpace(SkColorSpaceXformer* xformer) const { + return this->onMakeColorSpace(xformer); + } + virtual sk_sp onMakeColorSpace(SkColorSpaceXformer*) const { + return sk_ref_sp(const_cast(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 onMakeComposed(sk_sp) 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 diff --git a/skia/include/core/SkColorPriv.h b/skia/include/core/SkColorPriv.h new file mode 100644 index 00000000..004cfec7 --- /dev/null +++ b/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(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 diff --git a/skia/include/core/SkColorSpace.h b/skia/include/core/SkColorSpace.h new file mode 100644 index 00000000..26771f3c --- /dev/null +++ b/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 + +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 { +public: + /** + * Create the sRGB color space. + */ + static sk_sp 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 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 MakeRGB(RenderTargetGamma gamma, Gamut gamut); + static sk_sp MakeRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50); + static sk_sp MakeRGB(const SkColorSpaceTransferFn& coeffs, Gamut gamut); + static sk_sp MakeRGB(const SkColorSpaceTransferFn& coeffs, + const SkMatrix44& toXYZD50); + + static sk_sp MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50); + + /** + * Create an SkColorSpace from a parsed (skcms) ICC profile. + */ + static sk_sp 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 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 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 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 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 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 diff --git a/skia/include/core/SkColorSpaceXformCanvas.h b/skia/include/core/SkColorSpaceXformCanvas.h new file mode 100644 index 00000000..6bca6c70 --- /dev/null +++ b/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 +#include +#include + +// Proxy SkCanvas calls to unowned target, transforming colors into targetCS as it goes. +// May return nullptr if |targetCS| is unsupported. +std::unique_ptr SK_API SkCreateColorSpaceXformCanvas(SkCanvas* target, + sk_sp targetCS); + +#endif //SkColorSpaceXformCanvas_DEFINED diff --git a/skia/include/core/SkCoverageMode.h b/skia/include/core/SkCoverageMode.h new file mode 100644 index 00000000..856b767c --- /dev/null +++ b/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 diff --git a/skia/include/core/SkData.h b/skia/include/core/SkData.h new file mode 100644 index 00000000..931749a9 --- /dev/null +++ b/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 + +#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 { +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(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 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 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 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 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 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 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 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 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 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 MakeFromStream(SkStream*, size_t size); + + /** + * Create a new dataref using a subset of the data in the specified + * src dataref. + */ + static sk_sp 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 MakeEmpty(); + +private: + friend class SkNVRefCnt; + 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 PrivateNewWithCopy(const void* srcOrNull, size_t length); + + static void DummyReleaseProc(const void*, void*); // {} + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/core/SkDataTable.h b/skia/include/core/SkDataTable.h new file mode 100644 index 00000000..a46f74ef --- /dev/null +++ b/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 + const T* atT(int index, size_t* size = nullptr) const { + return reinterpret_cast(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(index, &size); + SkASSERT(strlen(str) + 1 == size); + return str; + } + + typedef void (*FreeProc)(void* context); + + static sk_sp 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 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 MakeCopyArray(const void* array, size_t elemSize, int count); + + static sk_sp 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 diff --git a/skia/include/core/SkDeferredDisplayListRecorder.h b/skia/include/core/SkDeferredDisplayListRecorder.h new file mode 100644 index 00000000..b3892817 --- /dev/null +++ b/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 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 makePromiseTexture(const GrBackendFormat& backendFormat, + int width, + int height, + GrMipMapped mipMapped, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp 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 makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace, + const GrBackendFormat yuvaFormats[], + const SkISize yuvaSizes[], + const SkYUVAIndex yuvaIndices[4], + int imageWidth, + int imageHeight, + GrSurfaceOrigin imageOrigin, + sk_sp imageColorSpace, + TextureFulfillProc textureFulfillProc, + TextureReleaseProc textureReleaseProc, + PromiseDoneProc promiseDoneProc, + TextureContext textureContexts[]); + + // deprecated version that doesn't take yuvaSizeInfo + sk_sp makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace, + const GrBackendFormat yuvaFormats[], + const SkYUVAIndex yuvaIndices[4], + int imageWidth, + int imageHeight, + GrSurfaceOrigin imageOrigin, + sk_sp imageColorSpace, + TextureFulfillProc textureFulfillProc, + TextureReleaseProc textureReleaseProc, + PromiseDoneProc promiseDoneProc, + TextureContext textureContexts[]); + +private: + bool init(); + + const SkSurfaceCharacterization fCharacterization; + +#if SK_SUPPORT_GPU + sk_sp fContext; + sk_sp fLazyProxyData; + sk_sp fSurface; +#endif +}; + +#endif diff --git a/skia/include/core/SkDeque.h b/skia/include/core/SkDeque.h new file mode 100644 index 00000000..43023b8f --- /dev/null +++ b/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 diff --git a/skia/include/core/SkDocument.h b/skia/include/core/SkDocument.h new file mode 100644 index 00000000..bf520693 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkDrawLooper.h b/skia/include/core/SkDrawLooper.h new file mode 100644 index 00000000..c6b2d668 --- /dev/null +++ b/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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize( + kSkDrawLooper_Type, data, size, procs).release())); + } + +protected: + sk_sp makeColorSpace(SkColorSpaceXformer* xformer) const { + return this->onMakeColorSpace(xformer); + } + virtual sk_sp onMakeColorSpace(SkColorSpaceXformer*) const = 0; + + SkDrawLooper() {} + +private: + friend class SkColorSpaceXformer; + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/skia/include/core/SkDrawable.h b/skia/include/core/SkDrawable.h new file mode 100644 index 00000000..48cca6df --- /dev/null +++ b/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 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + 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 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 diff --git a/skia/include/core/SkEncodedImageFormat.h b/skia/include/core/SkEncodedImageFormat.h new file mode 100644 index 00000000..d0a9e5e0 --- /dev/null +++ b/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 + +/** + * 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 diff --git a/skia/include/core/SkExecutor.h b/skia/include/core/SkExecutor.h new file mode 100644 index 00000000..ad612f37 --- /dev/null +++ b/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 +#include + +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 MakeFIFOThreadPool(int threads = 0); + static std::unique_ptr 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) = 0; + + // If it makes sense for this executor, use this thread to execute work for a little while. + virtual void borrow() {} +}; + +#endif//SkExecutor_DEFINED diff --git a/skia/include/core/SkFilterQuality.h b/skia/include/core/SkFilterQuality.h new file mode 100644 index 00000000..8f532580 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkFlattenable.h b/skia/include/core/SkFlattenable.h new file mode 100644 index 00000000..3b018454 --- /dev/null +++ b/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 (*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 serialize(const SkSerialProcs* = nullptr) const; + size_t serialize(void* memory, size_t memory_size, + const SkSerialProcs* = nullptr) const; + static sk_sp 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 CreateProc(SkReadBuffer&); \ + friend class SkFlattenable::PrivateInitializer; \ + Factory getFactory() const override { return type::CreateProc; } \ + const char* getTypeName() const override { return #type; } + +#endif diff --git a/skia/include/core/SkFont.h b/skia/include/core/SkFont.h new file mode 100644 index 00000000..d5d9d9c4 --- /dev/null +++ b/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 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 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 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 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 fTypeface; + SkScalar fSize; + SkScalar fScaleX; + SkScalar fSkewX; + uint8_t fFlags; + uint8_t fEdging; + uint8_t fHinting; + + SkScalar setupForAsPaths(SkPaint*); + + friend class SkCanonicalizeFont; +}; + +#endif diff --git a/skia/include/core/SkFontArguments.h b/skia/include/core/SkFontArguments.h new file mode 100644 index 00000000..52f20728 --- /dev/null +++ b/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(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(fVariationDesignPosition.coordinates); + } + VariationPosition getVariationDesignPosition() const { + return fVariationDesignPosition; + } +private: + int fCollectionIndex; + VariationPosition fVariationDesignPosition; +}; + +#endif diff --git a/skia/include/core/SkFontLCDConfig.h b/skia/include/core/SkFontLCDConfig.h new file mode 100644 index 00000000..ec738f1d --- /dev/null +++ b/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 diff --git a/skia/include/core/SkFontMetrics.h b/skia/include/core/SkFontMetrics.h new file mode 100644 index 00000000..873931bf --- /dev/null +++ b/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 diff --git a/skia/include/core/SkFontMgr.h b/skia/include/core/SkFontMgr.h new file mode 100644 index 00000000..2636e909 --- /dev/null +++ b/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 makeFromData(sk_sp, 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 makeFromStream(std::unique_ptr, int ttcIndex = 0) const; + + /* Experimental, API subject to change. */ + sk_sp makeFromStream(std::unique_ptr, 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 makeFromFontData(std::unique_ptr) 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 makeFromFile(const char path[], int ttcIndex = 0) const; + + sk_sp legacyMakeTypeface(const char familyName[], SkFontStyle style) const; + + /** Return the default fontmgr. */ + static sk_sp 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 onMakeFromData(sk_sp, int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamIndex(std::unique_ptr, + int ttcIndex) const = 0; + virtual sk_sp onMakeFromStreamArgs(std::unique_ptr, + const SkFontArguments&) const; + virtual sk_sp onMakeFromFontData(std::unique_ptr) const; + virtual sk_sp onMakeFromFile(const char path[], int ttcIndex) const = 0; + + virtual sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const = 0; + +private: + + /** Implemented by porting layer to return the default factory. */ + static sk_sp Factory(); + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/core/SkFontParameters.h b/skia/include/core/SkFontParameters.h new file mode 100644 index 00000000..7d3c407a --- /dev/null +++ b/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 diff --git a/skia/include/core/SkFontStyle.h b/skia/include/core/SkFontStyle.h new file mode 100644 index 00000000..b619c362 --- /dev/null +++ b/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(weight, kInvisible_Weight, kExtraBlack_Weight)) + + (SkTPin(width, kUltraCondensed_Width, kUltraExpanded_Width) << 16) + + (SkTPin(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 diff --git a/skia/include/core/SkFontTypes.h b/skia/include/core/SkFontTypes.h new file mode 100644 index 00000000..33251467 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkGraphics.h b/skia/include/core/SkGraphics.h new file mode 100644 index 00000000..98307683 --- /dev/null +++ b/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 + (*ImageGeneratorFromEncodedDataFactory)(sk_sp); + + /** + * 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 diff --git a/skia/include/core/SkICC.h b/skia/include/core/SkICC.h new file mode 100644 index 00000000..89188894 --- /dev/null +++ b/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 SkWriteICCProfile(const SkColorSpaceTransferFn&, const float toXYZD50[9]); + +namespace SkICC { + SK_API sk_sp WriteToICC(const SkColorSpaceTransferFn&, const SkMatrix44&); +} + +#endif//SkICC_DEFINED diff --git a/skia/include/core/SkImage.h b/skia/include/core/SkImage.h new file mode 100644 index 00000000..9b97884d --- /dev/null +++ b/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 +#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 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 MakeRasterData(const SkImageInfo& info, sk_sp 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 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 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 MakeFromGenerator(std::unique_ptr 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 MakeFromEncoded(sk_sp 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 MakeFromTexture(GrContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp 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 MakeFromTexture(GrContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + SkColorType colorType, + SkAlphaType alphaType, + sk_sp 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 MakeCrossContextFromEncoded(GrContext* context, sk_sp 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 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 MakeFromAdoptedTexture(GrContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin surfaceOrigin, + SkColorType colorType, + SkAlphaType alphaType = kPremul_SkAlphaType, + sk_sp 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 MakeFromYUVATexturesCopy(GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvaTextures[], + const SkYUVAIndex yuvaIndices[4], + SkISize imageSize, + GrSurfaceOrigin imageOrigin, + sk_sp 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 MakeFromYUVATexturesCopyWithExternalBackend( + GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvaTextures[], + const SkYUVAIndex yuvaIndices[4], + SkISize imageSize, + GrSurfaceOrigin imageOrigin, + const GrBackendTexture& backendTexture, + sk_sp 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 MakeFromYUVATextures(GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvaTextures[], + const SkYUVAIndex yuvaIndices[4], + SkISize imageSize, + GrSurfaceOrigin imageOrigin, + sk_sp 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 MakeFromYUVAPixmaps( + GrContext* context, SkYUVColorSpace yuvColorSpace, const SkPixmap yuvaPixmaps[], + const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin, + bool buildMips, bool limitToMaxTextureSize = false, + sk_sp imageColorSpace = nullptr); + + /** To be deprecated. + */ + static sk_sp MakeFromYUVTexturesCopy(GrContext* context, SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvTextures[3], + GrSurfaceOrigin imageOrigin, + sk_sp imageColorSpace = nullptr); + + /** To be deprecated. + */ + static sk_sp MakeFromYUVTexturesCopyWithExternalBackend( + GrContext* context, SkYUVColorSpace yuvColorSpace, + const GrBackendTexture yuvTextures[3], GrSurfaceOrigin imageOrigin, + const GrBackendTexture& backendTexture, sk_sp 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 MakeFromNV12TexturesCopy(GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture nv12Textures[2], + GrSurfaceOrigin imageOrigin, + sk_sp 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 MakeFromNV12TexturesCopyWithExternalBackend( + GrContext* context, + SkYUVColorSpace yuvColorSpace, + const GrBackendTexture nv12Textures[2], + GrSurfaceOrigin imageOrigin, + const GrBackendTexture& backendTexture, + sk_sp 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 MakeFromPicture(sk_sp picture, const SkISize& dimensions, + const SkMatrix* matrix, const SkPaint* paint, + BitDepth bitDepth, + sk_sp 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 MakeFromAHardwareBuffer( + AHardwareBuffer* hardwareBuffer, + SkAlphaType alphaType = kPremul_SkAlphaType, + sk_sp 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 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 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 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 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 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 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 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 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 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 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 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 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 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 makeColorSpace(sk_sp 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 diff --git a/skia/include/core/SkImageEncoder.h b/skia/include/core/SkImageEncoder.h new file mode 100644 index 00000000..a6d7cb8c --- /dev/null +++ b/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 SkEncodePixmap(const SkPixmap& src, SkEncodedImageFormat format, int quality); + +/** + * Helper that extracts the pixmap from the bitmap, and then calls SkEncodePixmap() + */ +SK_API sk_sp SkEncodeBitmap(const SkBitmap& src, SkEncodedImageFormat format, int quality); + +#endif // SkImageEncoder_DEFINED diff --git a/skia/include/core/SkImageFilter.h b/skia/include/core/SkImageFilter.h new file mode 100644 index 00000000..428455b5 --- /dev/null +++ b/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 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 DrawWithFP(GrContext* context, + std::unique_ptr 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 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 MakeMatrixFilter(const SkMatrix& matrix, + SkFilterQuality quality, + sk_sp input); + + static void RegisterFlattenables(); + + static SkFlattenable::Type GetFlattenableType() { + return kSkImageFilter_Type; + } + + SkFlattenable::Type getFlattenableType() const override { + return kSkImageFilter_Type; + } + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + 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* inputs() { return fInputs.begin(); } + + sk_sp getInput(int index) { return fInputs[index]; } + + private: + CropRect fCropRect; + // most filters accept at most 2 input-filters + SkSTArray<2, sk_sp, true> fInputs; + }; + + SkImageFilter(sk_sp 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 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 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 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 ImageToColorSpace(SkSpecialImage* src, const OutputProperties&); +#endif + + /** + * Returns an image filter transformed into a new color space via the |xformer|. + */ + sk_sp makeColorSpace(SkColorSpaceXformer* xformer) const { + return this->onMakeColorSpace(xformer); + } + virtual sk_sp onMakeColorSpace(SkColorSpaceXformer*) const = 0; + + sk_sp refMe() const { + return sk_ref_sp(const_cast(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 const* inputs, int inputCount, const CropRect* cropRect); + + bool usesSrcInput() const { return fUsesSrcInput; } + virtual bool affectsTransparentBlack() const { return false; } + + SkAutoSTArray<2, sk_sp> fInputs; + + bool fUsesSrcInput; + CropRect fCropRect; + uint32_t fUniqueID; // Globally unique + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/skia/include/core/SkImageGenerator.h b/skia/include/core/SkImageGenerator.h new file mode 100644 index 00000000..746a1179 --- /dev/null +++ b/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 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 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 MakeFromEncoded(sk_sp); + + /** 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 MakeFromPicture(const SkISize&, sk_sp, + const SkMatrix*, const SkPaint*, + SkImage::BitDepth, + sk_sp); + +protected: + static constexpr int kNeedNewImageUniqueID = 0; + + SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); + + virtual sk_sp 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 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 MakeFromEncodedImpl(sk_sp); + + SkImageGenerator(SkImageGenerator&&) = delete; + SkImageGenerator(const SkImageGenerator&) = delete; + SkImageGenerator& operator=(SkImageGenerator&&) = delete; + SkImageGenerator& operator=(const SkImageGenerator&) = delete; +}; + +#endif // SkImageGenerator_DEFINED diff --git a/skia/include/core/SkImageInfo.h b/skia/include/core/SkImageInfo.h new file mode 100644 index 00000000..450bcd6c --- /dev/null +++ b/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 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 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 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 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 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(minRowBytes)) { + return 0; + } + return SkTo(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 fColorSpace; + SkISize fDimensions; + SkColorType fColorType; + SkAlphaType fAlphaType; + + SkImageInfo(int width, int height, SkColorType ct, SkAlphaType at, sk_sp cs) + : fColorSpace(std::move(cs)) + , fDimensions{width, height} + , fColorType(ct) + , fAlphaType(at) + {} +}; + +#endif diff --git a/skia/include/core/SkLights.h b/skia/include/core/SkLights.h new file mode 100644 index 00000000..c4262a0f --- /dev/null +++ b/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 finish() { + return std::move(fLights); + } + + private: + sk_sp 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 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 makeColorSpace(SkColorSpaceXformer* xformer) const; + + SkTArray fLights; + SkColor3f fAmbientLightColor; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/core/SkMallocPixelRef.h b/skia/include/core/SkMallocPixelRef.h new file mode 100644 index 00000000..c85c9247 --- /dev/null +++ b/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 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 MakeAllocate(const SkImageInfo&, size_t rowBytes); + + /** + * Identical to MakeAllocate, except all pixel bytes are zeroed. + */ + static sk_sp 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 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 MakeWithData(const SkImageInfo&, size_t rowBytes, sk_sp data); + +protected: + ~SkMallocPixelRef() override; + +private: + // Uses alloc to implement NewAllocate or NewZeroed. + static sk_sp 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 diff --git a/skia/include/core/SkMaskFilter.h b/skia/include/core/SkMaskFilter.h new file mode 100644 index 00000000..02961be2 --- /dev/null +++ b/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 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 MakeCompose(sk_sp outer, sk_sp inner); + + /** + * Compose two maskfilters together using a coverage mode. Returns nullptr on failure. + */ + static sk_sp MakeCombine(sk_sp filterA, sk_sp 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 makeWithMatrix(const SkMatrix&) const; + + static SkFlattenable::Type GetFlattenableType() { + return kSkMaskFilter_Type; + } + + SkFlattenable::Type getFlattenableType() const override { + return kSkMaskFilter_Type; + } + + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + SkFlattenable::Deserialize( + kSkMaskFilter_Type, data, size, procs).release())); + } + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/skia/include/core/SkMath.h b/skia/include/core/SkMath.h new file mode 100644 index 00000000..b19436cc --- /dev/null +++ b/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 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 diff --git a/skia/include/core/SkMatrix.h b/skia/include/core/SkMatrix.h new file mode 100644 index 00000000..1816b3b9 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkMatrix44.h b/skia/include/core/SkMatrix44.h new file mode 100644 index 00000000..9fc7c908 --- /dev/null +++ b/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 +#include + +#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(x); + } + static inline float SkMScalarToFloat(double x) { + return static_cast(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(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(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 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 diff --git a/skia/include/core/SkMetaData.h b/skia/include/core/SkMetaData.h new file mode 100644 index 00000000..a8ebaac2 --- /dev/null +++ b/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(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 diff --git a/skia/include/core/SkMilestone.h b/skia/include/core/SkMilestone.h new file mode 100644 index 00000000..c64ce6b0 --- /dev/null +++ b/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 diff --git a/skia/include/core/SkMultiPictureDraw.h b/skia/include/core/SkMultiPictureDraw.h new file mode 100644 index 00000000..e798f062 --- /dev/null +++ b/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&); + }; + + SkTDArray fThreadSafeDrawData; + SkTDArray fGPUDrawData; +}; + +#endif diff --git a/skia/include/core/SkOverdrawCanvas.h b/skia/include/core/SkOverdrawCanvas.h new file mode 100644 index 00000000..ffc049ed --- /dev/null +++ b/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 { +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 INHERITED; +}; + +#endif diff --git a/skia/include/core/SkPaint.h b/skia/include/core/SkPaint.h new file mode 100644 index 00000000..deaa6832 --- /dev/null +++ b/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 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 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 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 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 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 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 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 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 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 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 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 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 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 drawLooper); + + /** Deprecated. + (see skbug.com/6259) + */ + void setLooper(sk_sp 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(this->getLooper()); + effects |= reinterpret_cast(this->getMaskFilter()); + effects |= reinterpret_cast(this->getPathEffect()); + effects |= reinterpret_cast(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 fTypeface; + sk_sp fPathEffect; + sk_sp fShader; + sk_sp fMaskFilter; + sk_sp fColorFilter; + sk_sp fDrawLooper; + sk_sp 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 diff --git a/skia/include/core/SkPath.h b/skia/include/core/SkPath.h new file mode 100644 index 00000000..91924191 --- /dev/null +++ b/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 + +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& 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 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 fPathRef; + int fLastMoveToIndex; + mutable SkAtomic fConvexity; // SkPath::Convexity + mutable SkAtomic 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 diff --git a/skia/include/core/SkPathEffect.h b/skia/include/core/SkPathEffect.h new file mode 100644 index 00000000..ff257156 --- /dev/null +++ b/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 MakeSum(sk_sp first, sk_sp 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 MakeCompose(sk_sp outer, sk_sp 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 Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp(static_cast( + 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 diff --git a/skia/include/core/SkPathMeasure.h b/skia/include/core/SkPathMeasure.h new file mode 100644 index 00000000..e506c422 --- /dev/null +++ b/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 fSegments; + SkTDArray 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 diff --git a/skia/include/core/SkPicture.h b/skia/include/core/SkPicture.h new file mode 100644 index 00000000..7ab5392f --- /dev/null +++ b/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 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 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 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 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 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 friend class SkMiniPicture; + + void serialize(SkWStream*, const SkSerialProcs*, class SkRefCntSet* typefaces) const; + static sk_sp 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 Forwardport(const struct SkPictInfo&, + const class SkPictureData*, + class SkReadBuffer* buffer); + + struct SkPictInfo createHeader() const; + class SkPictureData* backport() const; + + mutable uint32_t fUniqueID; +}; + +#endif diff --git a/skia/include/core/SkPictureRecorder.h b/skia/include/core/SkPictureRecorder.h new file mode 100644 index 00000000..d28544c4 --- /dev/null +++ b/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 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 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 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 fBBH; + std::unique_ptr fRecorder; + sk_sp fRecord; + std::unique_ptr fMiniRecorder; + + typedef SkNoncopyable INHERITED; +}; + +#endif diff --git a/skia/include/core/SkPixelRef.h b/skia/include/core/SkPixelRef.h new file mode 100644 index 00000000..1cf91d7b --- /dev/null +++ b/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 + +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 fTaggedGenID; + + SkMutex fGenIDChangeListenersMutex; + SkTDArray fGenIDChangeListeners; // pointers are owned + + // Set true by caches when they cache content that's derived from the current pixels. + std::atomic 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 diff --git a/skia/include/core/SkPixmap.h b/skia/include/core/SkPixmap.h new file mode 100644 index 00000000..5c15876d --- /dev/null +++ b/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 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(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(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(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(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(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(this->addr64(x, y)); + } + + /** Returns writable base pixel address. + + @return writable generic base pointer to pixels + */ + void* writable_addr() const { return const_cast(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(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(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(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(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(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(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 diff --git a/skia/include/core/SkPngChunkReader.h b/skia/include/core/SkPngChunkReader.h new file mode 100644 index 00000000..0cd6634b --- /dev/null +++ b/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 diff --git a/skia/include/core/SkPoint.h b/skia/include/core/SkPoint.h new file mode 100644 index 00000000..1c4768f5 --- /dev/null +++ b/skia/include/core/SkPoint.h @@ -0,0 +1,562 @@ +/* + * 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/SkPoint.h and docs/SkPoint_Reference.bmh + on 2018-09-13 13:59:55. Additional documentation and examples can be found at: + https://skia.org/user/api/SkPoint_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkPoint_Reference.bmh, run: + bookmaker -b docs -i include/core/SkPoint.h -p + to create an updated version of this file. + */ + +#ifndef SkPoint_DEFINED +#define SkPoint_DEFINED + +#include "SkMath.h" +#include "SkScalar.h" +#include "../private/SkSafe32.h" + +struct SkIPoint; + +/** SkIVector provides an alternative name for SkIPoint. SkIVector and SkIPoint + can be used interchangeably for all purposes. +*/ +typedef SkIPoint SkIVector; + +/** \struct SkIPoint + SkIPoint holds two 32-bit integer coordinates. +*/ +struct SkIPoint { + int32_t fX; //!< x-axis value + int32_t fY; //!< y-axis value + + /** Sets fX to x, fY to y. + + @param x integer x-axis value of constructed SkIPoint + @param y integer y-axis value of constructed SkIPoint + @return SkIPoint (x, y) + */ + static constexpr SkIPoint Make(int32_t x, int32_t y) { + return {x, y}; + } + + /** Returns x-axis value of SkIPoint. + + @return fX + */ + int32_t x() const { return fX; } + + /** Returns y-axis value of SkIPoint. + + @return fY + */ + int32_t y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (fX | fY) == 0; } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(int32_t x, int32_t y) { + fX = x; + fY = y; + } + + /** Returns SkIPoint changing the signs of fX and fY. + + @return SkIPoint as (-fX, -fY) + */ + SkIPoint operator-() const { + return {-fX, -fY}; + } + + /** Offsets SkIPoint by ivector v. Sets SkIPoint to (fX + v.fX, fY + v.fY). + + @param v ivector to add + */ + void operator+=(const SkIVector& v) { + fX = Sk32_sat_add(fX, v.fX); + fY = Sk32_sat_add(fY, v.fY); + } + + /** Subtracts ivector v from SkIPoint. Sets SkIPoint to: (fX - v.fX, fY - v.fY). + + @param v ivector to subtract + */ + void operator-=(const SkIVector& v) { + fX = Sk32_sat_sub(fX, v.fX); + fY = Sk32_sat_sub(fY, v.fY); + } + + /** Returns true if SkIPoint is equivalent to SkIPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkIPoint equals (x, y) + */ + bool equals(int32_t x, int32_t y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkIPoint& a, const SkIPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkIPoint to compare + @param b SkIPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns ivector from b to a; computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract ivector from ivector, returning ivector. + + @param a SkIPoint or ivector to subtract from + @param b ivector to subtract + @return ivector from b to a + */ + friend SkIVector operator-(const SkIPoint& a, const SkIPoint& b) { + return { Sk32_sat_sub(a.fX, b.fX), Sk32_sat_sub(a.fY, b.fY) }; + } + + /** Returns SkIPoint resulting from SkIPoint a offset by ivector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkIPoint b by ivector a, returning SkIPoint. + Can also be used to add ivector to ivector, returning ivector. + + @param a SkIPoint or ivector to add to + @param b SkIPoint or ivector to add + @return SkIPoint equal to a offset by b + */ + friend SkIPoint operator+(const SkIPoint& a, const SkIVector& b) { + return { Sk32_sat_add(a.fX, b.fX), Sk32_sat_add(a.fY, b.fY) }; + } +}; + +struct SkPoint; + +/** SkVector provides an alternative name for SkPoint. SkVector and SkPoint can + be used interchangeably for all purposes. +*/ +typedef SkPoint SkVector; + +/** \struct SkPoint + SkPoint holds two 32-bit floating point coordinates. +*/ +struct SK_API SkPoint { + SkScalar fX; //!< x-axis value + SkScalar fY; //!< y-axis value + + /** Sets fX to x, fY to y. Used both to set SkPoint and vector. + + @param x SkScalar x-axis value of constructed SkPoint or vector + @param y SkScalar y-axis value of constructed SkPoint or vector + @return SkPoint (x, y) + */ + static constexpr SkPoint Make(SkScalar x, SkScalar y) { + return {x, y}; + } + + /** Returns x-axis value of SkPoint or vector. + + @return fX + */ + SkScalar x() const { return fX; } + + /** Returns y-axis value of SkPoint or vector. + + @return fY + */ + SkScalar y() const { return fY; } + + /** Returns true if fX and fY are both zero. + + @return true if fX is zero and fY is zero + */ + bool isZero() const { return (0 == fX) & (0 == fY); } + + /** Sets fX to x and fY to y. + + @param x new value for fX + @param y new value for fY + */ + void set(SkScalar x, SkScalar y) { + fX = x; + fY = y; + } + + /** Sets fX to x and fY to y, promoting integers to SkScalar values. + + Assigning a large integer value directly to fX or fY may cause a compiler + error, triggered by narrowing conversion of int to SkScalar. This safely + casts x and y to avoid the error. + + @param x new value for fX + @param y new value for fY + */ + void iset(int32_t x, int32_t y) { + fX = SkIntToScalar(x); + fY = SkIntToScalar(y); + } + + /** Sets fX to p.fX and fY to p.fY, promoting integers to SkScalar values. + + Assigning an SkIPoint containing a large integer value directly to fX or fY may + cause a compiler error, triggered by narrowing conversion of int to SkScalar. + This safely casts p.fX and p.fY to avoid the error. + + @param p SkIPoint members promoted to SkScalar + */ + void iset(const SkIPoint& p) { + fX = SkIntToScalar(p.fX); + fY = SkIntToScalar(p.fY); + } + + /** Sets fX to absolute value of pt.fX; and fY to absolute value of pt.fY. + + @param pt members providing magnitude for fX and fY + */ + void setAbs(const SkPoint& pt) { + fX = SkScalarAbs(pt.fX); + fY = SkScalarAbs(pt.fY); + } + + /** Adds offset to each SkPoint in points array with count entries. + + @param points SkPoint array + @param count entries in array + @param offset vector added to points + */ + static void Offset(SkPoint points[], int count, const SkVector& offset) { + Offset(points, count, offset.fX, offset.fY); + } + + /** Adds offset (dx, dy) to each SkPoint in points array of length count. + + @param points SkPoint array + @param count entries in array + @param dx added to fX in points + @param dy added to fY in points + */ + static void Offset(SkPoint points[], int count, SkScalar dx, SkScalar dy) { + for (int i = 0; i < count; ++i) { + points[i].offset(dx, dy); + } + } + + /** Adds offset (dx, dy) to SkPoint. + + @param dx added to fX + @param dy added to fY + */ + void offset(SkScalar dx, SkScalar dy) { + fX += dx; + fY += dy; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + SkScalar length() const { return SkPoint::Length(fX, fY); } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(fX * fX + fY * fY) + + . + + @return straight-line distance to origin + */ + SkScalar distanceToOrigin() const { return this->length(); } + + /** Scales (fX, fY) so that length() returns one, while preserving ratio of fX to fY, + if possible. If prior length is nearly zero, sets vector to (0, 0) and returns + false; otherwise returns true. + + @return true if former length is not zero or nearly zero + */ + bool normalize(); + + /** Sets vector to (x, y) scaled so length() returns one, and so that + (fX, fY) is proportional to (x, y). If (x, y) length is nearly zero, + sets vector to (0, 0) and returns false; otherwise returns true. + + @param x proportional value for fX + @param y proportional value for fY + @return true if (x, y) length is not zero or nearly zero + */ + bool setNormalize(SkScalar x, SkScalar y); + + /** Scales vector so that distanceToOrigin() returns length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param length straight-line distance to origin + @return true if former length is not zero or nearly zero + */ + bool setLength(SkScalar length); + + /** Sets vector to (x, y) scaled to length, if possible. If former + length is nearly zero, sets vector to (0, 0) and return false; otherwise returns + true. + + @param x proportional value for fX + @param y proportional value for fY + @param length straight-line distance to origin + @return true if (x, y) length is not zero or nearly zero + */ + bool setLength(SkScalar x, SkScalar y, SkScalar length); + + /** Sets dst to SkPoint times scale. dst may be SkPoint to modify SkPoint in place. + + @param scale factor to multiply SkPoint by + @param dst storage for scaled SkPoint + */ + void scale(SkScalar scale, SkPoint* dst) const; + + /** Scales SkPoint in place by scale. + + @param value factor to multiply SkPoint by + */ + void scale(SkScalar value) { this->scale(value, this); } + + /** Changes the sign of fX and fY. + */ + void negate() { + fX = -fX; + fY = -fY; + } + + /** Returns SkPoint changing the signs of fX and fY. + + @return SkPoint as (-fX, -fY) + */ + SkPoint operator-() const { + return {-fX, -fY}; + } + + /** Adds vector v to SkPoint. Sets SkPoint to: (fX + v.fX, fY + v.fY). + + @param v vector to add + */ + void operator+=(const SkVector& v) { + fX += v.fX; + fY += v.fY; + } + + /** Subtracts vector v from SkPoint. Sets SkPoint to: (fX - v.fX, fY - v.fY). + + @param v vector to subtract + */ + void operator-=(const SkVector& v) { + fX -= v.fX; + fY -= v.fY; + } + + /** Returns SkPoint multiplied by scale. + + @param scale scalar to multiply by + @return SkPoint as (fX * scale, fY * scale) + */ + SkPoint operator*(SkScalar scale) const { + return {fX * scale, fY * scale}; + } + + /** Multiplies SkPoint by scale. Sets SkPoint to: (fX * scale, fY * scale). + + @param scale scalar to multiply by + @return reference to SkPoint + */ + SkPoint& operator*=(SkScalar scale) { + fX *= scale; + fY *= scale; + return *this; + } + + /** Returns true if both fX and fY are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + SkScalar accum = 0; + accum *= fX; + accum *= fY; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns true if SkPoint is equivalent to SkPoint constructed from (x, y). + + @param x value compared with fX + @param y value compared with fY + @return true if SkPoint equals (x, y) + */ + bool equals(SkScalar x, SkScalar y) const { + return fX == x && fY == y; + } + + /** Returns true if a is equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX == b.fX and a.fY == b.fY + */ + friend bool operator==(const SkPoint& a, const SkPoint& b) { + return a.fX == b.fX && a.fY == b.fY; + } + + /** Returns true if a is not equivalent to b. + + @param a SkPoint to compare + @param b SkPoint to compare + @return true if a.fX != b.fX or a.fY != b.fY + */ + friend bool operator!=(const SkPoint& a, const SkPoint& b) { + return a.fX != b.fX || a.fY != b.fY; + } + + /** Returns vector from b to a, computed as (a.fX - b.fX, a.fY - b.fY). + + Can also be used to subtract vector from SkPoint, returning SkPoint. + Can also be used to subtract vector from vector, returning vector. + + @param a SkPoint to subtract from + @param b SkPoint to subtract + @return vector from b to a + */ + friend SkVector operator-(const SkPoint& a, const SkPoint& b) { + return {a.fX - b.fX, a.fY - b.fY}; + } + + /** Returns SkPoint resulting from SkPoint a offset by vector b, computed as: + (a.fX + b.fX, a.fY + b.fY). + + Can also be used to offset SkPoint b by vector a, returning SkPoint. + Can also be used to add vector to vector, returning vector. + + @param a SkPoint or vector to add to + @param b SkPoint or vector to add + @return SkPoint equal to a offset by b + */ + friend SkPoint operator+(const SkPoint& a, const SkVector& b) { + return {a.fX + b.fX, a.fY + b.fY}; + } + + /** Returns the Euclidean distance from origin, computed as: + + sqrt(x * x + y * y) + + . + + @param x component of length + @param y component of length + @return straight-line distance to origin + */ + static SkScalar Length(SkScalar x, SkScalar y); + + /** Scales (vec->fX, vec->fY) so that length() returns one, while preserving ratio of vec->fX + to vec->fY, if possible. If original length is nearly zero, sets vec to (0, 0) and returns + zero; otherwise, returns length of vec before vec is scaled. + + Returned prior length may be SK_ScalarInfinity if it can not be represented by SkScalar. + + Note that normalize() is faster if prior length is not required. + + @param vec normalized to unit length + @return original vec length + */ + static SkScalar Normalize(SkVector* vec); + + /** Returns the Euclidean distance between a and b. + + @param a line end point + @param b line end point + @return straight-line distance from a to b + */ + static SkScalar Distance(const SkPoint& a, const SkPoint& b) { + return Length(a.fX - b.fX, a.fY - b.fY); + } + + /** Returns the dot product of vector a and vector b. + + @param a left side of dot product + @param b right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + static SkScalar DotProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fX + a.fY * b.fY; + } + + /** Returns the cross product of vector a and vector b. + + a and b form three-dimensional vectors with z-axis value equal to zero. The + cross product is a three-dimensional vector with x-axis and y-axis values equal + to zero. The cross product z-axis component is returned. + + @param a left side of cross product + @param b right side of cross product + @return area spanned by vectors signed by angle direction + */ + static SkScalar CrossProduct(const SkVector& a, const SkVector& b) { + return a.fX * b.fY - a.fY * b.fX; + } + + /** Returns the cross product of vector and vec. + + Vector and vec form three-dimensional vectors with z-axis value equal to zero. + The cross product is a three-dimensional vector with x-axis and y-axis values + equal to zero. The cross product z-axis component is returned. + + @param vec right side of cross product + @return area spanned by vectors signed by angle direction + */ + SkScalar cross(const SkVector& vec) const { + return CrossProduct(*this, vec); + } + + /** Returns the dot product of vector and vector vec. + + @param vec right side of dot product + @return product of input magnitudes and cosine of the angle between them + */ + SkScalar dot(const SkVector& vec) const { + return DotProduct(*this, vec); + } + +}; + +#endif diff --git a/skia/include/core/SkPoint3.h b/skia/include/core/SkPoint3.h new file mode 100644 index 00000000..91779da8 --- /dev/null +++ b/skia/include/core/SkPoint3.h @@ -0,0 +1,157 @@ +/* + * 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 SkPoint3_DEFINED +#define SkPoint3_DEFINED + +#include "SkPoint.h" + +struct SK_API SkPoint3 { + SkScalar fX, fY, fZ; + + static SkPoint3 Make(SkScalar x, SkScalar y, SkScalar z) { + SkPoint3 pt; + pt.set(x, y, z); + return pt; + } + + SkScalar x() const { return fX; } + SkScalar y() const { return fY; } + SkScalar z() const { return fZ; } + + void set(SkScalar x, SkScalar y, SkScalar z) { fX = x; fY = y; fZ = z; } + + friend bool operator==(const SkPoint3& a, const SkPoint3& b) { + return a.fX == b.fX && a.fY == b.fY && a.fZ == b.fZ; + } + + friend bool operator!=(const SkPoint3& a, const SkPoint3& b) { + return !(a == b); + } + + /** Returns the Euclidian distance from (0,0,0) to (x,y,z) + */ + static SkScalar Length(SkScalar x, SkScalar y, SkScalar z); + + /** Return the Euclidian distance from (0,0,0) to the point + */ + SkScalar length() const { return SkPoint3::Length(fX, fY, fZ); } + + /** Set the point (vector) to be unit-length in the same direction as it + already points. If the point has a degenerate length (i.e., nearly 0) + then set it to (0,0,0) and return false; otherwise return true. + */ + bool normalize(); + + /** Return a new point whose X, Y and Z coordinates are scaled. + */ + SkPoint3 makeScale(SkScalar scale) const { + SkPoint3 p; + p.set(scale * fX, scale * fY, scale * fZ); + return p; + } + + /** Scale the point's coordinates by scale. + */ + void scale(SkScalar value) { + fX *= value; + fY *= value; + fZ *= value; + } + + /** Return a new point whose X, Y and Z coordinates are the negative of the + original point's + */ + SkPoint3 operator-() const { + SkPoint3 neg; + neg.fX = -fX; + neg.fY = -fY; + neg.fZ = -fZ; + return neg; + } + + /** Returns a new point whose coordinates are the difference between + a and b (i.e., a - b) + */ + friend SkPoint3 operator-(const SkPoint3& a, const SkPoint3& b) { + SkPoint3 v; + v.set(a.fX - b.fX, a.fY - b.fY, a.fZ - b.fZ); + return v; + } + + /** Returns a new point whose coordinates are the sum of a and b (a + b) + */ + friend SkPoint3 operator+(const SkPoint3& a, const SkPoint3& b) { + SkPoint3 v; + v.set(a.fX + b.fX, a.fY + b.fY, a.fZ + b.fZ); + return v; + } + + /** Add v's coordinates to the point's + */ + void operator+=(const SkPoint3& v) { + fX += v.fX; + fY += v.fY; + fZ += v.fZ; + } + + /** Subtract v's coordinates from the point's + */ + void operator-=(const SkPoint3& v) { + fX -= v.fX; + fY -= v.fY; + fZ -= v.fZ; + } + + /** Returns true if fX, fY, and fZ are measurable values. + + @return true for values other than infinities and NaN + */ + bool isFinite() const { + SkScalar accum = 0; + accum *= fX; + accum *= fY; + accum *= fZ; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns the dot product of a and b, treating them as 3D vectors + */ + static SkScalar DotProduct(const SkPoint3& a, const SkPoint3& b) { + return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ; + } + + SkScalar dot(const SkPoint3& vec) const { + return DotProduct(*this, vec); + } + + /** Returns the cross product of a and b, treating them as 3D vectors + */ + static SkPoint3 CrossProduct(const SkPoint3& a, const SkPoint3& b) { + SkPoint3 result; + result.fX = a.fY*b.fZ - a.fZ*b.fY; + result.fY = a.fZ*b.fX - a.fX*b.fZ; + result.fZ = a.fX*b.fY - a.fY*b.fX; + + return result; + } + + SkPoint3 cross(const SkPoint3& vec) const { + return CrossProduct(*this, vec); + } +}; + +typedef SkPoint3 SkVector3; +typedef SkPoint3 SkColor3f; + +#endif diff --git a/skia/include/core/SkPostConfig.h b/skia/include/core/SkPostConfig.h new file mode 100644 index 00000000..d585b9fa --- /dev/null +++ b/skia/include/core/SkPostConfig.h @@ -0,0 +1,309 @@ +/* + * 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. + */ + +// IWYU pragma: private, include "SkTypes.h" + +#ifndef SkPostConfig_DEFINED +#define SkPostConfig_DEFINED + +#if !defined(SK_DEBUG) && !defined(SK_RELEASE) + #ifdef NDEBUG + #define SK_RELEASE + #else + #define SK_DEBUG + #endif +#endif + +#if defined(SK_DEBUG) && defined(SK_RELEASE) +# error "cannot define both SK_DEBUG and SK_RELEASE" +#elif !defined(SK_DEBUG) && !defined(SK_RELEASE) +# error "must define either SK_DEBUG or SK_RELEASE" +#endif + +/** + * Matrix calculations may be float or double. + * The default is float, as that's what Chromium's using. + */ +#if defined(SK_MSCALAR_IS_DOUBLE) && defined(SK_MSCALAR_IS_FLOAT) +# error "cannot define both SK_MSCALAR_IS_DOUBLE and SK_MSCALAR_IS_FLOAT" +#elif !defined(SK_MSCALAR_IS_DOUBLE) && !defined(SK_MSCALAR_IS_FLOAT) +# define SK_MSCALAR_IS_FLOAT +#endif + +#if defined(SK_CPU_LENDIAN) && defined(SK_CPU_BENDIAN) +# error "cannot define both SK_CPU_LENDIAN and SK_CPU_BENDIAN" +#elif !defined(SK_CPU_LENDIAN) && !defined(SK_CPU_BENDIAN) +# error "must define either SK_CPU_LENDIAN or SK_CPU_BENDIAN" +#endif + +#if defined(SK_CPU_BENDIAN) && !defined(I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN) + #error "The Skia team is not endian-savvy enough to support big-endian CPUs." + #error "If you still want to use Skia," + #error "please define I_ACKNOWLEDGE_SKIA_DOES_NOT_SUPPORT_BIG_ENDIAN." +#endif + +/** + * Ensure the port has defined all of SK_X32_SHIFT, or none of them. + */ +#ifdef SK_A32_SHIFT +# if !defined(SK_R32_SHIFT) || !defined(SK_G32_SHIFT) || !defined(SK_B32_SHIFT) +# error "all or none of the 32bit SHIFT amounts must be defined" +# endif +#else +# if defined(SK_R32_SHIFT) || defined(SK_G32_SHIFT) || defined(SK_B32_SHIFT) +# error "all or none of the 32bit SHIFT amounts must be defined" +# endif +#endif + +#if !defined(SK_HAS_COMPILER_FEATURE) +# if defined(__has_feature) +# define SK_HAS_COMPILER_FEATURE(x) __has_feature(x) +# else +# define SK_HAS_COMPILER_FEATURE(x) 0 +# endif +#endif + +#if !defined(SK_ATTRIBUTE) +# if defined(__clang__) || defined(__GNUC__) +# define SK_ATTRIBUTE(attr) __attribute__((attr)) +# else +# define SK_ATTRIBUTE(attr) +# endif +#endif + +#if !defined(SK_SUPPORT_GPU) +# define SK_SUPPORT_GPU 1 +#endif + +#if !defined(SK_SUPPORT_ATLAS_TEXT) +# define SK_SUPPORT_ATLAS_TEXT 0 +#elif SK_SUPPORT_ATLAS_TEXT && !SK_SUPPORT_GPU +# error "SK_SUPPORT_ATLAS_TEXT requires SK_SUPPORT_GPU" +#endif + +/** + * The clang static analyzer likes to know that when the program is not + * expected to continue (crash, assertion failure, etc). It will notice that + * some combination of parameters lead to a function call that does not return. + * It can then make appropriate assumptions about the parameters in code + * executed only if the non-returning function was *not* called. + */ +#if !defined(SkNO_RETURN_HINT) +# if SK_HAS_COMPILER_FEATURE(attribute_analyzer_noreturn) + static inline void SkNO_RETURN_HINT() __attribute__((analyzer_noreturn)); + static inline void SkNO_RETURN_HINT() {} +# else +# define SkNO_RETURN_HINT() do {} while (false) +# endif +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef SK_BUILD_FOR_WIN +# ifndef SK_A32_SHIFT +# define SK_A32_SHIFT 24 +# define SK_R32_SHIFT 16 +# define SK_G32_SHIFT 8 +# define SK_B32_SHIFT 0 +# endif +# +#endif + +#if defined(SK_BUILD_FOR_GOOGLE3) + void SkDebugfForDumpStackTrace(const char* data, void* unused); + void DumpStackTrace(int skip_count, void w(const char*, void*), void* arg); +# define SK_DUMP_GOOGLE3_STACK() DumpStackTrace(0, SkDebugfForDumpStackTrace, nullptr) +#else +# define SK_DUMP_GOOGLE3_STACK() +#endif + +#ifdef SK_BUILD_FOR_WIN +// permits visual studio to follow error back to source +#define SK_DUMP_LINE_FORMAT(message) \ + SkDebugf("%s(%d): fatal error: \"%s\"\n", __FILE__, __LINE__, message) +#else +#define SK_DUMP_LINE_FORMAT(message) \ + SkDebugf("%s:%d: fatal error: \"%s\"\n", __FILE__, __LINE__, message) +#endif + +#ifndef SK_ABORT +# define SK_ABORT(message) \ + do { \ + SkNO_RETURN_HINT(); \ + SK_DUMP_LINE_FORMAT(message); \ + SK_DUMP_GOOGLE3_STACK(); \ + sk_abort_no_print(); \ + } while (false) +#endif + +/** + * We check to see if the SHIFT value has already been defined. + * if not, we define it ourself to some default values. We default to OpenGL + * order (in memory: r,g,b,a) + */ +#ifndef SK_A32_SHIFT +# ifdef SK_CPU_BENDIAN +# define SK_R32_SHIFT 24 +# define SK_G32_SHIFT 16 +# define SK_B32_SHIFT 8 +# define SK_A32_SHIFT 0 +# else +# define SK_R32_SHIFT 0 +# define SK_G32_SHIFT 8 +# define SK_B32_SHIFT 16 +# define SK_A32_SHIFT 24 +# endif +#endif + +/** + * SkColor has well defined shift values, but SkPMColor is configurable. This + * macro is a convenience that returns true if the shift values are equal while + * ignoring the machine's endianness. + */ +#define SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER \ + (SK_A32_SHIFT == 24 && SK_R32_SHIFT == 16 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 0) + +/** + * SK_PMCOLOR_BYTE_ORDER can be used to query the byte order of SkPMColor at compile time. The + * relationship between the byte order and shift values depends on machine endianness. If the shift + * order is R=0, G=8, B=16, A=24 then ((char*)&pmcolor)[0] will produce the R channel on a little + * endian machine and the A channel on a big endian machine. Thus, given those shifts values, + * SK_PMCOLOR_BYTE_ORDER(R,G,B,A) will be true on a little endian machine and + * SK_PMCOLOR_BYTE_ORDER(A,B,G,R) will be true on a big endian machine. + */ +#ifdef SK_CPU_BENDIAN +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C3 ## 32_SHIFT == 0 && \ + SK_ ## C2 ## 32_SHIFT == 8 && \ + SK_ ## C1 ## 32_SHIFT == 16 && \ + SK_ ## C0 ## 32_SHIFT == 24) +#else +# define SK_PMCOLOR_BYTE_ORDER(C0, C1, C2, C3) \ + (SK_ ## C0 ## 32_SHIFT == 0 && \ + SK_ ## C1 ## 32_SHIFT == 8 && \ + SK_ ## C2 ## 32_SHIFT == 16 && \ + SK_ ## C3 ## 32_SHIFT == 24) +#endif + +////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined SK_DEBUG && defined SK_BUILD_FOR_WIN + #ifdef free + #undef free + #endif + #include + #undef free +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_UNUSED) +# if !defined(__clang__) && defined(_MSC_VER) +# define SK_UNUSED __pragma(warning(suppress:4189)) +# else +# define SK_UNUSED SK_ATTRIBUTE(unused) +# endif +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_ALWAYS_INLINE to force inlining. E.g. + * inline void someMethod() { ... } // may not be inlined + * SK_ALWAYS_INLINE void someMethod() { ... } // should always be inlined + */ +#if !defined(SK_ALWAYS_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_ALWAYS_INLINE __forceinline +# else +# define SK_ALWAYS_INLINE SK_ATTRIBUTE(always_inline) inline +# endif +#endif + +/** + * If your judgment is better than the compiler's (i.e. you've profiled it), + * you can use SK_NEVER_INLINE to prevent inlining. + */ +#if !defined(SK_NEVER_INLINE) +# if defined(SK_BUILD_FOR_WIN) +# define SK_NEVER_INLINE __declspec(noinline) +# else +# define SK_NEVER_INLINE SK_ATTRIBUTE(noinline) +# endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 + #define SK_PREFETCH(ptr) _mm_prefetch(reinterpret_cast(ptr), _MM_HINT_T0) + #define SK_WRITE_PREFETCH(ptr) _mm_prefetch(reinterpret_cast(ptr), _MM_HINT_T0) +#elif defined(__GNUC__) + #define SK_PREFETCH(ptr) __builtin_prefetch(ptr) + #define SK_WRITE_PREFETCH(ptr) __builtin_prefetch(ptr, 1) +#else + #define SK_PREFETCH(ptr) + #define SK_WRITE_PREFETCH(ptr) +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_PRINTF_LIKE +# if defined(__clang__) || defined(__GNUC__) +# define SK_PRINTF_LIKE(A, B) __attribute__((format(printf, (A), (B)))) +# else +# define SK_PRINTF_LIKE(A, B) +# endif +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_SIZE_T_SPECIFIER +# if defined(_MSC_VER) && !defined(__clang__) +# define SK_SIZE_T_SPECIFIER "%Iu" +# else +# define SK_SIZE_T_SPECIFIER "%zu" +# endif +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS +# define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1 +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_GAMMA_EXPONENT) + #define SK_GAMMA_EXPONENT (0.0f) // SRGB +#endif + +////////////////////////////////////////////////////////////////////// + +#ifndef GR_TEST_UTILS +# define GR_TEST_UTILS 0 +#endif + +////////////////////////////////////////////////////////////////////// + +#if defined(SK_HISTOGRAM_ENUMERATION) && defined(SK_HISTOGRAM_BOOLEAN) +# define SK_HISTOGRAMS_ENABLED 1 +#else +# define SK_HISTOGRAMS_ENABLED 0 +#endif + +#ifndef SK_HISTOGRAM_BOOLEAN +# define SK_HISTOGRAM_BOOLEAN(name, value) +#endif + +#ifndef SK_HISTOGRAM_ENUMERATION +# define SK_HISTOGRAM_ENUMERATION(name, value, boundary_value) +#endif + +#ifndef SK_DISABLE_LEGACY_SHADERCONTEXT +#define SK_ENABLE_LEGACY_SHADERCONTEXT +#endif + +#endif // SkPostConfig_DEFINED diff --git a/skia/include/core/SkPreConfig.h b/skia/include/core/SkPreConfig.h new file mode 100644 index 00000000..1f83c143 --- /dev/null +++ b/skia/include/core/SkPreConfig.h @@ -0,0 +1,200 @@ +/* + * 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. + */ + +// IWYU pragma: private, include "SkTypes.h" + +#ifndef SkPreConfig_DEFINED +#define SkPreConfig_DEFINED + +// Allows embedders that want to disable macros that take arguments to just +// define that symbol to be one of these +#define SK_NOTHING_ARG1(arg1) +#define SK_NOTHING_ARG2(arg1, arg2) +#define SK_NOTHING_ARG3(arg1, arg2, arg3) + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_WIN) && \ + !defined(SK_BUILD_FOR_UNIX) && !defined(SK_BUILD_FOR_MAC) + + #ifdef __APPLE__ + #include "TargetConditionals.h" + #endif + + #if defined(_WIN32) || defined(__SYMBIAN32__) + #define SK_BUILD_FOR_WIN + #elif defined(ANDROID) || defined(__ANDROID__) + #define SK_BUILD_FOR_ANDROID + #elif defined(linux) || defined(__linux) || defined(__FreeBSD__) || \ + defined(__OpenBSD__) || defined(__sun) || defined(__NetBSD__) || \ + defined(__DragonFly__) || defined(__Fuchsia__) || \ + defined(__GLIBC__) || defined(__GNU__) || defined(__unix__) + #define SK_BUILD_FOR_UNIX + #elif TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define SK_BUILD_FOR_IOS + #else + #define SK_BUILD_FOR_MAC + #endif + +#endif + +////////////////////////////////////////////////////////////////////// + +#ifdef SK_BUILD_FOR_WIN + #if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict + #endif + #if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT + #endif +#endif + +#if !defined(SK_RESTRICT) + #define SK_RESTRICT __restrict__ +#endif + +#if !defined(SK_WARN_UNUSED_RESULT) + #define SK_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SK_CPU_BENDIAN) && !defined(SK_CPU_LENDIAN) + #if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + #define SK_CPU_BENDIAN + #elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + #define SK_CPU_LENDIAN + #elif defined(__sparc) || defined(__sparc__) || \ + defined(_POWER) || defined(__powerpc__) || \ + defined(__ppc__) || defined(__hppa) || \ + defined(__PPC__) || defined(__PPC64__) || \ + defined(_MIPSEB) || defined(__ARMEB__) || \ + defined(__s390__) || \ + (defined(__sh__) && defined(__BIG_ENDIAN__)) || \ + (defined(__ia64) && defined(__BIG_ENDIAN__)) + #define SK_CPU_BENDIAN + #else + #define SK_CPU_LENDIAN + #endif +#endif + +////////////////////////////////////////////////////////////////////// + +#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + #define SK_CPU_X86 1 +#endif + +/** + * SK_CPU_SSE_LEVEL + * + * If defined, SK_CPU_SSE_LEVEL should be set to the highest supported level. + * On non-intel CPU this should be undefined. + */ + +#define SK_CPU_SSE_LEVEL_SSE1 10 +#define SK_CPU_SSE_LEVEL_SSE2 20 +#define SK_CPU_SSE_LEVEL_SSE3 30 +#define SK_CPU_SSE_LEVEL_SSSE3 31 +#define SK_CPU_SSE_LEVEL_SSE41 41 +#define SK_CPU_SSE_LEVEL_SSE42 42 +#define SK_CPU_SSE_LEVEL_AVX 51 +#define SK_CPU_SSE_LEVEL_AVX2 52 +#define SK_CPU_SSE_LEVEL_AVX512 60 + +// When targetting iOS and using gyp to generate the build files, it is not +// possible to select files to build depending on the architecture (i.e. it +// is not possible to use hand optimized assembly implementation). In that +// configuration SK_BUILD_NO_OPTS is defined. Remove optimisation then. +#ifdef SK_BUILD_NO_OPTS + #define SK_CPU_SSE_LEVEL 0 +#endif + +// Are we in GCC/Clang? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. + #if defined(__AVX512F__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX512 + #elif defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(__SSE4_2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE42 + #elif defined(__SSE4_1__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE41 + #elif defined(__SSSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSSE3 + #elif defined(__SSE3__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE3 + #elif defined(__SSE2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #endif +#endif + +// Are we in VisualStudio? +#ifndef SK_CPU_SSE_LEVEL + // These checks must be done in descending order to ensure we set the highest + // available SSE level. 64-bit intel guarantees at least SSE2 support. + #if defined(__AVX2__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX2 + #elif defined(__AVX__) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_AVX + #elif defined(_M_X64) || defined(_M_AMD64) + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif defined(_M_IX86_FP) + #if _M_IX86_FP >= 2 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE2 + #elif _M_IX86_FP == 1 + #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SSE1 + #endif + #endif +#endif + +////////////////////////////////////////////////////////////////////// +// ARM defines + +#if defined(__arm__) && (!defined(__APPLE__) || !TARGET_IPHONE_SIMULATOR) + #define SK_CPU_ARM32 +#elif defined(__aarch64__) && !defined(SK_BUILD_NO_OPTS) + #define SK_CPU_ARM64 +#endif + +// All 64-bit ARM chips have NEON. Many 32-bit ARM chips do too. +#if !defined(SK_ARM_HAS_NEON) && !defined(SK_BUILD_NO_OPTS) && defined(__ARM_NEON) + #define SK_ARM_HAS_NEON +#endif + +// Really this __APPLE__ check shouldn't be necessary, but it seems that Apple's Clang defines +// __ARM_FEATURE_CRC32 for -arch arm64, even though their chips don't support those instructions! +#if defined(__ARM_FEATURE_CRC32) && !defined(__APPLE__) + #define SK_ARM_HAS_CRC32 +#endif + +////////////////////////////////////////////////////////////////////// + +#if !defined(SKIA_IMPLEMENTATION) + #define SKIA_IMPLEMENTATION 0 +#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 + +#endif diff --git a/skia/include/core/SkRRect.h b/skia/include/core/SkRRect.h new file mode 100644 index 00000000..32fbd12b --- /dev/null +++ b/skia/include/core/SkRRect.h @@ -0,0 +1,529 @@ +/* + * 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/SkRRect.h and docs/SkRRect_Reference.bmh + on 2018-08-10 12:59:44. Additional documentation and examples can be found at: + https://skia.org/user/api/SkRRect_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkRRect_Reference.bmh, run: + bookmaker -b docs -i include/core/SkRRect.h -p + to create an updated version of this file. + */ + +#ifndef SkRRect_DEFINED +#define SkRRect_DEFINED + +#include "SkRect.h" +#include "SkPoint.h" + +class SkPath; +class SkMatrix; + +/** \class SkRRect + SkRRect describes a rounded rectangle with a bounds and a pair of radii for each corner. + The bounds and radii can be set so that SkRRect describes: a rectangle with sharp corners; + a circle; an oval; or a rectangle with one or more rounded corners. + + SkRRect allows implementing CSS properties that describe rounded corners. + SkRRect may have up to eight different radii, one for each axis on each of its four + corners. + + SkRRect may modify the provided parameters when initializing bounds and radii. + If either axis radii is zero or less: radii are stored as zero; corner is square. + If corner curves overlap, radii are proportionally reduced to fit within bounds. +*/ +class SK_API SkRRect { +public: + + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ + SkRRect() = default; + + /** Initializes to copy of rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ + SkRRect(const SkRRect& rrect) = default; + + /** Copies rrect bounds and corner radii. + + @param rrect bounds and corner to copy + @return copy of rrect + */ + SkRRect& operator=(const SkRRect& rrect) = default; + + /** \enum SkRRect::Type + Type describes possible specializations of SkRRect. Each Type is + exclusive; a SkRRect may only have one type. + + Type members become progressively less restrictive; larger values of + Type have more degrees of freedom than smaller values. + */ + enum Type { + kEmpty_Type, //!< zero width or height + kRect_Type, //!< non-zero width and height, and zeroed radii + kOval_Type, //!< non-zero width and height filled with radii + kSimple_Type, //!< non-zero width and height with equal radii + kNinePatch_Type, //!< non-zero width and height with axis-aligned radii + kComplex_Type, //!< non-zero width and height with arbitrary radii + kLastType = kComplex_Type, //!< largest Type value + }; + + /** Returns SkRRect::Type, one of: + kEmpty_Type, kRect_Type, kOval_Type, kSimple_Type, kNinePatch_Type, + kComplex_Type. + + @return SkRRect::Type + */ + Type getType() const { + SkASSERT(this->isValid()); + return static_cast(fType); + } + + /** Returns SkRRect::Type, one of: + kEmpty_Type, kRect_Type, kOval_Type, kSimple_Type, kNinePatch_Type, + kComplex_Type. + + @return SkRRect::Type + */ + Type type() const { return this->getType(); } + + inline bool isEmpty() const { return kEmpty_Type == this->getType(); } + inline bool isRect() const { return kRect_Type == this->getType(); } + inline bool isOval() const { return kOval_Type == this->getType(); } + inline bool isSimple() const { return kSimple_Type == this->getType(); } + inline bool isNinePatch() const { return kNinePatch_Type == this->getType(); } + inline bool isComplex() const { return kComplex_Type == this->getType(); } + + /** Returns span on the x-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return rect().fRight minus rect().fLeft + */ + SkScalar width() const { return fRect.width(); } + + /** Returns span on the y-axis. This does not check if result fits in 32-bit float; + result may be infinity. + + @return rect().fBottom minus rect().fTop + */ + SkScalar height() const { return fRect.height(); } + + /** Returns top-left corner radii. If type() returns kEmpty_Type, kRect_Type, + kOval_Type, or kSimple_Type, returns a value representative of all corner radii. + If type() returns kNinePatch_Type or kComplex_Type, at least one of the + remaining three corners has a different value. + + @return corner radii for simple types + */ + SkVector getSimpleRadii() const { + return fRadii[0]; + } + + /** Sets bounds to zero width and height at (0, 0), the origin. Sets + corner radii to zero and sets type to kEmpty_Type. + */ + void setEmpty() { *this = SkRRect(); } + + /** Sets bounds to sorted rect, and sets corner radii to zero. + If set bounds has width and height, and sets type to kRect_Type; + otherwise, sets type to kEmpty_Type. + + @param rect bounds to set + */ + void setRect(const SkRect& rect) { + if (!this->initializeRect(rect)) { + return; + } + + memset(fRadii, 0, sizeof(fRadii)); + fType = kRect_Type; + + SkASSERT(this->isValid()); + } + + /** Initializes bounds at (0, 0), the origin, with zero width and height. + Initializes corner radii to (0, 0), and sets type of kEmpty_Type. + + @return empty SkRRect + */ + static SkRRect MakeEmpty() { return SkRRect(); } + + /** Initializes to copy of r bounds and zeroes corner radii. + + @param r bounds to copy + @return copy of r + */ + static SkRRect MakeRect(const SkRect& r) { + SkRRect rr; + rr.setRect(r); + return rr; + } + + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + @return oval + */ + static SkRRect MakeOval(const SkRect& oval) { + SkRRect rr; + rr.setOval(oval); + return rr; + } + + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad and yRad are zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + @return rounded rectangle + */ + static SkRRect MakeRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { + SkRRect rr; + rr.setRectXY(rect, xRad, yRad); + return rr; + } + + /** Sets bounds to oval, x-axis radii to half oval.width(), and all y-axis radii + to half oval.height(). If oval bounds is empty, sets to kEmpty_Type. + Otherwise, sets to kOval_Type. + + @param oval bounds of oval + */ + void setOval(const SkRect& oval) { + if (!this->initializeRect(oval)) { + return; + } + + SkScalar xRad = SkScalarHalf(fRect.width()); + SkScalar yRad = SkScalarHalf(fRect.height()); + + for (int i = 0; i < 4; ++i) { + fRadii[i].set(xRad, yRad); + } + fType = kOval_Type; + + SkASSERT(this->isValid()); + } + + /** Sets to rounded rectangle with the same radii for all four corners. + If rect is empty, sets to kEmpty_Type. + Otherwise, if xRad or yRad is zero, sets to kRect_Type. + Otherwise, if xRad is at least half rect.width() and yRad is at least half + rect.height(), sets to kOval_Type. + Otherwise, sets to kSimple_Type. + + @param rect bounds of rounded rectangle + @param xRad x-axis radius of corners + @param yRad y-axis radius of corners + */ + void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); + + /** Sets bounds to rect. Sets radii to (leftRad, topRad), (rightRad, topRad), + (rightRad, bottomRad), (leftRad, bottomRad). + + If rect is empty, sets to kEmpty_Type. + Otherwise, if leftRad and rightRad are zero, sets to kRect_Type. + Otherwise, if topRad and bottomRad are zero, sets to kRect_Type. + Otherwise, if leftRad and rightRad are equal and at least half rect.width(), and + topRad and bottomRad are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if leftRad and rightRad are equal, and topRad and bottomRad are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + Nine patch refers to the nine parts defined by the radii: one center rectangle, + four edge patches, and four corner patches. + + @param rect bounds of rounded rectangle + @param leftRad left-top and left-bottom x-axis radius + @param topRad left-top and right-top y-axis radius + @param rightRad right-top and right-bottom x-axis radius + @param bottomRad left-bottom and right-bottom y-axis radius + */ + void setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad, + SkScalar rightRad, SkScalar bottomRad); + + /** Sets bounds to rect. Sets radii array for individual control of all for corners. + + If rect is empty, sets to kEmpty_Type. + Otherwise, if one of each corner radii are zero, sets to kRect_Type. + Otherwise, if all x-axis radii are equal and at least half rect.width(), and + all y-axis radii are equal at least half rect.height(), sets to kOval_Type. + Otherwise, if all x-axis radii are equal, and all y-axis radii are equal, + sets to kSimple_Type. Otherwise, sets to kNinePatch_Type. + + @param rect bounds of rounded rectangle + @param radii corner x-axis and y-axis radii + */ + void setRectRadii(const SkRect& rect, const SkVector radii[4]); + + /** \enum SkRRect::Corner + The radii are stored: top-left, top-right, bottom-right, bottom-left. + */ + enum Corner { + kUpperLeft_Corner, //!< index of top-left corner radii + kUpperRight_Corner, //!< index of top-right corner radii + kLowerRight_Corner, //!< index of bottom-right corner radii + kLowerLeft_Corner, //!< index of bottom-left corner radii + }; + + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to getBounds(). + + @return bounding box + */ + const SkRect& rect() const { return fRect; } + + /** Returns scalar pair for radius of curve on x-axis and y-axis for one corner. + Both radii may be zero. If not zero, both are positive and finite. + + @param corner one of: kUpperLeft_Corner, kUpperRight_Corner, + kLowerRight_Corner, kLowerLeft_Corner + @return x-axis and y-axis radii for one corner + */ + SkVector radii(Corner corner) const { return fRadii[corner]; } + + /** Returns bounds. Bounds may have zero width or zero height. Bounds right is + greater than or equal to left; bounds bottom is greater than or equal to top. + Result is identical to rect(). + + @return bounding box + */ + const SkRect& getBounds() const { return fRect; } + + /** Returns true if bounds and radii in a are equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are equal + */ + friend bool operator==(const SkRRect& a, const SkRRect& b) { + return a.fRect == b.fRect && SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); + } + + /** Returns true if bounds and radii in a are not equal to bounds and radii in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect bounds and radii to compare + @param b SkRect bounds and radii to compare + @return true if members are not equal + */ + friend bool operator!=(const SkRRect& a, const SkRRect& b) { + return a.fRect != b.fRect || !SkScalarsEqual(&a.fRadii[0].fX, &b.fRadii[0].fX, 8); + } + + /** Copies SkRRect to dst, then insets dst bounds by dx and dy, and adjusts dst + radii by dx and dy. dx and dy may be positive, negative, or zero. dst may be + SkRRect. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + @param dst insets bounds and radii + */ + void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const; + + /** Insets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx added to rect().fLeft, and subtracted from rect().fRight + @param dy added to rect().fTop, and subtracted from rect().fBottom + */ + void inset(SkScalar dx, SkScalar dy) { + this->inset(dx, dy, this); + } + + /** Outsets dst bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half dst bounds width, dst bounds left and right are set to + bounds x-axis center. If dy exceeds half dst bounds height, dst bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, dst bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + @param dst outset bounds and radii + */ + void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const { + this->inset(-dx, -dy, dst); + } + + /** Outsets bounds by dx and dy, and adjusts radii by dx and dy. dx and dy may be + positive, negative, or zero. + + If either corner radius is zero, the corner has no curvature and is unchanged. + Otherwise, if adjusted radius becomes negative, pins radius to zero. + If dx exceeds half bounds width, bounds left and right are set to + bounds x-axis center. If dy exceeds half bounds height, bounds top and + bottom are set to bounds y-axis center. + + If dx or dy cause the bounds to become infinite, bounds is zeroed. + + @param dx subtracted from rect().fLeft, and added to rect().fRight + @param dy subtracted from rect().fTop, and added to rect().fBottom + */ + void outset(SkScalar dx, SkScalar dy) { + this->inset(-dx, -dy, this); + } + + /** Translates SkRRect by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + */ + void offset(SkScalar dx, SkScalar dy) { + fRect.offset(dx, dy); + } + + /** Returns SkRRect translated by (dx, dy). + + @param dx offset added to rect().fLeft and rect().fRight + @param dy offset added to rect().fTop and rect().fBottom + @return SkRRect bounds offset by (dx, dy), with unchanged corner radii + */ + SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const { + return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType); + } + + /** Returns true if rect is inside the bounds and corner radii, and if + SkRRect and rect are not empty. + + @param rect area tested for containment + @return true if SkRRect contains rect + */ + bool contains(const SkRect& rect) const; + + /** Returns true if bounds and radii values are finite and describe a SkRRect + SkRRect::Type that matches getType(). All SkRRect methods construct valid types, + even if the input values are not valid. Invalid SkRRect data can only + be generated by corrupting memory. + + @return true if bounds and radii match type() + */ + bool isValid() const; + + static constexpr size_t kSizeInMemory = 12 * sizeof(SkScalar); + + /** Writes SkRRect to buffer. Writes kSizeInMemory bytes, and returns + kSizeInMemory, the number of bytes written. + + @param buffer storage for SkRRect + @return bytes written, kSizeInMemory + */ + size_t writeToMemory(void* buffer) const; + + /** Reads SkRRect from buffer, reading kSizeInMemory bytes. + Returns kSizeInMemory, bytes read if length is at least kSizeInMemory. + Otherwise, returns zero. + + @param buffer memory to read from + @param length size of buffer + @return bytes read, or 0 if length is less than kSizeInMemory + */ + size_t readFromMemory(const void* buffer, size_t length); + + /** Transforms by SkRRect by matrix, storing result in dst. + Returns true if SkRRect transformed can be represented by another SkRRect. + Returns false if matrix contains transformations other than scale and translate. + + Asserts in debug builds if SkRRect equals dst. + + @param matrix SkMatrix specifying the transform + @param dst SkRRect to store the result + @return true if transformation succeeded. + */ + bool transform(const SkMatrix& matrix, SkRRect* dst) const; + + /** Writes text representation of SkRRect to standard output. + Set asHex true to generate exact binary representations + of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + */ + void dump(bool asHex) const; + + /** Writes text representation of SkRRect 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 + SkRRect from output. + */ + void dump() const { this->dump(false); } + + /** Writes text representation of SkRRect 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 SkRRect. + */ + void dumpHex() const { this->dump(true); } + +private: + static bool AreRectAndRadiiValid(const SkRect&, const SkVector[4]); + + SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type) + : fRect(rect) + , fRadii{radii[0], radii[1], radii[2], radii[3]} + , fType(type) {} + + /** + * Initializes fRect. If the passed in rect is not finite or empty the rrect will be fully + * initialized and false is returned. Otherwise, just fRect is initialized and true is returned. + */ + bool initializeRect(const SkRect&); + + void computeType(); + bool checkCornerContainment(SkScalar x, SkScalar y) const; + void scaleRadii(const SkRect& rect); + + SkRect fRect = SkRect::MakeEmpty(); + // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] + SkVector fRadii[4] = {{0, 0}, {0, 0}, {0,0}, {0,0}}; + // use an explicitly sized type so we're sure the class is dense (no uninitialized bytes) + int32_t fType = kEmpty_Type; + // TODO: add padding so we can use memcpy for flattening and not copy uninitialized data + + // to access fRadii directly + friend class SkPath; + friend class SkRRectPriv; +}; + +#endif diff --git a/skia/include/core/SkRSXform.h b/skia/include/core/SkRSXform.h new file mode 100644 index 00000000..b11dea77 --- /dev/null +++ b/skia/include/core/SkRSXform.h @@ -0,0 +1,69 @@ +/* + * 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 SkRSXform_DEFINED +#define SkRSXform_DEFINED + +#include "SkPoint.h" +#include "SkSize.h" + +/** + * A compressed form of a rotation+scale matrix. + * + * [ fSCos -fSSin fTx ] + * [ fSSin fSCos fTy ] + * [ 0 0 1 ] + */ +struct SkRSXform { + static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) { + SkRSXform xform = { scos, ssin, tx, ty }; + return xform; + } + + /* + * Initialize a new xform based on the scale, rotation (in radians), final tx,ty location + * and anchor-point ax,ay within the src quad. + * + * Note: the anchor point is not normalized (e.g. 0...1) but is in pixels of the src image. + */ + static SkRSXform MakeFromRadians(SkScalar scale, SkScalar radians, SkScalar tx, SkScalar ty, + SkScalar ax, SkScalar ay) { + const SkScalar s = SkScalarSin(radians) * scale; + const SkScalar c = SkScalarCos(radians) * scale; + return Make(c, s, tx + -c * ax + s * ay, ty + -s * ax - c * ay); + } + + SkScalar fSCos; + SkScalar fSSin; + SkScalar fTx; + SkScalar fTy; + + bool rectStaysRect() const { + return 0 == fSCos || 0 == fSSin; + } + + void setIdentity() { + fSCos = 1; + fSSin = fTx = fTy = 0; + } + + void set(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty) { + fSCos = scos; + fSSin = ssin; + fTx = tx; + fTy = ty; + } + + void toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const; + void toQuad(const SkSize& size, SkPoint quad[4]) const { + this->toQuad(size.width(), size.height(), quad); + } + void toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const; +}; + +#endif + diff --git a/skia/include/core/SkRWBuffer.h b/skia/include/core/SkRWBuffer.h new file mode 100644 index 00000000..e59a56bd --- /dev/null +++ b/skia/include/core/SkRWBuffer.h @@ -0,0 +1,111 @@ +/* + * 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 SkRWBuffer_DEFINED +#define SkRWBuffer_DEFINED + +#include "SkRefCnt.h" + +struct SkBufferBlock; +struct SkBufferHead; +class SkRWBuffer; +class SkStreamAsset; + +/** + * Contains a read-only, thread-sharable block of memory. To access the memory, the caller must + * instantiate a local iterator, as the memory is stored in 1 or more contiguous blocks. + */ +class SK_API SkROBuffer : public SkRefCnt { +public: + /** + * Return the logical length of the data owned/shared by this buffer. It may be stored in + * multiple contiguous blocks, accessible via the iterator. + */ + size_t size() const { return fAvailable; } + + class SK_API Iter { + public: + Iter(const SkROBuffer*); + Iter(const sk_sp&); + + void reset(const SkROBuffer*); + + /** + * Return the current continuous block of memory, or nullptr if the iterator is exhausted + */ + const void* data() const; + + /** + * Returns the number of bytes in the current continguous block of memory, or 0 if the + * iterator is exhausted. + */ + size_t size() const; + + /** + * Advance to the next contiguous block of memory, returning true if there is another + * block, or false if the iterator is exhausted. + */ + bool next(); + + private: + const SkBufferBlock* fBlock; + size_t fRemaining; + const SkROBuffer* fBuffer; + }; + +private: + SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* fTail); + virtual ~SkROBuffer(); + + const SkBufferHead* fHead; + const size_t fAvailable; + const SkBufferBlock* fTail; + + friend class SkRWBuffer; +}; + +/** + * Accumulates bytes of memory that are "appended" to it, growing internal storage as needed. + * The growth is done such that at any time in the writer's thread, an RBuffer or StreamAsset + * can be snapped off (and safely passed to another thread). The RBuffer/StreamAsset snapshot + * can see the previously stored bytes, but will be unaware of any future writes. + */ +class SK_API SkRWBuffer { +public: + SkRWBuffer(size_t initialCapacity = 0); + ~SkRWBuffer(); + + size_t size() const { return fTotalUsed; } + + /** + * Append |length| bytes from |buffer|. + * + * If the caller knows in advance how much more data they are going to append, they can + * pass a |reserve| hint (representing the number of upcoming bytes *in addition* to the + * current append), to minimize the number of internal allocations. + */ + void append(const void* buffer, size_t length, size_t reserve = 0); + + sk_sp makeROBufferSnapshot() const { + return sk_sp(new SkROBuffer(fHead, fTotalUsed, fTail)); + } + + std::unique_ptr makeStreamSnapshot() const; + +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif + +private: + SkBufferHead* fHead; + SkBufferBlock* fTail; + size_t fTotalUsed; +}; + +#endif diff --git a/skia/include/core/SkRasterHandleAllocator.h b/skia/include/core/SkRasterHandleAllocator.h new file mode 100644 index 00000000..e1cc8304 --- /dev/null +++ b/skia/include/core/SkRasterHandleAllocator.h @@ -0,0 +1,87 @@ +/* + * 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 SkRasterHandleAllocator_DEFINED +#define SkRasterHandleAllocator_DEFINED + +#include "SkImageInfo.h" + +class SkBitmap; +class SkCanvas; +class SkMatrix; + +/** + * If a client wants to control the allocation of raster layers in a canvas, it should subclass + * SkRasterHandleAllocator. This allocator performs two tasks: + * 1. controls how the memory for the pixels is allocated + * 2. associates a "handle" to a private object that can track the matrix/clip of the SkCanvas + * + * This example allocates a canvas, and defers to the allocator to create the base layer. + * + * std::unique_ptr canvas = SkRasterHandleAllocator::MakeCanvas( + * SkImageInfo::Make(...), + * skstd::make_unique(...), + * nullptr); + * + * If you have already allocated the base layer (and its handle, release-proc etc.) then you + * can pass those in using the last parameter to MakeCanvas(). + * + * Regardless of how the base layer is allocated, each time canvas->saveLayer() is called, + * your allocator's allocHandle() will be called. + */ +class SK_API SkRasterHandleAllocator { +public: + virtual ~SkRasterHandleAllocator() {} + + // The value that is returned to clients of the canvas that has this allocator installed. + typedef void* Handle; + + struct Rec { + // When the allocation goes out of scope, this proc is called to free everything associated + // with it: the pixels, the "handle", etc. This is passed the pixel address and fReleaseCtx. + void (*fReleaseProc)(void* pixels, void* ctx); + void* fReleaseCtx; // context passed to fReleaseProc + void* fPixels; // pixels for this allocation + size_t fRowBytes; // rowbytes for these pixels + Handle fHandle; // public handle returned by SkCanvas::accessTopRasterHandle() + }; + + /** + * Given a requested info, allocate the corresponding pixels/rowbytes, and whatever handle + * is desired to give clients access to those pixels. The rec also contains a proc and context + * which will be called when this allocation goes out of scope. + * + * e.g. + * when canvas->saveLayer() is called, the allocator will be called to allocate the pixels + * for the layer. When canvas->restore() is called, the fReleaseProc will be called. + */ + virtual bool allocHandle(const SkImageInfo&, Rec*) = 0; + + /** + * Clients access the handle for a given layer by calling SkCanvas::accessTopRasterHandle(). + * To allow the handle to reflect the current matrix/clip in the canvs, updateHandle() is + * is called. The subclass is responsible to update the handle as it sees fit. + */ + virtual void updateHandle(Handle, const SkMatrix&, const SkIRect&) = 0; + + /** + * This creates a canvas which will use the allocator to manage pixel allocations, including + * all calls to saveLayer(). + * + * If rec is non-null, then it will be used as the base-layer of pixels/handle. + * If rec is null, then the allocator will be called for the base-layer as well. + */ + static std::unique_ptr MakeCanvas(std::unique_ptr, + const SkImageInfo&, const Rec* rec = nullptr); + +private: + friend class SkBitmapDevice; + + Handle allocBitmap(const SkImageInfo&, SkBitmap*); +}; + +#endif diff --git a/skia/include/core/SkRect.h b/skia/include/core/SkRect.h new file mode 100644 index 00000000..1748955e --- /dev/null +++ b/skia/include/core/SkRect.h @@ -0,0 +1,1560 @@ +/* + * 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/SkRect.h and docs/SkRect_Reference.bmh + on 2018-09-13 13:59:55. Additional documentation and examples can be found at: + https://skia.org/user/api/SkRect_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkRect_Reference.bmh, run: + bookmaker -b docs -i include/core/SkRect.h -p + to create an updated version of this file. + */ + +#ifndef SkRect_DEFINED +#define SkRect_DEFINED + +#include "SkPoint.h" +#include "SkSize.h" +#include "../private/SkSafe32.h" +#include "../private/SkTFitsIn.h" + +#include + +struct SkRect; + +/** \struct SkIRect + SkIRect holds four 32-bit integer coordinates describing the upper and + lower bounds of a rectangle. SkIRect may be created from outer bounds or + from position, width, and height. SkIRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkIRect { + int32_t fLeft; //!< smaller x-axis bounds + int32_t fTop; //!< smaller y-axis bounds + int32_t fRight; //!< larger x-axis bounds + int32_t fBottom; //!< larger y-axis bounds + + /** Returns constructed SkIRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() { + return SkIRect{0, 0, 0, 0}; + } + + /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h + may be negative. + + @param w width of constructed SkIRect + @param h height of constructed SkIRect + @return bounds (0, 0, w, h) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) { + return SkIRect{0, 0, w, h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size values for SkIRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) { + return SkIRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l integer stored in fLeft + @param t integer stored in fTop + @param r integer stored in fRight + @param b integer stored in fBottom + @return bounds (l, t, r, b) + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, + int32_t r, int32_t b) { + return SkIRect{l, t, r, b}; + } + + /** Returns constructed SkIRect set to: (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + static constexpr SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, + int32_t w, int32_t h) { + return { x, y, Sk32_sat_add(x, w), Sk32_sat_add(y, h) }; + } + + /** Returns left edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + int32_t left() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + int32_t top() const { return fTop; } + + /** Returns right edge of SkIRect, if sorted. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + int32_t right() const { return fRight; } + + /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + int32_t bottom() const { return fBottom; } + + /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + int32_t x() const { return fLeft; } + + /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + int32_t y() const { return fTop; } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fRight minus fLeft + */ + int32_t width() const { return Sk32_can_overflow_sub(fRight, fLeft); } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if + result fits in 32-bit signed integer; result may be negative. + + @return fBottom minus fTop + */ + int32_t height() const { return Sk32_can_overflow_sub(fBottom, fTop); } + + /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, + or if result fits in 32-bit signed integer; result may be negative. + + @return SkISize (width, height) + */ + SkISize size() const { return SkISize::Make(this->width(), this->height()); } + + /** Returns span on the x-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling width() since width() might + overflow in its calculation. + + @return fRight minus fLeft cast to int64_t + */ + int64_t width64() const { return (int64_t)fRight - (int64_t)fLeft; } + + /** Returns span on the y-axis. This does not check if SkIRect is sorted, so the + result may be negative. This is safer than calling height() since height() might + overflow in its calculation. + + @return fBottom minus fTop cast to int64_t + */ + int64_t height64() const { return (int64_t)fBottom - (int64_t)fTop; } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width64() or height64(). + + @return true if width64() or height64() are zero or negative + */ + bool isEmpty64() const { return fRight <= fLeft || fBottom <= fTop; } + + /** Returns true if width() or height() are zero or negative. + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + int64_t w = this->width64(); + int64_t h = this->height64(); + if (w <= 0 || h <= 0) { + return true; + } + // Return true if either exceeds int32_t + return !SkTFitsIn(w | h); + } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + identical to corresponding members in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are equal + */ + friend bool operator==(const SkIRect& a, const SkIRect& b) { + return !memcmp(&a, &b, sizeof(a)); + } + + /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not + identical to the corresponding member in b. + + @param a SkIRect to compare + @param b SkIRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkIRect& a, const SkIRect& b) { + return !(a == b); + } + + /** Sets SkIRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { memset(this, 0, sizeof(*this)); } + + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left assigned to fLeft + @param top assigned to fTop + @param right assigned to fRight + @param bottom assigned to fBottom + */ + void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets SkIRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { + this->set(left, top, right, bottom); + } + + /** Sets SkIRect to: (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { + fLeft = x; + fTop = y; + fRight = Sk32_sat_add(x, width); + fBottom = Sk32_sat_add(y, height); + } + + /** Returns SkIRect offset by (dx, dy). + + If dx is negative, SkIRect returned is moved to the left. + If dx is positive, SkIRect returned is moved to the right. + If dy is negative, SkIRect returned is moved upward. + If dy is positive, SkIRect returned is moved downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + @return SkIRect offset by dx and dy, with original width and height + */ + SkIRect makeOffset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Returns SkIRect, inset by (dx, dy). + + If dx is negative, SkIRect returned is wider. + If dx is positive, SkIRect returned is narrower. + If dy is negative, SkIRect returned is taller. + If dy is positive, SkIRect returned is shorter. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + @return SkIRect inset symmetrically left and right, top and bottom + */ + SkIRect makeInset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_add(fLeft, dx), Sk32_sat_add(fTop, dy), + Sk32_sat_sub(fRight, dx), Sk32_sat_sub(fBottom, dy), + }; + } + + /** Returns SkIRect, outset by (dx, dy). + + If dx is negative, SkIRect returned is narrower. + If dx is positive, SkIRect returned is wider. + If dy is negative, SkIRect returned is shorter. + If dy is positive, SkIRect returned is taller. + + @param dx offset subtracted to fLeft and added from fRight + @param dy offset subtracted to fTop and added from fBottom + @return SkIRect outset symmetrically left and right, top and bottom + */ + SkIRect makeOutset(int32_t dx, int32_t dy) const { + return { + Sk32_sat_sub(fLeft, dx), Sk32_sat_sub(fTop, dy), + Sk32_sat_add(fRight, dx), Sk32_sat_add(fBottom, dy), + }; + } + + /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkIRect returned to the left. + If dx is positive, moves SkIRect returned to the right. + If dy is negative, moves SkIRect returned upward. + If dy is positive, moves SkIRect returned downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_add(fRight, dx); + fBottom = Sk32_sat_add(fBottom, dy); + } + + /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkIRect returned to the left. + If delta.fX is positive, moves SkIRect returned to the right. + If delta.fY is negative, moves SkIRect returned upward. + If delta.fY is positive, moves SkIRect returned downward. + + @param delta offset added to SkIRect + */ + void offset(const SkIPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(int32_t newX, int32_t newY) { + fRight = Sk64_pin_to_s32((int64_t)fRight + newX - fLeft); + fBottom = Sk64_pin_to_s32((int64_t)fBottom + newY - fTop); + fLeft = newX; + fTop = newY; + } + + /** Insets SkIRect by (dx,dy). + + If dx is positive, makes SkIRect narrower. + If dx is negative, makes SkIRect wider. + If dy is positive, makes SkIRect shorter. + If dy is negative, makes SkIRect taller. + + @param dx offset added to fLeft and subtracted from fRight + @param dy offset added to fTop and subtracted from fBottom + */ + void inset(int32_t dx, int32_t dy) { + fLeft = Sk32_sat_add(fLeft, dx); + fTop = Sk32_sat_add(fTop, dy); + fRight = Sk32_sat_sub(fRight, dx); + fBottom = Sk32_sat_sub(fBottom, dy); + } + + /** Outsets SkIRect by (dx, dy). + + If dx is positive, makes SkIRect wider. + If dx is negative, makes SkIRect narrower. + If dy is positive, makes SkIRect taller. + If dy is negative, makes SkIRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); } + + /** Adjusts SkIRect by adding dL to fLeft, dT to fTop, dR to fRight, and dB to fBottom. + + If dL is positive, narrows SkIRect on the left. If negative, widens it on the left. + If dT is positive, shrinks SkIRect on the top. If negative, lengthens it on the top. + If dR is positive, narrows SkIRect on the right. If negative, widens it on the right. + If dB is positive, shrinks SkIRect on the bottom. If negative, lengthens it on the bottom. + + The resulting SkIRect is not checked for validity. Thus, if the resulting SkIRect left is + greater than right, the SkIRect will be considered empty. Call sort() after this call + if that is not the desired behavior. + + @param dL offset added to fLeft + @param dT offset added to fTop + @param dR offset added to fRight + @param dB offset added to fBottom + */ + void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB) { + fLeft = Sk32_sat_add(fLeft, dL); + fTop = Sk32_sat_add(fTop, dT); + fRight = Sk32_sat_add(fRight, dR); + fBottom = Sk32_sat_add(fBottom, dB); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkIRect is empty. + + Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and + returns true if constructed area is completely enclosed by SkIRect area. + + @param x test SkIPoint x-coordinate + @param y test SkIPoint y-coordinate + @return true if (x, y) is inside SkIRect + */ + bool contains(int32_t x, int32_t y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Constructs SkIRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkIRect contains construction. + Returns false if SkIRect is empty or construction is empty. + + @param left x-axis minimum of constructed SkIRect + @param top y-axis minimum of constructed SkIRect + @param right x-axis maximum of constructed SkIRect + @param bottom y-axis maximum of constructed SkIRect + @return true if all sides of SkIRect are outside construction + */ + bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { + return left < right && top < bottom && !this->isEmpty() && // check for empties + fLeft <= left && fTop <= top && + fRight >= right && fBottom >= bottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool contains(const SkIRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkIRect contains r. + Returns false if SkIRect is empty or r is empty. + + SkIRect contains r when SkIRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkIRect are outside r + */ + bool contains(const SkRect& r) const; + + /** Constructs SkIRect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkIRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkIRect is empty or construction is empty. + + @param left x-axis minimum of constructed SkIRect + @param top y-axis minimum of constructed SkIRect + @param right x-axis maximum of constructed SkIRect + @param bottom y-axis maximum of constructed SkIRect + @return true if all sides of SkIRect are outside construction + */ + bool containsNoEmptyCheck(int32_t left, int32_t top, + int32_t right, int32_t bottom) const { + SkASSERT(fLeft < fRight && fTop < fBottom); + SkASSERT(left < right && top < bottom); + + return fLeft <= left && fTop <= top && + fRight >= right && fBottom >= bottom; + } + + /** Returns true if SkIRect contains construction. + Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. + + Return is undefined if SkIRect is empty or construction is empty. + + @param r SkIRect contained + @return true if all sides of SkIRect are outside r + */ + bool containsNoEmptyCheck(const SkIRect& r) const { + return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. + + Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. + + @param r limit of result + @return true if r and SkIRect have area in common + */ + bool intersect(const SkIRect& r) { + return this->intersect(*this, r); + } + + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Asserts if either a or b is empty, and if SK_DEBUG is defined. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + bool SK_WARN_UNUSED_RESULT intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { + SkASSERT(!a.isEmpty64() && !b.isEmpty64()); + SkIRect r = { + SkMax32(a.fLeft, b.fLeft), + SkMax32(a.fTop, b.fTop), + SkMin32(a.fRight, b.fRight), + SkMin32(a.fBottom, b.fBottom) + }; + if (r.isEmpty()) { + return false; + } + *this = r; + return true; + } + + /** Returns true if a intersects b, and sets SkIRect to intersection. + Returns false if a does not intersect b, and leaves SkIRect unchanged. + + Returns false if either a or b is empty, leaving SkIRect unchanged. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& a, const SkIRect& b) { + if (a.isEmpty64() || b.isEmpty64()) { + return false; + } + return this->intersectNoEmptyCheck(a, b); + } + + /** Constructs SkIRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkIRect intersects construction, and sets SkIRect to intersection. + Returns false if SkIRect does not intersect construction, and leaves SkIRect unchanged. + + Returns false if either construction or SkIRect is empty, leaving SkIRect unchanged. + + @param left x-axis minimum of constructed SkIRect + @param top y-axis minimum of constructed SkIRect + @param right x-axis maximum of constructed SkIRect + @param bottom y-axis maximum of constructed SkIRect + @return true if construction and SkIRect have area in common + */ + bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { + return this->intersect(*this, {left, top, right, bottom}); + } + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkIRect& a, const SkIRect& b) { + SkIRect dummy; + return dummy.intersect(a, b); + } + + /** Returns true if a intersects b. + Asserts if either a or b is empty, and if SK_DEBUG is defined. + + @param a SkIRect to intersect + @param b SkIRect to intersect + @return true if a and b have area in common + */ + static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) { + SkIRect dummy; + return dummy.intersectNoEmptyCheck(a, b); + } + + /** Constructs SkIRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Sets SkIRect to the union of itself and the construction. + + Has no effect if construction is empty. Otherwise, if SkIRect is empty, sets + SkIRect to construction. + + @param left x-axis minimum of constructed SkIRect + @param top y-axis minimum of constructed SkIRect + @param right x-axis maximum of constructed SkIRect + @param bottom y-axis maximum of constructed SkIRect + */ + void join(int32_t left, int32_t top, int32_t right, int32_t bottom); + + /** Sets SkIRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkIRect is empty, sets SkIRect to r. + + @param r expansion SkIRect + */ + void join(const SkIRect& r) { + this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty, + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkIRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkIRect + */ + SkIRect makeSorted() const { + return MakeLTRB(SkMin32(fLeft, fRight), SkMin32(fTop, fBottom), + SkMax32(fLeft, fRight), SkMax32(fTop, fBottom)); + } + + /** Returns a reference to immutable empty SkIRect, set to (0, 0, 0, 0). + + @return global SkIRect set to all zeroes + */ + static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() { + static const SkIRect gEmpty = { 0, 0, 0, 0 }; + return gEmpty; + } +}; + +/** \struct SkRect + SkRect holds four SkScalar coordinates describing the upper and + lower bounds of a rectangle. SkRect may be created from outer bounds or + from position, width, and height. SkRect describes an area; if its right + is less than or equal to its left, or if its bottom is less than or equal to + its top, it is considered empty. +*/ +struct SK_API SkRect { + SkScalar fLeft; //!< smaller x-axis bounds + SkScalar fTop; //!< smaller y-axis bounds + SkScalar fRight; //!< larger x-axis bounds + SkScalar fBottom; //!< larger y-axis bounds + + /** Returns constructed SkRect set to (0, 0, 0, 0). + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + + @return bounds (0, 0, 0, 0) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { + return SkRect{0, 0, 0, 0}; + } + + /** Returns constructed SkRect set to SkScalar values (0, 0, w, h). Does not + validate input; w or h may be negative. + + Passing integer values may generate a compiler warning since SkRect cannot + represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. + + @param w SkScalar width of constructed SkRect + @param h SkScalar height of constructed SkRect + @return bounds (0, 0, w, h) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) { + return SkRect{0, 0, w, h}; + } + + /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate + input; w or h may be negative. + + Use to avoid a compiler warning that input may lose precision when stored. + Use SkIRect for an exact integer rectangle. + + @param w integer width of constructed SkRect + @param h integer height of constructed SkRect + @return bounds (0, 0, w, h) + */ + static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) { + SkRect r; + r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h)); + return r; + } + + /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not + validate input; size.width() or size.height() may be negative. + + @param size SkScalar values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) { + return SkRect{0, 0, size.fWidth, size.fHeight}; + } + + /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may + result in fLeft greater than fRight, or fTop greater than fBottom. + + @param l SkScalar stored in fLeft + @param t SkScalar stored in fTop + @param r SkScalar stored in fRight + @param b SkScalar stored in fBottom + @return bounds (l, t, r, b) + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, + SkScalar b) { + return SkRect {l, t, r, b}; + } + + /** Returns constructed SkRect set to (x, y, x + w, y + h). + Does not validate input; w or h may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param w added to x and stored in fRight + @param h added to y and stored in fBottom + @return bounds at (x, y) with width w and height h + */ + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, + SkScalar h) { + return SkRect {x, y, x + w, y + h}; + } + + /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). + Does not validate input; size.width() or size.height() may be negative. + + @param size integer values for SkRect width and height + @return bounds (0, 0, size.width(), size.height()) + */ + static SkRect Make(const SkISize& size) { + return MakeIWH(size.width(), size.height()); + } + + /** Returns constructed SkIRect set to irect, promoting integers to scalar. + Does not validate input; fLeft may be greater than fRight, fTop may be greater + than fBottom. + + @param irect integer unsorted bounds + @return irect members converted to SkScalar + */ + static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { + SkRect r; + r.set(SkIntToScalar(irect.fLeft), + SkIntToScalar(irect.fTop), + SkIntToScalar(irect.fRight), + SkIntToScalar(irect.fBottom)); + return r; + } + + /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal + to or greater than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or negative + */ + bool isEmpty() const { + // We write it as the NOT of a non-empty rect, so we will return true if any values + // are NaN. + return !(fLeft < fRight && fTop < fBottom); + } + + /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal + to or less than fBottom. Call sort() to reverse rectangles with negative + width() or height(). + + @return true if width() or height() are zero or positive + */ + bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } + + /** Returns true if all values in the rectangle are finite: SK_ScalarMin or larger, + and SK_ScalarMax or smaller. + + @return true if no member is infinite or NaN + */ + bool isFinite() const { + float accum = 0; + accum *= fLeft; + accum *= fTop; + accum *= fRight; + accum *= fBottom; + + // accum is either NaN or it is finite (zero). + SkASSERT(0 == accum || SkScalarIsNaN(accum)); + + // value==value will be true iff value is not NaN + // TODO: is it faster to say !accum or accum==accum? + return !SkScalarIsNaN(accum); + } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + SkScalar x() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + SkScalar y() const { return fTop; } + + /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fLeft + */ + SkScalar left() const { return fLeft; } + + /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fTop + */ + SkScalar top() const { return fTop; } + + /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. + Call sort() to reverse fLeft and fRight if needed. + + @return fRight + */ + SkScalar right() const { return fRight; } + + /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, + and sort() to reverse fTop and fBottom if needed. + + @return fBottom + */ + SkScalar bottom() const { return fBottom; } + + /** Returns span on the x-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fRight minus fLeft + */ + SkScalar width() const { return fRight - fLeft; } + + /** Returns span on the y-axis. This does not check if SkRect is sorted, or if + result fits in 32-bit float; result may be negative or infinity. + + @return fBottom minus fTop + */ + SkScalar height() const { return fBottom - fTop; } + + /** Returns average of left edge and right edge. Result does not change if SkRect + is sorted. Result may overflow to infinity if SkRect is far from the origin. + + @return midpoint on x-axis + */ + SkScalar centerX() const { + // don't use SkScalarHalf(fLeft + fBottom) as that might overflow before the 0.5 + return SkScalarHalf(fLeft) + SkScalarHalf(fRight); + } + + /** Returns average of top edge and bottom edge. Result does not change if SkRect + is sorted. + + @return midpoint on y-axis + */ + SkScalar centerY() const { + // don't use SkScalarHalf(fTop + fBottom) as that might overflow before the 0.5 + return SkScalarHalf(fTop) + SkScalarHalf(fBottom); + } + + /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are + equal to the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are equal + */ + friend bool operator==(const SkRect& a, const SkRect& b) { + return SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); + } + + /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not + equal the corresponding members in b. + + a and b are not equal if either contain NaN. a and b are equal if members + contain zeroes with different signs. + + @param a SkRect to compare + @param b SkRect to compare + @return true if members are not equal + */ + friend bool operator!=(const SkRect& a, const SkRect& b) { + return !SkScalarsEqual((const SkScalar*)&a, (const SkScalar*)&b, 4); + } + + /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, + bottom-right, bottom-left. + + TODO: Consider adding parameter to control whether quad is clockwise or counterclockwise. + + @param quad storage for corners of SkRect + */ + void toQuad(SkPoint quad[4]) const; + + /** Sets SkRect to (0, 0, 0, 0). + + Many other rectangles are empty; if left is equal to or greater than right, + or if top is equal to or greater than bottom. Setting all members to zero + is a convenience, but does not designate a special empty rectangle. + */ + void setEmpty() { *this = MakeEmpty(); } + + /** Sets SkRect to src, promoting src members from integer to scalar. + Very large values in src may lose precision. + + @param src integer SkRect + */ + void set(const SkIRect& src) { + fLeft = SkIntToScalar(src.fLeft); + fTop = SkIntToScalar(src.fTop); + fRight = SkIntToScalar(src.fRight); + fBottom = SkIntToScalar(src.fBottom); + } + + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { + fLeft = left; + fTop = top; + fRight = right; + fBottom = bottom; + } + + /** Sets SkRect to (left, top, right, bottom). + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left stored in fLeft + @param top stored in fTop + @param right stored in fRight + @param bottom stored in fBottom + */ + void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { + this->set(left, top, right, bottom); + } + + /** Sets SkRect to (left, top, right, bottom). + All parameters are promoted from integer to scalar. + left and right are not sorted; left is not necessarily less than right. + top and bottom are not sorted; top is not necessarily less than bottom. + + @param left promoted to SkScalar and stored in fLeft + @param top promoted to SkScalar and stored in fTop + @param right promoted to SkScalar and stored in fRight + @param bottom promoted to SkScalar and stored in fBottom + */ + void iset(int left, int top, int right, int bottom) { + fLeft = SkIntToScalar(left); + fTop = SkIntToScalar(top); + fRight = SkIntToScalar(right); + fBottom = SkIntToScalar(bottom); + } + + /** Sets SkRect to (0, 0, width, height). + width and height may be zero or negative. width and height are promoted from + integer to SkScalar, large values may lose precision. + + @param width promoted to SkScalar and stored in fRight + @param height promoted to SkScalar and stored in fBottom + */ + void isetWH(int width, int height) { + fLeft = fTop = 0; + fRight = SkIntToScalar(width); + fBottom = SkIntToScalar(height); + } + + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + */ + void set(const SkPoint pts[], int count) { + // set() had been checking for non-finite values, so keep that behavior + // for now. Now that we have setBoundsCheck(), we may decide to make + // set() be simpler/faster, and not check for those. + (void)this->setBoundsCheck(pts, count); + } + + /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, + or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + */ + void setBounds(const SkPoint pts[], int count) { + (void)this->setBoundsCheck(pts, count); + } + + /** Sets to bounds of SkPoint array with count entries. Returns false if count is + zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases + sets SkRect to (0, 0, 0, 0). + + Result is either empty or sorted: fLeft is less than or equal to fRight, and + fTop is less than or equal to fBottom. + + @param pts SkPoint array + @param count entries in array + @return true if all SkPoint values are finite + */ + bool setBoundsCheck(const SkPoint pts[], int count); + + /** Sets to bounds of SkPoint pts array with count entries. If any SkPoint in pts + contains infinity or NaN, all SkRect dimensions are set to NaN. + + @param pts SkPoint array + @param count entries in array + */ + void setBoundsNoCheck(const SkPoint pts[], int count); + + /** Sets bounds to the smallest SkRect enclosing SkPoint p0 and p1. The result is + sorted and may be empty. Does not check to see if values are finite. + + @param p0 corner to include + @param p1 corner to include + */ + void set(const SkPoint& p0, const SkPoint& p1) { + fLeft = SkMinScalar(p0.fX, p1.fX); + fRight = SkMaxScalar(p0.fX, p1.fX); + fTop = SkMinScalar(p0.fY, p1.fY); + fBottom = SkMaxScalar(p0.fY, p1.fY); + } + + /** Sets SkRect to (x, y, x + width, y + height). + Does not validate input; width or height may be negative. + + @param x stored in fLeft + @param y stored in fTop + @param width added to x and stored in fRight + @param height added to y and stored in fBottom + */ + void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) { + fLeft = x; + fTop = y; + fRight = x + width; + fBottom = y + height; + } + + /** Sets SkRect to (0, 0, width, height). Does not validate input; + width or height may be negative. + + @param width stored in fRight + @param height stored in fBottom + */ + void setWH(SkScalar width, SkScalar height) { + fLeft = 0; + fTop = 0; + fRight = width; + fBottom = height; + } + + /** Returns SkRect offset by (dx, dy). + + If dx is negative, SkRect returned is moved to the left. + If dx is positive, SkRect returned is moved to the right. + If dy is negative, SkRect returned is moved upward. + If dy is positive, SkRect returned is moved downward. + + @param dx added to fLeft and fRight + @param dy added to fTop and fBottom + @return SkRect offset on axes, with original width and height + */ + SkRect makeOffset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy); + } + + /** Returns SkRect, inset by (dx, dy). + + If dx is negative, SkRect returned is wider. + If dx is positive, SkRect returned is narrower. + If dy is negative, SkRect returned is taller. + If dy is positive, SkRect returned is shorter. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + @return SkRect inset symmetrically left and right, top and bottom + */ + SkRect makeInset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy); + } + + /** Returns SkRect, outset by (dx, dy). + + If dx is negative, SkRect returned is narrower. + If dx is positive, SkRect returned is wider. + If dy is negative, SkRect returned is shorter. + If dy is positive, SkRect returned is taller. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + @return SkRect outset symmetrically left and right, top and bottom + */ + SkRect makeOutset(SkScalar dx, SkScalar dy) const { + return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy); + } + + /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. + + If dx is negative, moves SkRect to the left. + If dx is positive, moves SkRect to the right. + If dy is negative, moves SkRect upward. + If dy is positive, moves SkRect downward. + + @param dx offset added to fLeft and fRight + @param dy offset added to fTop and fBottom + */ + void offset(SkScalar dx, SkScalar dy) { + fLeft += dx; + fTop += dy; + fRight += dx; + fBottom += dy; + } + + /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to + fTop, fBottom. + + If delta.fX is negative, moves SkRect to the left. + If delta.fX is positive, moves SkRect to the right. + If delta.fY is negative, moves SkRect upward. + If delta.fY is positive, moves SkRect downward. + + @param delta added to SkRect + */ + void offset(const SkPoint& delta) { + this->offset(delta.fX, delta.fY); + } + + /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height + are unchanged. + + @param newX stored in fLeft, preserving width() + @param newY stored in fTop, preserving height() + */ + void offsetTo(SkScalar newX, SkScalar newY) { + fRight += newX - fLeft; + fBottom += newY - fTop; + fLeft = newX; + fTop = newY; + } + + /** Insets SkRect by (dx, dy). + + If dx is positive, makes SkRect narrower. + If dx is negative, makes SkRect wider. + If dy is positive, makes SkRect shorter. + If dy is negative, makes SkRect taller. + + @param dx added to fLeft and subtracted from fRight + @param dy added to fTop and subtracted from fBottom + */ + void inset(SkScalar dx, SkScalar dy) { + fLeft += dx; + fTop += dy; + fRight -= dx; + fBottom -= dy; + } + + /** Outsets SkRect by (dx, dy). + + If dx is positive, makes SkRect wider. + If dx is negative, makes SkRect narrower. + If dy is positive, makes SkRect taller. + If dy is negative, makes SkRect shorter. + + @param dx subtracted to fLeft and added from fRight + @param dy subtracted to fTop and added from fBottom + */ + void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); } + + /** Returns true if SkRect intersects r, and sets SkRect to intersection. + Returns false if SkRect does not intersect r, and leaves SkRect unchanged. + + Returns false if either r or SkRect is empty, leaving SkRect unchanged. + + @param r limit of result + @return true if r and SkRect have area in common + */ + bool intersect(const SkRect& r); + + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect intersects construction, and sets SkRect to intersection. + Returns false if SkRect does not intersect construction, and leaves SkRect unchanged. + + Returns false if either construction or SkRect is empty, leaving SkRect unchanged. + + @param left x-axis minimum of constructed SkRect + @param top y-axis minimum of constructed SkRect + @param right x-axis maximum of constructed SkRect + @param bottom y-axis maximum of constructed SkRect + @return true if construction and SkRect have area in common + */ + bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); + + /** Returns true if a intersects b, and sets SkRect to intersection. + Returns false if a does not intersect b, and leaves SkRect unchanged. + + Returns false if either a or b is empty, leaving SkRect unchanged. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b); + + +private: + static bool Intersects(SkScalar al, SkScalar at, SkScalar ar, SkScalar ab, + SkScalar bl, SkScalar bt, SkScalar br, SkScalar bb) { + SkScalar L = SkMaxScalar(al, bl); + SkScalar R = SkMinScalar(ar, br); + SkScalar T = SkMaxScalar(at, bt); + SkScalar B = SkMinScalar(ab, bb); + return L < R && T < B; + } + +public: + + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Returns true if SkRect intersects construction. + Returns false if either construction or SkRect is empty, or do not intersect. + + @param left x-axis minimum of constructed SkRect + @param top y-axis minimum of constructed SkRect + @param right x-axis maximum of constructed SkRect + @param bottom y-axis maximum of constructed SkRect + @return true if construction and SkRect have area in common + */ + bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { + return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom); + } + + /** Returns true if SkRect intersects r. + Returns false if either r or SkRect is empty, or do not intersect. + + @param r SkRect to intersect + @return true if r and SkRect have area in common + */ + bool intersects(const SkRect& r) const { + return Intersects(fLeft, fTop, fRight, fBottom, + r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if a intersects b. + Returns false if either a or b is empty, or do not intersect. + + @param a SkRect to intersect + @param b SkRect to intersect + @return true if a and b have area in common + */ + static bool Intersects(const SkRect& a, const SkRect& b) { + return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom, + b.fLeft, b.fTop, b.fRight, b.fBottom); + } + + /** Constructs SkRect to intersect from (left, top, right, bottom). Does not sort + construction. + + Sets SkRect to the union of itself and the construction. + + Has no effect if construction is empty. Otherwise, if SkRect is empty, sets + SkRect to construction. + + @param left x-axis minimum of constructed SkRect + @param top y-axis minimum of constructed SkRect + @param right x-axis maximum of constructed SkRect + @param bottom y-axis maximum of constructed SkRect + */ + void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); + + /** Sets SkRect to the union of itself and r. + + Has no effect if r is empty. Otherwise, if SkRect is empty, sets + SkRect to r. + + @param r expansion SkRect + */ + void join(const SkRect& r) { + this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Sets SkRect to the union of itself and r. + + Asserts if r is empty and SK_DEBUG is defined. + If SkRect is empty, sets SkRect to r. + + May produce incorrect results if r is empty. + + @param r expansion SkRect + */ + void joinNonEmptyArg(const SkRect& r) { + SkASSERT(!r.isEmpty()); + // if we are empty, just assign + if (fLeft >= fRight || fTop >= fBottom) { + *this = r; + } else { + this->joinPossiblyEmptyRect(r); + } + } + + /** Sets SkRect to the union of itself and the construction. + + May produce incorrect results if SkRect or r is empty. + + @param r expansion SkRect + */ + void joinPossiblyEmptyRect(const SkRect& r) { + fLeft = SkMinScalar(fLeft, r.left()); + fTop = SkMinScalar(fTop, r.top()); + fRight = SkMaxScalar(fRight, r.right()); + fBottom = SkMaxScalar(fBottom, r.bottom()); + } + + /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. + Returns false if SkRect is empty. + + @param x test SkPoint x-coordinate + @param y test SkPoint y-coordinate + @return true if (x, y) is inside SkRect + */ + bool contains(SkScalar x, SkScalar y) const { + return x >= fLeft && x < fRight && y >= fTop && y < fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= r.fLeft && fTop <= r.fTop && + fRight >= r.fRight && fBottom >= r.fBottom; + } + + /** Returns true if SkRect contains r. + Returns false if SkRect is empty or r is empty. + + SkRect contains r when SkRect area completely includes r area. + + @param r SkIRect contained + @return true if all sides of SkRect are outside r + */ + bool contains(const SkIRect& r) const { + // todo: can we eliminate the this->isEmpty check? + return !r.isEmpty() && !this->isEmpty() && + fLeft <= SkIntToScalar(r.fLeft) && fTop <= SkIntToScalar(r.fTop) && + fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom); + } + + /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @param dst storage for SkIRect + */ + void round(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)); + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkIRect + */ + void roundOut(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)); + } + + /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @param dst storage for SkRect + */ + void roundOut(SkRect* dst) const { + dst->set(SkScalarFloorToScalar(fLeft), + SkScalarFloorToScalar(fTop), + SkScalarCeilToScalar(fRight), + SkScalarCeilToScalar(fBottom)); + } + + /** Sets SkRect by rounding up fLeft and fTop; and discarding the fractional portion + of fRight and fBottom, using + (SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)). + + @param dst storage for SkIRect + */ + void roundIn(SkIRect* dst) const { + SkASSERT(dst); + dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop), + SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom)); + } + + /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect + members, using (SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop), + SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom)). + + @return rounded SkIRect + */ + SkIRect round() const { + SkIRect ir; + this->round(&ir); + return ir; + } + + /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding + up fRight and fBottom, using + (SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop), + SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom)). + + @return rounded SkIRect + */ + SkIRect roundOut() const { + SkIRect ir; + this->roundOut(&ir); + return ir; + } + + /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps + fTop and fBottom if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + */ + void sort() { + using std::swap; + if (fLeft > fRight) { + swap(fLeft, fRight); + } + + if (fTop > fBottom) { + swap(fTop, fBottom); + } + } + + /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and + with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; + and width() and height() will be zero or positive. + + @return sorted SkRect + */ + SkRect makeSorted() const { + return MakeLTRB(SkMinScalar(fLeft, fRight), SkMinScalar(fTop, fBottom), + SkMaxScalar(fLeft, fRight), SkMaxScalar(fTop, fBottom)); + } + + /** Returns pointer to first scalar in SkRect, to treat it as an array with four + entries. + + @return pointer to fLeft + */ + const SkScalar* asScalars() const { return &fLeft; } + + /** Writes text representation of SkRect to standard output. Set asHex to true to + generate exact binary representations of floating point numbers. + + @param asHex true if SkScalar values are written as hexadecimal + */ + void dump(bool asHex) const; + + /** Writes text representation of SkRect 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 SkRect + from output. + */ + void dump() const { this->dump(false); } + + /** Writes text representation of SkRect 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 SkRect. + + Use instead of dump() when submitting + */ + void dumpHex() const { this->dump(true); } +}; + +inline bool SkIRect::contains(const SkRect& r) const { + return !r.isEmpty() && !this->isEmpty() && // check for empties + (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop && + (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom; +} + +#endif diff --git a/skia/include/core/SkRefCnt.h b/skia/include/core/SkRefCnt.h new file mode 100644 index 00000000..28099601 --- /dev/null +++ b/skia/include/core/SkRefCnt.h @@ -0,0 +1,414 @@ +/* + * 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 SkRefCnt_DEFINED +#define SkRefCnt_DEFINED + +#include "SkTypes.h" + +#include +#include +#include +#include +#include +#include +#include + +/** \class SkRefCntBase + + SkRefCntBase is the base class for objects that may be shared by multiple + objects. When an existing owner wants to share a reference, it calls ref(). + When an owner wants to release its reference, it calls unref(). When the + shared object's reference count goes to zero as the result of an unref() + call, its (virtual) destructor is called. It is an error for the + destructor to be called explicitly (or via the object going out of scope on + the stack or calling delete) if getRefCnt() > 1. +*/ +class SK_API SkRefCntBase { +public: + /** Default construct, initializing the reference count to 1. + */ + SkRefCntBase() : fRefCnt(1) {} + + /** Destruct, asserting that the reference count is 1. + */ + virtual ~SkRefCntBase() { + #ifdef SK_DEBUG + SkASSERTF(this->getRefCnt() == 1, "fRefCnt was %d", this->getRefCnt()); + // illegal value, to catch us if we reuse after delete + fRefCnt.store(0, std::memory_order_relaxed); + #endif + } + + /** May return true if the caller is the only owner. + * Ensures that all previous owner's actions are complete. + */ + bool unique() const { + if (1 == fRefCnt.load(std::memory_order_acquire)) { + // The acquire barrier is only really needed if we return true. It + // prevents code conditioned on the result of unique() from running + // until previous owners are all totally done calling unref(). + return true; + } + return false; + } + + /** Increment the reference count. Must be balanced by a call to unref(). + */ + void ref() const { + SkASSERT(this->getRefCnt() > 0); + // No barrier required. + (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); + } + + /** Decrement the reference count. If the reference count is 1 before the + decrement, then delete the object. Note that if this is the case, then + the object needs to have been allocated via new, and not on the stack. + */ + void unref() const { + SkASSERT(this->getRefCnt() > 0); + // A release here acts in place of all releases we "should" have been doing in ref(). + if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // Like unique(), the acquire is only needed on success, to make sure + // code in internal_dispose() doesn't happen before the decrement. + this->internal_dispose(); + } + } + +private: + +#ifdef SK_DEBUG + /** Return the reference count. Use only for debugging. */ + int32_t getRefCnt() const { + return fRefCnt.load(std::memory_order_relaxed); + } +#endif + + /** + * Called when the ref count goes to 0. + */ + virtual void internal_dispose() const { + #ifdef SK_DEBUG + SkASSERT(0 == this->getRefCnt()); + fRefCnt.store(1, std::memory_order_relaxed); + #endif + delete this; + } + + // The following friends are those which override internal_dispose() + // and conditionally call SkRefCnt::internal_dispose(). + friend class SkWeakRefCnt; + + mutable std::atomic fRefCnt; + + SkRefCntBase(SkRefCntBase&&) = delete; + SkRefCntBase(const SkRefCntBase&) = delete; + SkRefCntBase& operator=(SkRefCntBase&&) = delete; + SkRefCntBase& operator=(const SkRefCntBase&) = delete; +}; + +#ifdef SK_REF_CNT_MIXIN_INCLUDE +// It is the responsibility of the following include to define the type SkRefCnt. +// This SkRefCnt should normally derive from SkRefCntBase. +#include SK_REF_CNT_MIXIN_INCLUDE +#else +class SK_API SkRefCnt : public SkRefCntBase { + // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system. + #if defined(SK_BUILD_FOR_GOOGLE3) + public: + void deref() const { this->unref(); } + #endif +}; +#endif + +/////////////////////////////////////////////////////////////////////////////// + +/** Call obj->ref() and return obj. The obj must not be nullptr. + */ +template static inline T* SkRef(T* obj) { + SkASSERT(obj); + obj->ref(); + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->ref() and return obj. + */ +template static inline T* SkSafeRef(T* obj) { + if (obj) { + obj->ref(); + } + return obj; +} + +/** Check if the argument is non-null, and if so, call obj->unref() + */ +template static inline void SkSafeUnref(T* obj) { + if (obj) { + obj->unref(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +// This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16. +// There's only benefit to using this if the deriving class does not otherwise need a vtable. +template +class SkNVRefCnt { +public: + SkNVRefCnt() : fRefCnt(1) {} + ~SkNVRefCnt() { + #ifdef SK_DEBUG + int rc = fRefCnt.load(std::memory_order_relaxed); + SkASSERTF(rc == 1, "NVRefCnt was %d", rc); + #endif + } + + // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same: + // - unique() needs acquire when it returns true, and no barrier if it returns false; + // - ref() doesn't need any barrier; + // - unref() needs a release barrier, and an acquire if it's going to call delete. + + bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); } + void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } + void unref() const { + if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // restore the 1 for our destructor's assert + SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed)); + delete (const Derived*)this; + } + } + void deref() const { this->unref(); } + +private: + mutable std::atomic fRefCnt; + + SkNVRefCnt(SkNVRefCnt&&) = delete; + SkNVRefCnt(const SkNVRefCnt&) = delete; + SkNVRefCnt& operator=(SkNVRefCnt&&) = delete; + SkNVRefCnt& operator=(const SkNVRefCnt&) = delete; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Shared pointer class to wrap classes that support a ref()/unref() interface. + * + * This can be used for classes inheriting from SkRefCnt, but it also works for other + * classes that match the interface, but have different internal choices: e.g. the hosted class + * may have its ref/unref be thread-safe, but that is not assumed/imposed by sk_sp. + */ +template class sk_sp { +public: + using element_type = T; + + constexpr sk_sp() : fPtr(nullptr) {} + constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {} + + /** + * Shares the underlying object by calling ref(), so that both the argument and the newly + * created sk_sp both have a reference to it. + */ + sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {} + template ::value>::type> + sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {} + + /** + * Move the underlying object from the argument to the newly created sk_sp. Afterwards only + * the new sk_sp will have a reference to the object, and the argument will point to null. + * No call to ref() or unref() will be made. + */ + sk_sp(sk_sp&& that) : fPtr(that.release()) {} + template ::value>::type> + sk_sp(sk_sp&& that) : fPtr(that.release()) {} + + /** + * Adopt the bare pointer into the newly created sk_sp. + * No call to ref() or unref() will be made. + */ + explicit sk_sp(T* obj) : fPtr(obj) {} + + /** + * Calls unref() on the underlying object pointer. + */ + ~sk_sp() { + SkSafeUnref(fPtr); + SkDEBUGCODE(fPtr = nullptr); + } + + sk_sp& operator=(std::nullptr_t) { this->reset(); return *this; } + + /** + * Shares the underlying object referenced by the argument by calling ref() on it. If this + * sk_sp previously had a reference to an object (i.e. not null) it will call unref() on that + * object. + */ + sk_sp& operator=(const sk_sp& that) { + if (this != &that) { + this->reset(SkSafeRef(that.get())); + } + return *this; + } + template ::value>::type> + sk_sp& operator=(const sk_sp& that) { + this->reset(SkSafeRef(that.get())); + return *this; + } + + /** + * Move the underlying object from the argument to the sk_sp. If the sk_sp previously held + * a reference to another object, unref() will be called on that object. No call to ref() + * will be made. + */ + sk_sp& operator=(sk_sp&& that) { + this->reset(that.release()); + return *this; + } + template ::value>::type> + sk_sp& operator=(sk_sp&& that) { + this->reset(that.release()); + return *this; + } + + T& operator*() const { + SkASSERT(this->get() != nullptr); + return *this->get(); + } + + explicit operator bool() const { return this->get() != nullptr; } + + T* get() const { return fPtr; } + T* operator->() const { return fPtr; } + + /** + * Adopt the new bare pointer, and call unref() on any previously held object (if not null). + * No call to ref() will be made. + */ + void reset(T* ptr = nullptr) { + // Calling fPtr->unref() may call this->~() or this->reset(T*). + // http://wg21.cmeerw.net/lwg/issue998 + // http://wg21.cmeerw.net/lwg/issue2262 + T* oldPtr = fPtr; + fPtr = ptr; + SkSafeUnref(oldPtr); + } + + /** + * Return the bare pointer, and set the internal object pointer to nullptr. + * The caller must assume ownership of the object, and manage its reference count directly. + * No call to unref() will be made. + */ + T* SK_WARN_UNUSED_RESULT release() { + T* ptr = fPtr; + fPtr = nullptr; + return ptr; + } + + void swap(sk_sp& that) /*noexcept*/ { + using std::swap; + swap(fPtr, that.fPtr); + } + +private: + T* fPtr; +}; + +template inline void swap(sk_sp& a, sk_sp& b) /*noexcept*/ { + a.swap(b); +} + +template inline bool operator==(const sk_sp& a, const sk_sp& b) { + return a.get() == b.get(); +} +template inline bool operator==(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return !a; +} +template inline bool operator==(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return !b; +} + +template inline bool operator!=(const sk_sp& a, const sk_sp& b) { + return a.get() != b.get(); +} +template inline bool operator!=(const sk_sp& a, std::nullptr_t) /*noexcept*/ { + return static_cast(a); +} +template inline bool operator!=(std::nullptr_t, const sk_sp& b) /*noexcept*/ { + return static_cast(b); +} + +template inline bool operator<(const sk_sp& a, const sk_sp& b) { + // Provide defined total order on sk_sp. + // http://wg21.cmeerw.net/lwg/issue1297 + // http://wg21.cmeerw.net/lwg/issue1401 . + return std::less::type>()(a.get(), b.get()); +} +template inline bool operator<(const sk_sp& a, std::nullptr_t) { + return std::less()(a.get(), nullptr); +} +template inline bool operator<(std::nullptr_t, const sk_sp& b) { + return std::less()(nullptr, b.get()); +} + +template inline bool operator<=(const sk_sp& a, const sk_sp& b) { + return !(b < a); +} +template inline bool operator<=(const sk_sp& a, std::nullptr_t) { + return !(nullptr < a); +} +template inline bool operator<=(std::nullptr_t, const sk_sp& b) { + return !(b < nullptr); +} + +template inline bool operator>(const sk_sp& a, const sk_sp& b) { + return b < a; +} +template inline bool operator>(const sk_sp& a, std::nullptr_t) { + return nullptr < a; +} +template inline bool operator>(std::nullptr_t, const sk_sp& b) { + return b < nullptr; +} + +template inline bool operator>=(const sk_sp& a, const sk_sp& b) { + return !(a < b); +} +template inline bool operator>=(const sk_sp& a, std::nullptr_t) { + return !(a < nullptr); +} +template inline bool operator>=(std::nullptr_t, const sk_sp& b) { + return !(nullptr < b); +} + +template +auto operator<<(std::basic_ostream& os, const sk_sp& sp) -> decltype(os << sp.get()) { + return os << sp.get(); +} + +template +sk_sp sk_make_sp(Args&&... args) { + return sk_sp(new T(std::forward(args)...)); +} + +/* + * Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null). + * + * This is different than the semantics of the constructor for sk_sp, which just wraps the ptr, + * effectively "adopting" it. + */ +template sk_sp sk_ref_sp(T* obj) { + return sk_sp(SkSafeRef(obj)); +} + +template sk_sp sk_ref_sp(const T* obj) { + return sk_sp(const_cast(SkSafeRef(obj))); +} + +#endif diff --git a/skia/include/core/SkRegion.h b/skia/include/core/SkRegion.h new file mode 100644 index 00000000..07839f21 --- /dev/null +++ b/skia/include/core/SkRegion.h @@ -0,0 +1,679 @@ +/* + * Copyright 2005 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/SkRegion.h and docs/SkRegion_Reference.bmh + on 2018-08-10 12:59:44. Additional documentation and examples can be found at: + https://skia.org/user/api/SkRegion_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkRegion_Reference.bmh, run: + bookmaker -b docs -i include/core/SkRegion.h -p + to create an updated version of this file. + */ + +#ifndef SkRegion_DEFINED +#define SkRegion_DEFINED + +#include "SkRect.h" + +class SkPath; +class SkRgnBuilder; + +/** \class SkRegion + SkRegion describes the set of pixels used to clip SkCanvas. SkRegion is compact, + efficiently storing a single integer rectangle, or a run length encoded array + of rectangles. SkRegion may reduce the current SkCanvas clip, or may be drawn as + one or more integer rectangles. SkRegion iterator returns the scan lines or + rectangles contained by it, optionally intersecting a bounding rectangle. +*/ +class SK_API SkRegion { + typedef int32_t RunType; +public: + + /** Constructs an empty SkRegion. SkRegion is set to empty bounds + at (0, 0) with zero width and height. + + @return empty SkRegion + */ + SkRegion(); + + /** Constructs a copy of an existing region. + Copy constructor makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return copy of SkRegion + */ + SkRegion(const SkRegion& region); + + /** Constructs a rectangular SkRegion matching the bounds of rect. + + @param rect bounds of constructed SkRegion + @return rectangular SkRegion + */ + explicit SkRegion(const SkIRect& rect); + + /** Releases ownership of any shared data and deletes data if SkRegion is sole owner. + */ + ~SkRegion(); + + /** Constructs a copy of an existing region. + Makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return SkRegion to copy by value + */ + SkRegion& operator=(const SkRegion& region); + + /** Compares SkRegion and other; returns true if they enclose exactly + the same area. + + @param other SkRegion to compare + @return true if SkRegion pair are equivalent + */ + bool operator==(const SkRegion& other) const; + + /** Compares SkRegion and other; returns true if they do not enclose the same area. + + @param other SkRegion to compare + @return true if SkRegion pair are not equivalent + */ + bool operator!=(const SkRegion& other) const { + return !(*this == other); + } + + /** Sets SkRegion to src, and returns true if src bounds is not empty. + This makes SkRegion and src identical by value. Internally, + SkRegion and src share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param src SkRegion to copy + @return copy of src + */ + bool set(const SkRegion& src) { + *this = src; + return !this->isEmpty(); + } + + /** Exchanges SkIRect array of SkRegion and other. swap() internally exchanges pointers, + so it is lightweight and does not allocate memory. + + swap() usage has largely been replaced by operator=(const SkRegion& region). + SkPath do not copy their content on assignment until they are written to, + making assignment as efficient as swap(). + + @param other operator=(const SkRegion& region) set + */ + void swap(SkRegion& other); + + /** Returns true if SkRegion is empty. + Empty SkRegion has bounds width or height less than or equal to zero. + SkRegion() constructs empty SkRegion; setEmpty() + and setRect() with dimensionless data make SkRegion empty. + + @return true if bounds has no width or height + */ + bool isEmpty() const { return fRunHead == emptyRunHeadPtr(); } + + /** Returns true if SkRegion is one SkIRect with positive dimensions. + + @return true if SkRegion contains one SkIRect + */ + bool isRect() const { return fRunHead == kRectRunHeadPtr; } + + /** Returns true if SkRegion is described by more than one rectangle. + + @return true if SkRegion contains more than one SkIRect + */ + bool isComplex() const { return !this->isEmpty() && !this->isRect(); } + + /** Returns minimum and maximum axes values of SkIRect array. + Returns (0, 0, 0, 0) if SkRegion is empty. + + @return combined bounds of all SkIRect elements + */ + const SkIRect& getBounds() const { return fBounds; } + + /** Returns a value that increases with the number of + elements in SkRegion. Returns zero if SkRegion is empty. + Returns one if SkRegion equals SkIRect; otherwise, returns + value greater than one indicating that SkRegion is complex. + + Call to compare SkRegion for relative complexity. + + @return relative complexity + */ + int computeRegionComplexity() const; + + /** Appends outline of SkRegion to path. + Returns true if SkRegion is not empty; otherwise, returns false, and leaves path + unmodified. + + @param path SkPath to append to + @return true if path changed + */ + bool getBoundaryPath(SkPath* path) const; + + /** Constructs an empty SkRegion. SkRegion is set to empty bounds + at (0, 0) with zero width and height. Always returns false. + + @return false + */ + bool setEmpty(); + + /** Constructs a rectangular SkRegion matching the bounds of rect. + If rect is empty, constructs empty and returns false. + + @param rect bounds of constructed SkRegion + @return true if rect is not empty + */ + bool setRect(const SkIRect& rect); + + /** Constructs SkRegion with bounds (left, top, right, bottom). + Returns true if left is less than right and top is less than bottom; otherwise, + constructs empty SkRegion and returns false. + + @param left edge of bounds on x-axis + @param top edge of bounds on y-axis + @param right edge of bounds on x-axis + @param bottom edge of bounds on y-axis + @return rectangular SkRegion + */ + bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom) { + return this->setRect({ left, top, right, bottom }); + } + + /** Constructs SkRegion as the union of SkIRect in rects array. If count is + zero, constructs empty SkRegion. Returns false if constructed SkRegion is empty. + + May be faster than repeated calls to op(). + + @param rects array of SkIRect + @param count array size + @return true if constructed SkRegion is not empty + */ + bool setRects(const SkIRect rects[], int count); + + /** Constructs a copy of an existing region. + Makes two regions identical by value. Internally, region and + the returned result share pointer values. The underlying SkRect array is + copied when modified. + + Creating a SkRegion copy is very efficient and never allocates memory. + SkRegion are always copied by value from the interface; the underlying shared + pointers are not exposed. + + @param region SkRegion to copy by value + @return SkRegion to copy by value + */ + bool setRegion(const SkRegion& region); + + /** Constructs SkRegion to match outline of path within clip. + Returns false if constructed SkRegion is empty. + + Constructed SkRegion draws the same pixels as path through clip when + anti-aliasing is disabled. + + @param path SkPath providing outline + @param clip SkRegion containing path + @return true if constructed SkRegion is not empty + */ + bool setPath(const SkPath& path, const SkRegion& clip); + + /** Returns true if SkRegion intersects rect. + Returns false if either rect or SkRegion is empty, or do not intersect. + + @param rect SkIRect to intersect + @return true if rect and SkRegion have area in common + */ + bool intersects(const SkIRect& rect) const; + + /** Returns true if SkRegion intersects other. + Returns false if either other or SkRegion is empty, or do not intersect. + + @param other SkRegion to intersect + @return true if other and SkRegion have area in common + */ + bool intersects(const SkRegion& other) const; + + /** Returns true if SkIPoint (x, y) is inside SkRegion. + Returns false if SkRegion is empty. + + @param x test SkIPoint x-coordinate + @param y test SkIPoint y-coordinate + @return true if (x, y) is inside SkRegion + */ + bool contains(int32_t x, int32_t y) const; + + /** Returns true if other is completely inside SkRegion. + Returns false if SkRegion or other is empty. + + @param other SkIRect to contain + @return true if other is inside SkRegion + */ + bool contains(const SkIRect& other) const; + + /** Returns true if other is completely inside SkRegion. + Returns false if SkRegion or other is empty. + + @param other SkRegion to contain + @return true if other is inside SkRegion + */ + bool contains(const SkRegion& other) const; + + /** Returns true if SkRegion is a single rectangle and contains r. + May return false even though SkRegion contains r. + + @param r SkIRect to contain + @return true quickly if r points are equal or inside + */ + bool quickContains(const SkIRect& r) const { + return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); + } + + /** Returns true if SkRegion is a single rectangle and contains SkIRect + (left, top, right, bottom). + Returns false if SkRegion is empty or SkIRect (left, top, right, bottom) is empty. + May return false even though SkRegion contains (left, top, right, bottom). + + @param left edge of bounds on x-axis + @param top edge of bounds on y-axis + @param right edge of bounds on x-axis + @param bottom edge of bounds on y-axis + @return true quickly if SkIRect are equal or inside + */ + bool quickContains(int32_t left, int32_t top, int32_t right, + int32_t bottom) const { + SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region + + return left < right && top < bottom && + fRunHead == kRectRunHeadPtr && // this->isRect() + /* fBounds.contains(left, top, right, bottom); */ + fBounds.fLeft <= left && fBounds.fTop <= top && + fBounds.fRight >= right && fBounds.fBottom >= bottom; + } + + /** Returns true if SkRegion does not intersect rect. + Returns true if rect is empty or SkRegion is empty. + May return false even though SkRegion does not intersect rect. + + @param rect SkIRect to intersect + @return true if rect does not intersect + */ + bool quickReject(const SkIRect& rect) const { + return this->isEmpty() || rect.isEmpty() || + !SkIRect::Intersects(fBounds, rect); + } + + /** Returns true if SkRegion does not intersect rgn. + Returns true if rgn is empty or SkRegion is empty. + May return false even though SkRegion does not intersect rgn. + + @param rgn SkRegion to intersect + @return true if rgn does not intersect + */ + bool quickReject(const SkRegion& rgn) const { + return this->isEmpty() || rgn.isEmpty() || + !SkIRect::Intersects(fBounds, rgn.fBounds); + } + + /** Offsets SkRegion by ivector (dx, dy). Has no effect if SkRegion is empty. + + @param dx x-axis offset + @param dy y-axis offset + */ + void translate(int dx, int dy) { this->translate(dx, dy, this); } + + /** Offsets SkRegion by ivector (dx, dy), writing result to dst. SkRegion may be passed + as dst parameter, translating SkRegion in place. Has no effect if dst is nullptr. + If SkRegion is empty, sets dst to empty. + + @param dx x-axis offset + @param dy y-axis offset + @param dst translated result + */ + void translate(int dx, int dy, SkRegion* dst) const; + + /** \enum SkRegion::Op + The logical operations that can be performed when combining two SkRegion. + */ + enum Op { + kDifference_Op, //!< target minus operand + kIntersect_Op, //!< target intersected with operand + kUnion_Op, //!< target unioned with operand + kXOR_Op, //!< target exclusive or with operand + kReverseDifference_Op, //!< operand minus target + kReplace_Op, //!< replace target with operand + kLastOp = kReplace_Op, //!< last operator + }; + + static const int kOpCnt = kLastOp + 1; + + /** Replaces SkRegion with the result of SkRegion op rect. + Returns true if replaced SkRegion is not empty. + + @param rect SkIRect operand + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(const SkIRect& rect, Op op) { + if (this->isRect() && kIntersect_Op == op) { + if (!fBounds.intersect(rect)) { + return this->setEmpty(); + } + return true; + } + return this->op(*this, rect, op); + } + + /** Replaces SkRegion with the result of SkRegion op SkIRect (left, top, right, bottom). + Returns true if replaced SkRegion is not empty. + + @param left edge of bounds on x-axis + @param top edge of bounds on y-axis + @param right edge of bounds on x-axis + @param bottom edge of bounds on y-axis + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(int left, int top, int right, int bottom, Op op) { + SkIRect rect; + rect.set(left, top, right, bottom); + return this->op(*this, rect, op); + } + + /** Replaces SkRegion with the result of SkRegion op rgn. + Returns true if replaced SkRegion is not empty. + + @param rgn SkRegion operand + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } + + /** Replaces SkRegion with the result of rect op rgn. + Returns true if replaced SkRegion is not empty. + + @param rect SkIRect operand + @param rgn SkRegion operand + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(const SkIRect& rect, const SkRegion& rgn, Op op); + + /** Replaces SkRegion with the result of rgn op rect. + Returns true if replaced SkRegion is not empty. + + @param rgn SkRegion operand + @param rect SkIRect operand + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(const SkRegion& rgn, const SkIRect& rect, Op op); + + /** Replaces SkRegion with the result of rgna op rgnb. + Returns true if replaced SkRegion is not empty. + + @param rgna SkRegion operand + @param rgnb SkRegion operand + @param op operator, one of: + kDifference_Op, kIntersect_Op, kUnion_Op, kXOR_Op, kReverseDifference_Op, + kReplace_Op + @return false if result is empty + */ + bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + /** Private. Android framework only. + + @return string representation of SkRegion + */ + char* toString(); +#endif + + /** \class SkRegion::Iterator + Returns sequence of rectangles, sorted along y-axis, then x-axis, that make + up SkRegion. + */ + class SK_API Iterator { + public: + + /** Initializes SkRegion::Iterator with an empty SkRegion. done() on SkRegion::Iterator + returns true. + Call reset() to initialized SkRegion::Iterator at a later time. + + @return empty SkRegion iterator + */ + Iterator() : fRgn(nullptr), fDone(true) {} + + /** Sets SkRegion::Iterator to return elements of SkIRect array in region. + + @param region SkRegion to iterate + @return SkRegion iterator + */ + Iterator(const SkRegion& region); + + /** SkPoint SkRegion::Iterator to start of SkRegion. + Returns true if SkRegion was set; otherwise, returns false. + + @return true if SkRegion was set + */ + bool rewind(); + + /** Resets iterator, using the new SkRegion. + + @param region SkRegion to iterate + */ + void reset(const SkRegion& region); + + /** Returns true if SkRegion::Iterator is pointing to final SkIRect in SkRegion. + + @return true if data parsing is complete + */ + bool done() const { return fDone; } + + /** Advances SkRegion::Iterator to next SkIRect in SkRegion if it is not done. + */ + void next(); + + /** Returns SkIRect element in SkRegion. Does not return predictable results if SkRegion + is empty. + + @return part of SkRegion as SkIRect + */ + const SkIRect& rect() const { return fRect; } + + /** Returns SkRegion if set; otherwise, returns nullptr. + + @return iterated SkRegion + */ + const SkRegion* rgn() const { return fRgn; } + + private: + const SkRegion* fRgn; + const SkRegion::RunType* fRuns; + SkIRect fRect = {0, 0, 0, 0}; + bool fDone; + }; + + /** \class SkRegion::Cliperator + Returns the sequence of rectangles, sorted along y-axis, then x-axis, that make + up SkRegion intersected with the specified clip rectangle. + */ + class SK_API Cliperator { + public: + + /** Sets SkRegion::Cliperator to return elements of SkIRect array in SkRegion within clip. + + @param region SkRegion to iterate + @param clip bounds of iteration + @return SkRegion iterator + */ + Cliperator(const SkRegion& region, const SkIRect& clip); + + /** Returns true if SkRegion::Cliperator is pointing to final SkIRect in SkRegion. + + @return true if data parsing is complete + */ + bool done() { return fDone; } + + /** Advances iterator to next SkIRect in SkRegion contained by clip. + */ + void next(); + + /** Returns SkIRect element in SkRegion, intersected with clip passed to + SkRegion::Cliperator constructor. Does not return predictable results if SkRegion + is empty. + + @return part of SkRegion inside clip as SkIRect + */ + const SkIRect& rect() const { return fRect; } + + private: + Iterator fIter; + SkIRect fClip; + SkIRect fRect = {0, 0, 0, 0}; + bool fDone; + }; + + /** \class SkRegion::Spanerator + Returns the line segment ends within SkRegion that intersect a horizontal line. + */ + class Spanerator { + public: + + /** Sets SkRegion::Spanerator to return line segments in SkRegion on scan line. + + @param region SkRegion to iterate + @param y horizontal line to intersect + @param left bounds of iteration + @param right bounds of iteration + @return SkRegion iterator + */ + Spanerator(const SkRegion& region, int y, int left, int right); + + /** Advances iterator to next span intersecting SkRegion within line segment provided + in constructor. Returns true if interval was found. + + @param left pointer to span start; may be nullptr + @param right pointer to span end; may be nullptr + @return true if interval was found + */ + bool next(int* left, int* right); + + private: + const SkRegion::RunType* fRuns; + int fLeft, fRight; + bool fDone; + }; + + /** Writes SkRegion to buffer, and returns number of bytes written. + If buffer is nullptr, returns number number of bytes that would be written. + + @param buffer storage for binary data + @return size of SkRegion + */ + size_t writeToMemory(void* buffer) const; + + /** Constructs SkRegion from buffer of size length. Returns bytes read. + Returned value will be multiple of four or zero if length was too small. + + @param buffer storage for binary data + @param length size of buffer + @return bytes read + */ + size_t readFromMemory(const void* buffer, size_t length); + +private: + static constexpr int kOpCount = kReplace_Op + 1; + + // T + // [B N L R S] + // S + static constexpr int kRectRegionRuns = 7; + + struct RunHead; + + static RunHead* emptyRunHeadPtr() { return (SkRegion::RunHead*) -1; } + static constexpr RunHead* kRectRunHeadPtr = nullptr; + + // allocate space for count runs + void allocateRuns(int count); + void allocateRuns(int count, int ySpanCount, int intervalCount); + void allocateRuns(const RunHead& src); + + SkDEBUGCODE(void dump() const;) + + SkIRect fBounds; + RunHead* fRunHead; + + void freeRuns(); + + /** + * Return the runs from this region, consing up fake runs if the region + * is empty or a rect. In those 2 cases, we use tmpStorage to hold the + * run data. + */ + const RunType* getRuns(RunType tmpStorage[], int* intervals) const; + + // This is called with runs[] that do not yet have their interval-count + // field set on each scanline. That is computed as part of this call + // (inside ComputeRunBounds). + bool setRuns(RunType runs[], int count); + + int count_runtype_values(int* itop, int* ibot) const; + + bool isValid() const; + + static void BuildRectRuns(const SkIRect& bounds, + RunType runs[kRectRegionRuns]); + + // If the runs define a simple rect, return true and set bounds to that + // rect. If not, return false and ignore bounds. + static bool RunsAreARect(const SkRegion::RunType runs[], int count, + SkIRect* bounds); + + /** + * If the last arg is null, just return if the result is non-empty, + * else store the result in the last arg. + */ + static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); + + friend struct RunHead; + friend class Iterator; + friend class Spanerator; + friend class SkRegionPriv; + friend class SkRgnBuilder; + friend class SkFlatRegion; +}; + +#endif diff --git a/skia/include/core/SkScalar.h b/skia/include/core/SkScalar.h new file mode 100644 index 00000000..ba7cc7cd --- /dev/null +++ b/skia/include/core/SkScalar.h @@ -0,0 +1,205 @@ +/* + * 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 SkScalar_DEFINED +#define SkScalar_DEFINED + +#include "../private/SkFloatingPoint.h" + +#undef SK_SCALAR_IS_FLOAT +#define SK_SCALAR_IS_FLOAT 1 + +typedef float SkScalar; + +#define SK_Scalar1 1.0f +#define SK_ScalarHalf 0.5f +#define SK_ScalarSqrt2 1.41421356f +#define SK_ScalarPI 3.14159265f +#define SK_ScalarTanPIOver8 0.414213562f +#define SK_ScalarRoot2Over2 0.707106781f +#define SK_ScalarMax 3.402823466e+38f +#define SK_ScalarInfinity SK_FloatInfinity +#define SK_ScalarNegativeInfinity SK_FloatNegativeInfinity +#define SK_ScalarNaN SK_FloatNaN + +#define SkScalarFloorToScalar(x) sk_float_floor(x) +#define SkScalarCeilToScalar(x) sk_float_ceil(x) +#define SkScalarRoundToScalar(x) sk_float_floor((x) + 0.5f) +#define SkScalarTruncToScalar(x) sk_float_trunc(x) + +#define SkScalarFloorToInt(x) sk_float_floor2int(x) +#define SkScalarCeilToInt(x) sk_float_ceil2int(x) +#define SkScalarRoundToInt(x) sk_float_round2int(x) + +#define SkScalarAbs(x) sk_float_abs(x) +#define SkScalarCopySign(x, y) sk_float_copysign(x, y) +#define SkScalarMod(x, y) sk_float_mod(x,y) +#define SkScalarSqrt(x) sk_float_sqrt(x) +#define SkScalarPow(b, e) sk_float_pow(b, e) + +#define SkScalarSin(radians) (float)sk_float_sin(radians) +#define SkScalarCos(radians) (float)sk_float_cos(radians) +#define SkScalarTan(radians) (float)sk_float_tan(radians) +#define SkScalarASin(val) (float)sk_float_asin(val) +#define SkScalarACos(val) (float)sk_float_acos(val) +#define SkScalarATan2(y, x) (float)sk_float_atan2(y,x) +#define SkScalarExp(x) (float)sk_float_exp(x) +#define SkScalarLog(x) (float)sk_float_log(x) +#define SkScalarLog2(x) (float)sk_float_log2(x) + +////////////////////////////////////////////////////////////////////////////////////////////////// + +#define SkIntToScalar(x) static_cast(x) +#define SkIntToFloat(x) static_cast(x) +#define SkScalarTruncToInt(x) sk_float_saturate2int(x) + +#define SkScalarToFloat(x) static_cast(x) +#define SkFloatToScalar(x) static_cast(x) +#define SkScalarToDouble(x) static_cast(x) +#define SkDoubleToScalar(x) sk_double_to_float(x) + +#define SK_ScalarMin (-SK_ScalarMax) + +static inline bool SkScalarIsNaN(SkScalar x) { return x != x; } + +/** Returns true if x is not NaN and not infinite + */ +static inline bool SkScalarIsFinite(SkScalar x) { return sk_float_isfinite(x); } + +static inline bool SkScalarsAreFinite(SkScalar a, SkScalar b) { + return sk_float_isfinite(a) && sk_float_isfinite(b); +} + +static inline bool SkScalarsAreFinite(const SkScalar array[], int count) { + SkScalar prod = 0; + for (int i = 0; i < count; ++i) { + prod *= array[i]; + } + // At this point, prod will either be NaN or 0 + return prod == 0; // if prod is NaN, this check will return false +} + +/** + * Variant of SkScalarRoundToInt, that performs the rounding step (adding 0.5) explicitly using + * double, to avoid possibly losing the low bit(s) of the answer before calling floor(). + * + * This routine will likely be slower than SkScalarRoundToInt(), and should only be used when the + * extra precision is known to be valuable. + * + * In particular, this catches the following case: + * SkScalar x = 0.49999997; + * int ix = SkScalarRoundToInt(x); + * SkASSERT(0 == ix); // <--- fails + * ix = SkDScalarRoundToInt(x); + * SkASSERT(0 == ix); // <--- succeeds + */ +static inline int SkDScalarRoundToInt(SkScalar x) { + double xx = x; + xx += 0.5; + return (int)floor(xx); +} + +/** Returns the fractional part of the scalar. */ +static inline SkScalar SkScalarFraction(SkScalar x) { + return x - SkScalarTruncToScalar(x); +} + +static inline SkScalar SkScalarClampMax(SkScalar x, SkScalar max) { + x = SkTMin(x, max); + x = SkTMax(x, 0); + return x; +} + +static inline SkScalar SkScalarPin(SkScalar x, SkScalar min, SkScalar max) { + return SkTPin(x, min, max); +} + +SkScalar SkScalarSinCos(SkScalar radians, SkScalar* cosValue); + +static inline SkScalar SkScalarSquare(SkScalar x) { return x * x; } + +#define SkScalarInvert(x) sk_ieee_float_divide_TODO_IS_DIVIDE_BY_ZERO_SAFE_HERE(SK_Scalar1, (x)) +#define SkScalarAve(a, b) (((a) + (b)) * SK_ScalarHalf) +#define SkScalarHalf(a) ((a) * SK_ScalarHalf) + +#define SkDegreesToRadians(degrees) ((degrees) * (SK_ScalarPI / 180)) +#define SkRadiansToDegrees(radians) ((radians) * (180 / SK_ScalarPI)) + +static inline SkScalar SkMaxScalar(SkScalar a, SkScalar b) { return a > b ? a : b; } +static inline SkScalar SkMinScalar(SkScalar a, SkScalar b) { return a < b ? a : b; } + +static inline bool SkScalarIsInt(SkScalar x) { + return x == SkScalarFloorToScalar(x); +} + +/** + * Returns -1 || 0 || 1 depending on the sign of value: + * -1 if x < 0 + * 0 if x == 0 + * 1 if x > 0 + */ +static inline int SkScalarSignAsInt(SkScalar x) { + return x < 0 ? -1 : (x > 0); +} + +// Scalar result version of above +static inline SkScalar SkScalarSignAsScalar(SkScalar x) { + return x < 0 ? -SK_Scalar1 : ((x > 0) ? SK_Scalar1 : 0); +} + +#define SK_ScalarNearlyZero (SK_Scalar1 / (1 << 12)) + +static inline bool SkScalarNearlyZero(SkScalar x, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x) <= tolerance; +} + +static inline bool SkScalarNearlyEqual(SkScalar x, SkScalar y, + SkScalar tolerance = SK_ScalarNearlyZero) { + SkASSERT(tolerance >= 0); + return SkScalarAbs(x-y) <= tolerance; +} + +/** Linearly interpolate between A and B, based on t. + If t is 0, return A + If t is 1, return B + else interpolate. + t must be [0..SK_Scalar1] +*/ +static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) { + SkASSERT(t >= 0 && t <= SK_Scalar1); + return A + (B - A) * t; +} + +/** Interpolate along the function described by (keys[length], values[length]) + for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length] + clamp to the min or max value. This function was inspired by a desire + to change the multiplier for thickness in fakeBold; therefore it assumes + the number of pairs (length) will be small, and a linear search is used. + Repeated keys are allowed for discontinuous functions (so long as keys is + monotonically increasing), and if key is the value of a repeated scalar in + keys, the first one will be used. However, that may change if a binary + search is used. +*/ +SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[], + const SkScalar values[], int length); + +/* + * Helper to compare an array of scalars. + */ +static inline bool SkScalarsEqual(const SkScalar a[], const SkScalar b[], int n) { + SkASSERT(n >= 0); + for (int i = 0; i < n; ++i) { + if (a[i] != b[i]) { + return false; + } + } + return true; +} + +#endif diff --git a/skia/include/core/SkSerialProcs.h b/skia/include/core/SkSerialProcs.h new file mode 100644 index 00000000..e5a886a3 --- /dev/null +++ b/skia/include/core/SkSerialProcs.h @@ -0,0 +1,73 @@ +/* + * 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 SkSerialProcs_DEFINED +#define SkSerialProcs_DEFINED + +#include "SkImage.h" +#include "SkPicture.h" +#include "SkTypeface.h" + +/** + * A serial-proc is asked to serialize the specified object (e.g. picture or image). + * If a data object is returned, it will be used (even if it is zero-length). + * If null is returned, then Skia will take its default action. + * + * The default action for pictures is to use Skia's internal format. + * The default action for images is to encode either in its native format or PNG. + * The default action for typefaces is to use Skia's internal format. + */ + +typedef sk_sp (*SkSerialPictureProc)(SkPicture*, void* ctx); +typedef sk_sp (*SkSerialImageProc)(SkImage*, void* ctx); +typedef sk_sp (*SkSerialTypefaceProc)(SkTypeface*, void* ctx); + +/** + * Called with the encoded form of a picture (previously written with a custom + * SkSerialPictureProc proc). Return a picture object, or nullptr indicating failure. + */ +typedef sk_sp (*SkDeserialPictureProc)(const void* data, size_t length, void* ctx); + +/** + * Called with the encoded from of an image. The proc can return an image object, or if it + * returns nullptr, then Skia will take its default action to try to create an image from the data. + * + * Note that unlike SkDeserialPictureProc and SkDeserialTypefaceProc, return nullptr from this + * does not indicate failure, but is a signal for Skia to take its default action. + */ +typedef sk_sp (*SkDeserialImageProc)(const void* data, size_t length, void* ctx); + +/** + * Called with the encoded form of a typeface (previously written with a custom + * SkSerialTypefaceProc proc). Return a typeface object, or nullptr indicating failure. + */ +typedef sk_sp (*SkDeserialTypefaceProc)(const void* data, size_t length, void* ctx); + +struct SK_API SkSerialProcs { + SkSerialPictureProc fPictureProc = nullptr; + void* fPictureCtx = nullptr; + + SkSerialImageProc fImageProc = nullptr; + void* fImageCtx = nullptr; + + SkSerialTypefaceProc fTypefaceProc = nullptr; + void* fTypefaceCtx = nullptr; +}; + +struct SK_API SkDeserialProcs { + SkDeserialPictureProc fPictureProc = nullptr; + void* fPictureCtx = nullptr; + + SkDeserialImageProc fImageProc = nullptr; + void* fImageCtx = nullptr; + + SkDeserialTypefaceProc fTypefaceProc = nullptr; + void* fTypefaceCtx = nullptr; +}; + +#endif + diff --git a/skia/include/core/SkShader.h b/skia/include/core/SkShader.h new file mode 100644 index 00000000..2761daa5 --- /dev/null +++ b/skia/include/core/SkShader.h @@ -0,0 +1,276 @@ +/* + * 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 SkShader_DEFINED +#define SkShader_DEFINED + +#include "SkBlendMode.h" +#include "SkColor.h" +#include "SkFilterQuality.h" +#include "SkFlattenable.h" +#include "SkImageInfo.h" +#include "SkMatrix.h" + +class SkArenaAlloc; +class SkBitmap; +class SkColorFilter; +class SkColorSpace; +class SkColorSpaceXformer; +class SkImage; +class SkPath; +class SkPicture; +class SkRasterPipeline; +class GrContext; +class GrFragmentProcessor; + +/** \class SkShader + * + * Shaders specify 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. This makes it easy to create a shader + * once (e.g. bitmap tiling or gradient) and then change its transparency + * w/o having to modify the original shader... only the paint's alpha needs + * to be modified. + */ +class SK_API SkShader : public SkFlattenable { +public: + enum TileMode { + /** replicate the edge color if the shader draws outside of its + * original bounds + */ + kClamp_TileMode, + + /** repeat the shader's image horizontally and vertically */ + kRepeat_TileMode, + + /** repeat the shader's image horizontally and vertically, alternating + * mirror images so that adjacent images always seam + */ + kMirror_TileMode, + + /** + * Only draw within the original domain, return transparent-black everywhere else. + * EXPERIMENTAL -- DO NOT USE YET + */ + kDecal_TileMode, + + kLast_TileMode = kDecal_TileMode, + }; + + static constexpr int kTileModeCount = kLast_TileMode + 1; + + /** + * Returns the local matrix. + * + * FIXME: This can be incorrect for a Shader with its own local matrix + * that is also wrapped via CreateLocalMatrixShader. + */ + const SkMatrix& getLocalMatrix() const; + + /** + * Returns true if the shader is guaranteed to produce only opaque + * colors, subject to the SkPaint using the shader to apply an opaque + * alpha value. Subclasses should override this to allow some + * optimizations. + */ + virtual bool isOpaque() const { return false; } + + /** + * Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this + * if they want to keep it longer than the lifetime of the shader). If not, return nullptr. + */ + SkImage* isAImage(SkMatrix* localMatrix, TileMode xy[2]) const; + + bool isAImage() const { + return this->isAImage(nullptr, nullptr) != nullptr; + } + + /** + * If the shader subclass can be represented as a gradient, asAGradient + * returns the matching GradientType enum (or kNone_GradientType if it + * cannot). Also, if info is not null, asAGradient populates info with + * the relevant (see below) parameters for the gradient. fColorCount + * is both an input and output parameter. On input, it indicates how + * many entries in fColors and fColorOffsets can be used, if they are + * non-NULL. After asAGradient has run, fColorCount indicates how + * many color-offset pairs there are in the gradient. If there is + * insufficient space to store all of the color-offset pairs, fColors + * and fColorOffsets will not be altered. fColorOffsets specifies + * where on the range of 0 to 1 to transition to the given color. + * The meaning of fPoint and fRadius is dependant on the type of gradient. + * + * None: + * info is ignored. + * Color: + * fColorOffsets[0] is meaningless. + * Linear: + * fPoint[0] and fPoint[1] are the end-points of the gradient + * Radial: + * fPoint[0] and fRadius[0] are the center and radius + * Conical: + * fPoint[0] and fRadius[0] are the center and radius of the 1st circle + * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle + * Sweep: + * fPoint[0] is the center of the sweep. + */ + + enum GradientType { + kNone_GradientType, + kColor_GradientType, + kLinear_GradientType, + kRadial_GradientType, + kSweep_GradientType, + kConical_GradientType, + kLast_GradientType = kConical_GradientType, + }; + + struct GradientInfo { + int fColorCount; //!< In-out parameter, specifies passed size + // of fColors/fColorOffsets on input, and + // actual number of colors/offsets on + // output. + SkColor* fColors; //!< The colors in the gradient. + SkScalar* fColorOffsets; //!< The unit offset for color transitions. + SkPoint fPoint[2]; //!< Type specific, see above. + SkScalar fRadius[2]; //!< Type specific, see above. + TileMode fTileMode; //!< The tile mode used. + uint32_t fGradientFlags; //!< see SkGradientShader::Flags + }; + + virtual GradientType asAGradient(GradientInfo* info) const; + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + struct ComposeRec { + const SkShader* fShaderA; + const SkShader* fShaderB; + SkBlendMode fBlendMode; + }; + virtual bool asACompose(ComposeRec*) const { return false; } +#endif + + ////////////////////////////////////////////////////////////////////////// + // Methods to create combinations or variants of shaders + + /** + * Return a shader that will apply the specified localMatrix to this shader. + * The specified matrix will be applied before any matrix associated with this shader. + */ + sk_sp makeWithLocalMatrix(const SkMatrix&) const; + + /** + * Create a new shader that produces the same colors as invoking this shader and then applying + * the colorfilter. + */ + sk_sp makeWithColorFilter(sk_sp) const; + + ////////////////////////////////////////////////////////////////////////// + // Factory methods for stock shaders + + /** + * Call this to create a new "empty" shader, that will not draw anything. + */ + static sk_sp MakeEmptyShader(); + + /** + * Call this to create a new shader that just draws the specified color. This should always + * draw the same as a paint with this color (and no shader). + */ + static sk_sp MakeColorShader(SkColor); + + /** + * Create a shader that draws the specified color (in the specified colorspace). + * + * This works around the limitation that SkPaint::setColor() only takes byte values, and does + * not support specific colorspaces. + */ + static sk_sp MakeColorShader(const SkColor4f&, sk_sp); + + /** + * Compose two shaders together, using two operators: mode and lerp. The resulting colors + * are computed by first combining the src and dst shaders using mode, and then linearly + * interpolating between the dst and result colors using lerp. + * + * result = dst * (1 - lerp) + (src (mode) dst) * lerp + * + * If either shader is nullptr, then this returns nullptr. + * If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1]. + */ + static sk_sp MakeCompose(sk_sp dst, sk_sp src, + SkBlendMode mode, float lerp = 1); + + /* + * DEPRECATED: call MakeCompose. + */ + static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, + SkBlendMode mode) { + return MakeCompose(std::move(dst), std::move(src), mode, 1); + } + + /** + * Compose two shaders together using a weighted average. + * + * result = dst * (1 - lerp) + src * lerp + * + * If either shader is nullptr, then this returns nullptr. + * If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1]. + */ + static sk_sp MakeMixer(sk_sp dst, sk_sp src, float lerp) { + return MakeCompose(std::move(dst), std::move(src), SkBlendMode::kSrc, lerp); + } + + /** Call this to create a new shader that will draw with the specified bitmap. + * + * If the bitmap cannot be used (e.g. has no pixels, or its dimensions + * exceed implementation limits (currently at 64K - 1)) then SkEmptyShader + * may be returned. + * + * If the src is kA8_Config then that mask will be colorized using the color on + * the paint. + * + * @param src The bitmap to use inside the shader + * @param tmx The tiling mode to use when sampling the bitmap in the x-direction. + * @param tmy The tiling mode to use when sampling the bitmap in the y-direction. + * @return Returns a new shader object. Note: this function never returns null. + */ + static sk_sp MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, + const SkMatrix* localMatrix = nullptr); + + // NOTE: You can create an SkImage Shader with SkImage::newShader(). + + /** Call this to create a new shader that will draw with the specified picture. + * + * @param src The picture to use inside the shader (if not NULL, its ref count + * is incremented). The SkPicture must not be changed after + * successfully creating a picture shader. + * @param tmx The tiling mode to use when sampling the bitmap in the x-direction. + * @param tmy The tiling mode to use when sampling the bitmap in the y-direction. + * @param tile The tile rectangle in picture coordinates: this represents the subset + * (or superset) of the picture used when building a tile. It is not + * affected by localMatrix and does not imply scaling (only translation + * and cropping). If null, the tile rect is considered equal to the picture + * bounds. + * @return Returns a new shader object. Note: this function never returns null. + */ + static sk_sp MakePictureShader(sk_sp src, TileMode tmx, TileMode tmy, + const SkMatrix* localMatrix, const SkRect* tile); + + /** + * If this shader can be represented by another shader + a localMatrix, return that shader and + * the localMatrix. If not, return nullptr and ignore the localMatrix parameter. + */ + // TODO: clean up clients, move to SkShaderBase. + virtual sk_sp makeAsALocalMatrixShader(SkMatrix* localMatrix) const; + +private: + SkShader() = default; + friend class SkShaderBase; + + typedef SkFlattenable INHERITED; +}; + +#endif diff --git a/skia/include/core/SkSize.h b/skia/include/core/SkSize.h new file mode 100644 index 00000000..9e871144 --- /dev/null +++ b/skia/include/core/SkSize.h @@ -0,0 +1,92 @@ +/* + * 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 SkSize_DEFINED +#define SkSize_DEFINED + +#include "SkScalar.h" + +struct SkISize { + int32_t fWidth; + int32_t fHeight; + + static SkISize Make(int32_t w, int32_t h) { return {w, h}; } + + static SkISize MakeEmpty() { return {0, 0}; } + + void set(int32_t w, int32_t h) { *this = SkISize{w, h}; } + + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { return 0 == fWidth && 0 == fHeight; } + + /** Returns true if either width or height are <= 0 */ + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + + /** Set the width and height to 0 */ + void setEmpty() { fWidth = fHeight = 0; } + + int32_t width() const { return fWidth; } + int32_t height() const { return fHeight; } + + bool equals(int32_t w, int32_t h) const { return fWidth == w && fHeight == h; } +}; + +static inline bool operator==(const SkISize& a, const SkISize& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +static inline bool operator!=(const SkISize& a, const SkISize& b) { return !(a == b); } + +/////////////////////////////////////////////////////////////////////////////// + +struct SkSize { + SkScalar fWidth; + SkScalar fHeight; + + static SkSize Make(SkScalar w, SkScalar h) { return {w, h}; } + + static SkSize Make(const SkISize& src) { + return {SkIntToScalar(src.width()), SkIntToScalar(src.height())}; + } + + SkSize& operator=(const SkISize& src) { + return *this = SkSize{SkIntToScalar(src.fWidth), SkIntToScalar(src.fHeight)}; + } + + static SkSize MakeEmpty() { return {0, 0}; } + + void set(SkScalar w, SkScalar h) { *this = SkSize{w, h}; } + + /** Returns true iff fWidth == 0 && fHeight == 0 + */ + bool isZero() const { return 0 == fWidth && 0 == fHeight; } + + /** Returns true if either width or height are <= 0 */ + bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } + + /** Set the width and height to 0 */ + void setEmpty() { *this = SkSize{0, 0}; } + + SkScalar width() const { return fWidth; } + SkScalar height() const { return fHeight; } + + bool equals(SkScalar w, SkScalar h) const { return fWidth == w && fHeight == h; } + + SkISize toRound() const { return {SkScalarRoundToInt(fWidth), SkScalarRoundToInt(fHeight)}; } + + SkISize toCeil() const { return {SkScalarCeilToInt(fWidth), SkScalarCeilToInt(fHeight)}; } + + SkISize toFloor() const { return {SkScalarFloorToInt(fWidth), SkScalarFloorToInt(fHeight)}; } +}; + +static inline bool operator==(const SkSize& a, const SkSize& b) { + return a.fWidth == b.fWidth && a.fHeight == b.fHeight; +} + +static inline bool operator!=(const SkSize& a, const SkSize& b) { return !(a == b); } +#endif diff --git a/skia/include/core/SkStream.h b/skia/include/core/SkStream.h new file mode 100644 index 00000000..f1c1a143 --- /dev/null +++ b/skia/include/core/SkStream.h @@ -0,0 +1,515 @@ +/* + * 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 SkStream_DEFINED +#define SkStream_DEFINED + +#include "../private/SkTo.h" +#include "SkData.h" +#include "SkRefCnt.h" +#include "SkScalar.h" + +#include + +class SkStream; +class SkStreamRewindable; +class SkStreamSeekable; +class SkStreamAsset; +class SkStreamMemory; + +/** + * SkStream -- abstraction for a source of bytes. Subclasses can be backed by + * memory, or a file, or something else. + * + * NOTE: + * + * Classic "streams" APIs are sort of async, in that on a request for N + * bytes, they may return fewer than N bytes on a given call, in which case + * the caller can "try again" to get more bytes, eventually (modulo an error) + * receiving their total N bytes. + * + * Skia streams behave differently. They are effectively synchronous, and will + * always return all N bytes of the request if possible. If they return fewer + * (the read() call returns the number of bytes read) then that means there is + * no more data (at EOF or hit an error). The caller should *not* call again + * in hopes of fulfilling more of the request. + */ +class SK_API SkStream { +public: + virtual ~SkStream() {} + SkStream() {} + + /** + * Attempts to open the specified file as a stream, returns nullptr on failure. + */ + static std::unique_ptr MakeFromFile(const char path[]); + + /** Reads or skips size number of bytes. + * If buffer == NULL, skip size bytes, return how many were skipped. + * If buffer != NULL, copy size bytes into buffer, return how many were copied. + * @param buffer when NULL skip size bytes, otherwise copy size bytes into buffer + * @param size the number of bytes to skip or copy + * @return the number of bytes actually read. + */ + virtual size_t read(void* buffer, size_t size) = 0; + + /** Skip size number of bytes. + * @return the actual number bytes that could be skipped. + */ + size_t skip(size_t size) { + return this->read(nullptr, size); + } + + /** + * Attempt to peek at size bytes. + * If this stream supports peeking, copy min(size, peekable bytes) into + * buffer, and return the number of bytes copied. + * If the stream does not support peeking, or cannot peek any bytes, + * return 0 and leave buffer unchanged. + * The stream is guaranteed to be in the same visible state after this + * call, regardless of success or failure. + * @param buffer Must not be NULL, and must be at least size bytes. Destination + * to copy bytes. + * @param size Number of bytes to copy. + * @return The number of bytes peeked/copied. + */ + virtual size_t peek(void* /*buffer*/, size_t /*size*/) const { return 0; } + + /** Returns true when all the bytes in the stream have been read. + * This may return true early (when there are no more bytes to be read) + * or late (after the first unsuccessful read). + */ + virtual bool isAtEnd() const = 0; + + bool SK_WARN_UNUSED_RESULT readS8(int8_t*); + bool SK_WARN_UNUSED_RESULT readS16(int16_t*); + bool SK_WARN_UNUSED_RESULT readS32(int32_t*); + + bool SK_WARN_UNUSED_RESULT readU8(uint8_t* i) { return this->readS8((int8_t*)i); } + bool SK_WARN_UNUSED_RESULT readU16(uint16_t* i) { return this->readS16((int16_t*)i); } + bool SK_WARN_UNUSED_RESULT readU32(uint32_t* i) { return this->readS32((int32_t*)i); } + + bool SK_WARN_UNUSED_RESULT readBool(bool* b) { + uint8_t i; + if (!this->readU8(&i)) { return false; } + *b = (i != 0); + return true; + } + bool SK_WARN_UNUSED_RESULT readScalar(SkScalar*); + bool SK_WARN_UNUSED_RESULT readPackedUInt(size_t*); + +//SkStreamRewindable + /** Rewinds to the beginning of the stream. Returns true if the stream is known + * to be at the beginning after this call returns. + */ + virtual bool rewind() { return false; } + + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned at the beginning of its data. + */ + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + /** Duplicates this stream. If this cannot be done, returns NULL. + * The returned stream will be positioned the same as this stream. + */ + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + +//SkStreamSeekable + /** Returns true if this stream can report it's current position. */ + virtual bool hasPosition() const { return false; } + /** Returns the current position in the stream. If this cannot be done, returns 0. */ + virtual size_t getPosition() const { return 0; } + + /** Seeks to an absolute position in the stream. If this cannot be done, returns false. + * If an attempt is made to seek past the end of the stream, the position will be set + * to the end of the stream. + */ + virtual bool seek(size_t /*position*/) { return false; } + + /** Seeks to an relative offset in the stream. If this cannot be done, returns false. + * If an attempt is made to move to a position outside the stream, the position will be set + * to the closest point within the stream (beginning or end). + */ + virtual bool move(long /*offset*/) { return false; } + +//SkStreamAsset + /** Returns true if this stream can report it's total length. */ + virtual bool hasLength() const { return false; } + /** Returns the total length of the stream. If this cannot be done, returns 0. */ + virtual size_t getLength() const { return 0; } + +//SkStreamMemory + /** Returns the starting address for the data. If this cannot be done, returns NULL. */ + //TODO: replace with virtual const SkData* getData() + virtual const void* getMemoryBase() { return nullptr; } + +private: + virtual SkStream* onDuplicate() const { return nullptr; } + virtual SkStream* onFork() const { return nullptr; } + + SkStream(SkStream&&) = delete; + SkStream(const SkStream&) = delete; + SkStream& operator=(SkStream&&) = delete; + SkStream& operator=(const SkStream&) = delete; +}; + +/** SkStreamRewindable is a SkStream for which rewind and duplicate are required. */ +class SK_API SkStreamRewindable : public SkStream { +public: + bool rewind() override = 0; + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } +private: + SkStreamRewindable* onDuplicate() const override = 0; +}; + +/** SkStreamSeekable is a SkStreamRewindable for which position, seek, move, and fork are required. */ +class SK_API SkStreamSeekable : public SkStreamRewindable { +public: + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + bool hasPosition() const override { return true; } + size_t getPosition() const override = 0; + bool seek(size_t position) override = 0; + bool move(long offset) override = 0; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamSeekable* onDuplicate() const override = 0; + SkStreamSeekable* onFork() const override = 0; +}; + +/** SkStreamAsset is a SkStreamSeekable for which getLength is required. */ +class SK_API SkStreamAsset : public SkStreamSeekable { +public: + bool hasLength() const override { return true; } + size_t getLength() const override = 0; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamAsset* onDuplicate() const override = 0; + SkStreamAsset* onFork() const override = 0; +}; + +/** SkStreamMemory is a SkStreamAsset for which getMemoryBase is required. */ +class SK_API SkStreamMemory : public SkStreamAsset { +public: + const void* getMemoryBase() override = 0; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } +private: + SkStreamMemory* onDuplicate() const override = 0; + SkStreamMemory* onFork() const override = 0; +}; + +class SK_API SkWStream { +public: + virtual ~SkWStream(); + SkWStream() {} + + /** Called to write bytes to a SkWStream. Returns true on success + @param buffer the address of at least size bytes to be written to the stream + @param size The number of bytes in buffer to write to the stream + @return true on success + */ + virtual bool write(const void* buffer, size_t size) = 0; + virtual void flush(); + + virtual size_t bytesWritten() const = 0; + + // helpers + + bool write8(U8CPU value) { + uint8_t v = SkToU8(value); + return this->write(&v, 1); + } + bool write16(U16CPU value) { + uint16_t v = SkToU16(value); + return this->write(&v, 2); + } + bool write32(uint32_t v) { + return this->write(&v, 4); + } + + bool writeText(const char text[]) { + SkASSERT(text); + return this->write(text, strlen(text)); + } + + bool newline() { return this->write("\n", strlen("\n")); } + + bool writeDecAsText(int32_t); + bool writeBigDecAsText(int64_t, int minDigits = 0); + bool writeHexAsText(uint32_t, int minDigits = 0); + bool writeScalarAsText(SkScalar); + + bool writeBool(bool v) { return this->write8(v); } + bool writeScalar(SkScalar); + bool writePackedUInt(size_t); + + bool writeStream(SkStream* input, size_t length); + + /** + * This returns the number of bytes in the stream required to store + * 'value'. + */ + static int SizeOfPackedUInt(size_t value); + +private: + SkWStream(const SkWStream&) = delete; + SkWStream& operator=(const SkWStream&) = delete; +}; + +class SK_API SkNullWStream : public SkWStream { +public: + SkNullWStream() : fBytesWritten(0) {} + + bool write(const void* , size_t n) override { fBytesWritten += n; return true; } + void flush() override {} + size_t bytesWritten() const override { return fBytesWritten; } + +private: + size_t fBytesWritten; +}; + +//////////////////////////////////////////////////////////////////////////////////////// + +#include + +/** A stream that wraps a C FILE* file stream. */ +class SK_API SkFILEStream : public SkStreamAsset { +public: + /** Initialize the stream by calling sk_fopen on the specified path. + * This internal stream will be closed in the destructor. + */ + explicit SkFILEStream(const char path[] = nullptr); + + /** Initialize the stream with an existing C FILE stream. + * The current position of the C FILE stream will be considered the + * beginning of the SkFILEStream. + * The C FILE stream will be closed in the destructor. + */ + explicit SkFILEStream(FILE* file); + + ~SkFILEStream() override; + + static std::unique_ptr Make(const char path[]) { + std::unique_ptr stream(new SkFILEStream(path)); + return stream->isValid() ? std::move(stream) : nullptr; + } + + /** Returns true if the current path could be opened. */ + bool isValid() const { return fFILE != nullptr; } + + /** Close this SkFILEStream. */ + void close(); + + size_t read(void* buffer, size_t size) override; + bool isAtEnd() const override; + + bool rewind() override; + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + +private: + explicit SkFILEStream(std::shared_ptr, size_t size, size_t offset); + explicit SkFILEStream(std::shared_ptr, size_t size, size_t offset, size_t originalOffset); + + SkStreamAsset* onDuplicate() const override; + SkStreamAsset* onFork() const override; + + std::shared_ptr fFILE; + // My own council will I keep on sizes and offsets. + size_t fSize; + size_t fOffset; + size_t fOriginalOffset; + + typedef SkStreamAsset INHERITED; +}; + +class SK_API SkMemoryStream : public SkStreamMemory { +public: + SkMemoryStream(); + + /** We allocate (and free) the memory. Write to it via getMemoryBase() */ + SkMemoryStream(size_t length); + + /** If copyData is true, the stream makes a private copy of the data. */ + SkMemoryStream(const void* data, size_t length, bool copyData = false); + + /** Creates the stream to read from the specified data */ + SkMemoryStream(sk_sp data); + + /** Returns a stream with a copy of the input data. */ + static std::unique_ptr MakeCopy(const void* data, size_t length); + + /** Returns a stream with a bare pointer reference to the input data. */ + static std::unique_ptr MakeDirect(const void* data, size_t length); + + /** Returns a stream with a shared reference to the input data. */ + static std::unique_ptr Make(sk_sp data); + + /** Resets the stream to the specified data and length, + just like the constructor. + if copyData is true, the stream makes a private copy of the data + */ + virtual void setMemory(const void* data, size_t length, + bool copyData = false); + /** Replace any memory buffer with the specified buffer. The caller + must have allocated data with sk_malloc or sk_realloc, since it + will be freed with sk_free. + */ + void setMemoryOwned(const void* data, size_t length); + + sk_sp asData() const { return fData; } + void setData(sk_sp data); + + void skipToAlign4(); + const void* getAtPos(); + + size_t read(void* buffer, size_t size) override; + bool isAtEnd() const override; + + size_t peek(void* buffer, size_t size) const override; + + bool rewind() override; + + std::unique_ptr duplicate() const { + return std::unique_ptr(this->onDuplicate()); + } + + size_t getPosition() const override; + bool seek(size_t position) override; + bool move(long offset) override; + + std::unique_ptr fork() const { + return std::unique_ptr(this->onFork()); + } + + size_t getLength() const override; + + const void* getMemoryBase() override; + +private: + SkMemoryStream* onDuplicate() const override; + SkMemoryStream* onFork() const override; + + sk_sp fData; + size_t fOffset; + + typedef SkStreamMemory INHERITED; +}; + +///////////////////////////////////////////////////////////////////////////////////////////// + +class SK_API SkFILEWStream : public SkWStream { +public: + SkFILEWStream(const char path[]); + ~SkFILEWStream() override; + + /** Returns true if the current path could be opened. + */ + bool isValid() const { return fFILE != nullptr; } + + bool write(const void* buffer, size_t size) override; + void flush() override; + void fsync(); + size_t bytesWritten() const override; + +private: + FILE* fFILE; + + typedef SkWStream INHERITED; +}; + +class SK_API SkDynamicMemoryWStream : public SkWStream { +public: + SkDynamicMemoryWStream() = default; + SkDynamicMemoryWStream(SkDynamicMemoryWStream&&); + SkDynamicMemoryWStream& operator=(SkDynamicMemoryWStream&&); + ~SkDynamicMemoryWStream() override; + + bool write(const void* buffer, size_t size) override; + size_t bytesWritten() const override; + + bool read(void* buffer, size_t offset, size_t size); + + /** More efficient version of read(dst, 0, bytesWritten()). */ + void copyTo(void* dst) const; + bool writeToStream(SkWStream* dst) const; + + /** Equivalent to copyTo() followed by reset(), but may save memory use. */ + void copyToAndReset(void* dst); + + /** Equivalent to writeToStream() followed by reset(), but may save memory use. */ + bool writeToAndReset(SkWStream* dst); + + /** Equivalent to writeToStream() followed by reset(), but may save memory use. + When the dst is also a SkDynamicMemoryWStream, the implementation is constant time. */ + bool writeToAndReset(SkDynamicMemoryWStream* dst); + + /** Prepend this stream to dst, resetting this. */ + void prependToAndReset(SkDynamicMemoryWStream* dst); + + /** Return the contents as SkData, and then reset the stream. */ + sk_sp detachAsData(); + + /** Reset, returning a reader stream with the current content. */ + std::unique_ptr detachAsStream(); + + /** Reset the stream to its original, empty, state. */ + void reset(); + void padToAlign4(); +private: + struct Block; + Block* fHead = nullptr; + Block* fTail = nullptr; + size_t fBytesWrittenBeforeTail = 0; + +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif + + // For access to the Block type. + friend class SkBlockMemoryStream; + friend class SkBlockMemoryRefCnt; + + typedef SkWStream INHERITED; +}; + +#endif diff --git a/skia/include/core/SkString.h b/skia/include/core/SkString.h new file mode 100644 index 00000000..300d9ed8 --- /dev/null +++ b/skia/include/core/SkString.h @@ -0,0 +1,299 @@ +/* + * 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 SkString_DEFINED +#define SkString_DEFINED + +#include "../private/SkTArray.h" +#include "../private/SkTo.h" +#include "SkRefCnt.h" +#include "SkScalar.h" + +#include +#include + +/* Some helper functions for C strings +*/ + +static bool SkStrStartsWith(const char string[], const char prefixStr[]) { + SkASSERT(string); + SkASSERT(prefixStr); + return !strncmp(string, prefixStr, strlen(prefixStr)); +} +static bool SkStrStartsWith(const char string[], const char prefixChar) { + SkASSERT(string); + return (prefixChar == *string); +} + +bool SkStrEndsWith(const char string[], const char suffixStr[]); +bool SkStrEndsWith(const char string[], const char suffixChar); + +int SkStrStartsWithOneOf(const char string[], const char prefixes[]); + +static int SkStrFind(const char string[], const char substring[]) { + const char *first = strstr(string, substring); + if (nullptr == first) return -1; + return SkToInt(first - &string[0]); +} + +static int SkStrFindLastOf(const char string[], const char subchar) { + const char* last = strrchr(string, subchar); + if (nullptr == last) return -1; + return SkToInt(last - &string[0]); +} + +static bool SkStrContains(const char string[], const char substring[]) { + SkASSERT(string); + SkASSERT(substring); + return (-1 != SkStrFind(string, substring)); +} +static bool SkStrContains(const char string[], const char subchar) { + SkASSERT(string); + char tmp[2]; + tmp[0] = subchar; + tmp[1] = '\0'; + return (-1 != SkStrFind(string, tmp)); +} + +static inline char *SkStrDup(const char string[]) { + char *ret = (char *) sk_malloc_throw(strlen(string)+1); + memcpy(ret,string,strlen(string)+1); + return ret; +} + +/* + * The SkStrAppend... methods will write into the provided buffer, assuming it is large enough. + * Each method has an associated const (e.g. SkStrAppendU32_MaxSize) which will be the largest + * value needed for that method's buffer. + * + * char storage[SkStrAppendU32_MaxSize]; + * SkStrAppendU32(storage, value); + * + * Note : none of the SkStrAppend... methods write a terminating 0 to their buffers. Instead, + * the methods return the ptr to the end of the written part of the buffer. This can be used + * to compute the length, and/or know where to write a 0 if that is desired. + * + * char storage[SkStrAppendU32_MaxSize + 1]; + * char* stop = SkStrAppendU32(storage, value); + * size_t len = stop - storage; + * *stop = 0; // valid, since storage was 1 byte larger than the max. + */ + +#define SkStrAppendU32_MaxSize 10 +char* SkStrAppendU32(char buffer[], uint32_t); +#define SkStrAppendU64_MaxSize 20 +char* SkStrAppendU64(char buffer[], uint64_t, int minDigits); + +#define SkStrAppendS32_MaxSize (SkStrAppendU32_MaxSize + 1) +char* SkStrAppendS32(char buffer[], int32_t); +#define SkStrAppendS64_MaxSize (SkStrAppendU64_MaxSize + 1) +char* SkStrAppendS64(char buffer[], int64_t, int minDigits); + +/** + * Floats have at most 8 significant digits, so we limit our %g to that. + * However, the total string could be 15 characters: -1.2345678e-005 + * + * In theory we should only expect up to 2 digits for the exponent, but on + * some platforms we have seen 3 (as in the example above). + */ +#define SkStrAppendScalar_MaxSize 15 + +/** + * Write the scaler in decimal format into buffer, and return a pointer to + * the next char after the last one written. Note: a terminating 0 is not + * written into buffer, which must be at least SkStrAppendScalar_MaxSize. + * Thus if the caller wants to add a 0 at the end, buffer must be at least + * SkStrAppendScalar_MaxSize + 1 bytes large. + */ +#define SkStrAppendScalar SkStrAppendFloat + +char* SkStrAppendFloat(char buffer[], float); + +/** \class SkString + + Light weight class for managing strings. Uses reference + counting to make string assignments and copies very fast + with no extra RAM cost. Assumes UTF8 encoding. +*/ +class SK_API SkString { +public: + SkString(); + explicit SkString(size_t len); + explicit SkString(const char text[]); + SkString(const char text[], size_t len); + SkString(const SkString&); + SkString(SkString&&); + ~SkString(); + + bool isEmpty() const { return 0 == fRec->fLength; } + size_t size() const { return (size_t) fRec->fLength; } + const char* c_str() const { return fRec->data(); } + char operator[](size_t n) const { return this->c_str()[n]; } + + bool equals(const SkString&) const; + bool equals(const char text[]) const; + bool equals(const char text[], size_t len) const; + + bool startsWith(const char prefixStr[]) const { + return SkStrStartsWith(fRec->data(), prefixStr); + } + bool startsWith(const char prefixChar) const { + return SkStrStartsWith(fRec->data(), prefixChar); + } + bool endsWith(const char suffixStr[]) const { + return SkStrEndsWith(fRec->data(), suffixStr); + } + bool endsWith(const char suffixChar) const { + return SkStrEndsWith(fRec->data(), suffixChar); + } + bool contains(const char substring[]) const { + return SkStrContains(fRec->data(), substring); + } + bool contains(const char subchar) const { + return SkStrContains(fRec->data(), subchar); + } + int find(const char substring[]) const { + return SkStrFind(fRec->data(), substring); + } + int findLastOf(const char subchar) const { + return SkStrFindLastOf(fRec->data(), subchar); + } + + friend bool operator==(const SkString& a, const SkString& b) { + return a.equals(b); + } + friend bool operator!=(const SkString& a, const SkString& b) { + return !a.equals(b); + } + + // these methods edit the string + + SkString& operator=(const SkString&); + SkString& operator=(SkString&&); + SkString& operator=(const char text[]); + + char* writable_str(); + char& operator[](size_t n) { return this->writable_str()[n]; } + + void reset(); + /** Destructive resize, does not preserve contents. */ + void resize(size_t len) { this->set(nullptr, len); } + void set(const SkString& src) { *this = src; } + void set(const char text[]); + void set(const char text[], size_t len); + + void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); } + void insert(size_t offset, const char text[]); + void insert(size_t offset, const char text[], size_t len); + void insertUnichar(size_t offset, SkUnichar); + void insertS32(size_t offset, int32_t value); + void insertS64(size_t offset, int64_t value, int minDigits = 0); + void insertU32(size_t offset, uint32_t value); + void insertU64(size_t offset, uint64_t value, int minDigits = 0); + void insertHex(size_t offset, uint32_t value, int minDigits = 0); + void insertScalar(size_t offset, SkScalar); + + void append(const SkString& str) { this->insert((size_t)-1, str); } + void append(const char text[]) { this->insert((size_t)-1, text); } + void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); } + void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); } + void appendS32(int32_t value) { this->insertS32((size_t)-1, value); } + void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); } + void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); } + void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); } + void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); } + void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void prepend(const SkString& str) { this->insert(0, str); } + void prepend(const char text[]) { this->insert(0, text); } + void prepend(const char text[], size_t len) { this->insert(0, text, len); } + void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); } + void prependS32(int32_t value) { this->insertS32(0, value); } + void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); } + void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); } + void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); } + + void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void appendVAList(const char format[], va_list); + void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3); + void prependVAList(const char format[], va_list); + + void remove(size_t offset, size_t length); + + SkString& operator+=(const SkString& s) { this->append(s); return *this; } + SkString& operator+=(const char text[]) { this->append(text); return *this; } + SkString& operator+=(const char c) { this->append(&c, 1); return *this; } + + /** + * Swap contents between this and other. This function is guaranteed + * to never fail or throw. + */ + void swap(SkString& other); + +private: + struct Rec { + public: + constexpr Rec(uint32_t len, int32_t refCnt) + : fLength(len), fRefCnt(refCnt), fBeginningOfData(0) + { } + static sk_sp Make(const char text[], size_t len); + uint32_t fLength; // logically size_t, but we want it to stay 32bits + mutable std::atomic fRefCnt; + char fBeginningOfData; + + char* data() { return &fBeginningOfData; } + const char* data() const { return &fBeginningOfData; } + + void ref() const; + void unref() const; + bool unique() const; + private: + // Ensure the unsized delete is called. + void operator delete(void* p) { ::operator delete(p); } + }; + sk_sp fRec; + +#ifdef SK_DEBUG + void validate() const; +#else + void validate() const {} +#endif + + static const Rec gEmptyRec; +}; + +/// Creates a new string and writes into it using a printf()-style format. +SkString SkStringPrintf(const char* format, ...); +/// This makes it easier to write a caller as a VAR_ARGS function where the format string is +/// optional. +static inline SkString SkStringPrintf() { return SkString(); } + +static inline void swap(SkString& a, SkString& b) { + a.swap(b); +} + +enum SkStrSplitMode { + // Strictly return all results. If the input is ",," and the separator is ',' this will return + // an array of three empty strings. + kStrict_SkStrSplitMode, + + // Only nonempty results will be added to the results. Multiple separators will be + // coalesced. Separators at the beginning and end of the input will be ignored. If the input is + // ",," and the separator is ',', this will return an empty vector. + kCoalesce_SkStrSplitMode +}; + +// Split str on any characters in delimiters into out. (Think, strtok with a sane API.) +void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode, + SkTArray* out); +inline void SkStrSplit(const char* str, const char* delimiters, SkTArray* out) { + SkStrSplit(str, delimiters, kCoalesce_SkStrSplitMode, out); +} + +#endif diff --git a/skia/include/core/SkStrokeRec.h b/skia/include/core/SkStrokeRec.h new file mode 100644 index 00000000..d5470b16 --- /dev/null +++ b/skia/include/core/SkStrokeRec.h @@ -0,0 +1,154 @@ +/* + * 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 SkStrokeRec_DEFINED +#define SkStrokeRec_DEFINED + +#include "../private/SkMacros.h" +#include "SkPaint.h" + +class SkPath; + +SK_BEGIN_REQUIRE_DENSE +class SkStrokeRec { +public: + enum InitStyle { + kHairline_InitStyle, + kFill_InitStyle + }; + SkStrokeRec(InitStyle style); + SkStrokeRec(const SkPaint&, SkPaint::Style, SkScalar resScale = 1); + explicit SkStrokeRec(const SkPaint&, SkScalar resScale = 1); + + enum Style { + kHairline_Style, + kFill_Style, + kStroke_Style, + kStrokeAndFill_Style + }; + + static constexpr int kStyleCount = kStrokeAndFill_Style + 1; + + Style getStyle() const; + SkScalar getWidth() const { return fWidth; } + SkScalar getMiter() const { return fMiterLimit; } + SkPaint::Cap getCap() const { return (SkPaint::Cap)fCap; } + SkPaint::Join getJoin() const { return (SkPaint::Join)fJoin; } + + bool isHairlineStyle() const { + return kHairline_Style == this->getStyle(); + } + + bool isFillStyle() const { + return kFill_Style == this->getStyle(); + } + + void setFillStyle(); + void setHairlineStyle(); + /** + * Specify the strokewidth, and optionally if you want stroke + fill. + * Note, if width==0, then this request is taken to mean: + * strokeAndFill==true -> new style will be Fill + * strokeAndFill==false -> new style will be Hairline + */ + void setStrokeStyle(SkScalar width, bool strokeAndFill = false); + + void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit) { + fCap = cap; + fJoin = join; + fMiterLimit = miterLimit; + } + + SkScalar getResScale() const { + return fResScale; + } + + void setResScale(SkScalar rs) { + SkASSERT(rs > 0 && SkScalarIsFinite(rs)); + fResScale = rs; + } + + /** + * Returns true if this specifes any thick stroking, i.e. applyToPath() + * will return true. + */ + bool needToApply() const { + Style style = this->getStyle(); + return (kStroke_Style == style) || (kStrokeAndFill_Style == style); + } + + /** + * Apply these stroke parameters to the src path, returning the result + * in dst. + * + * If there was no change (i.e. style == hairline or fill) this returns + * false and dst is unchanged. Otherwise returns true and the result is + * stored in dst. + * + * src and dst may be the same path. + */ + bool applyToPath(SkPath* dst, const SkPath& src) const; + + /** + * Apply these stroke parameters to a paint. + */ + void applyToPaint(SkPaint* paint) const; + + /** + * Gives a conservative value for the outset that should applied to a + * geometries bounds to account for any inflation due to applying this + * strokeRec to the geometry. + */ + SkScalar getInflationRadius() const; + + /** + * Equivalent to: + * SkStrokeRec rec(paint, style); + * rec.getInflationRadius(); + * This does not account for other effects on the paint (i.e. path + * effect). + */ + static SkScalar GetInflationRadius(const SkPaint&, SkPaint::Style); + + static SkScalar GetInflationRadius(SkPaint::Join, SkScalar miterLimit, SkPaint::Cap, + SkScalar strokeWidth); + + /** + * Compare if two SkStrokeRecs have an equal effect on a path. + * Equal SkStrokeRecs produce equal paths. Equality of produced + * paths does not take the ResScale parameter into account. + */ + bool hasEqualEffect(const SkStrokeRec& other) const { + if (!this->needToApply()) { + return this->getStyle() == other.getStyle(); + } + return fWidth == other.fWidth && + fMiterLimit == other.fMiterLimit && + fCap == other.fCap && + fJoin == other.fJoin && + fStrokeAndFill == other.fStrokeAndFill; + } + +private: + void init(const SkPaint&, SkPaint::Style, SkScalar resScale); + + SkScalar fResScale; + SkScalar fWidth; + SkScalar fMiterLimit; + // The following three members are packed together into a single u32. + // This is to avoid unnecessary padding and ensure binary equality for + // hashing (because the padded areas might contain garbage values). + // + // fCap and fJoin are larger than needed to avoid having to initialize + // any pad values + uint32_t fCap : 16; // SkPaint::Cap + uint32_t fJoin : 15; // SkPaint::Join + uint32_t fStrokeAndFill : 1; // bool +}; +SK_END_REQUIRE_DENSE + +#endif diff --git a/skia/include/core/SkSurface.h b/skia/include/core/SkSurface.h new file mode 100644 index 00000000..23c3b6a2 --- /dev/null +++ b/skia/include/core/SkSurface.h @@ -0,0 +1,755 @@ +/* + * 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/SkSurface.h and docs/SkSurface_Reference.bmh + on 2018-09-13 13:59:55. Additional documentation and examples can be found at: + https://skia.org/user/api/SkSurface_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkSurface_Reference.bmh, run: + bookmaker -b docs -i include/core/SkSurface.h -p + to create an updated version of this file. + */ + +#ifndef SkSurface_DEFINED +#define SkSurface_DEFINED + +#include "SkRefCnt.h" +#include "SkImage.h" +#include "SkSurfaceProps.h" + +#include "GrTypes.h" + +class SkCanvas; +class SkDeferredDisplayList; +class SkPaint; +class SkSurfaceCharacterization; +class GrBackendRenderTarget; +class GrBackendSemaphore; +class GrBackendTexture; +class GrContext; +class GrRenderTarget; + +/** \class SkSurface + SkSurface is responsible for managing the pixels that a canvas draws into. The pixels can be + allocated either in CPU memory (a raster surface) or on the GPU (a GrRenderTarget surface). + SkSurface takes care of allocating a SkCanvas that will draw into the surface. Call + surface->getCanvas() to use that canvas (but don't delete it, it is owned by the surface). + SkSurface always has non-zero dimensions. If there is a request for a new surface, and either + of the requested dimensions are zero, then nullptr will be returned. +*/ +class SK_API SkSurface : public SkRefCnt { +public: + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of 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 imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterDirect(const SkImageInfo& imageInfo, void* pixels, + size_t rowBytes, + const SkSurfaceProps* surfaceProps = nullptr); + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + releaseProc is called with pixels and context when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + pixels is not nullptr; + rowBytes is large enough to contain info width pixels of 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 imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param pixels pointer to destination pixels buffer + @param rowBytes interval from one SkSurface row to the next + @param releaseProc called when SkSurface is deleted; may be nullptr + @param context passed to releaseProc; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterDirectReleaseProc(const SkImageInfo& imageInfo, void* pixels, + size_t rowBytes, + void (*releaseProc)(void* pixels, void* context), + void* context, const SkSurfaceProps* surfaceProps = nullptr); + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is imageInfo.height() times + rowBytes, or times imageInfo.minRowBytes() if rowBytes is zero. + Pixel memory is deleted when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface; + rowBytes is large enough to contain info width pixels of SkColorType, or is zero. + + If rowBytes is not zero, subsequent images returned by makeImageSnapshot() + have the same rowBytes. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param rowBytes interval from one SkSurface row to the next; may be zero + @param surfaceProps LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRaster(const SkImageInfo& imageInfo, size_t rowBytes, + const SkSurfaceProps* surfaceProps); + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is imageInfo.height() times + imageInfo.minRowBytes(). + Pixel memory is deleted when SkSurface is deleted. + + SkSurface is returned if all parameters are valid. + Valid parameters include: + info dimensions are greater than zero; + info contains SkColorType and SkAlphaType supported by raster surface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width and height must be greater than zero + @param props LCD striping orientation and setting for device independent fonts; + may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRaster(const SkImageInfo& imageInfo, + const SkSurfaceProps* props = nullptr) { + return MakeRaster(imageInfo, 0, props); + } + + /** Allocates raster SkSurface. SkCanvas returned by SkSurface draws directly into pixels. + Allocates and zeroes pixel memory. Pixel memory size is height times width times + four. Pixel memory is deleted when SkSurface is deleted. + + Internally, sets SkImageInfo to width, height, native color type, and + kPremul_SkAlphaType. + + SkSurface is returned if width and height are greater than zero. + + Use to create SkSurface that matches SkPMColor, the native pixel arrangement on + the platform. SkSurface drawn to output device skips converting its pixel format. + + @param width pixel column count; must be greater than zero + @param height pixel row count; must be greater than zero + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRasterN32Premul(int width, int height, + const SkSurfaceProps* surfaceProps = nullptr) { + return MakeRaster(SkImageInfo::MakeN32Premul(width, height), surfaceProps); + } + + /** Wraps a GPU-backed texture into SkSurface. Caller must ensure the texture is + valid for the lifetime of returned SkSurface. If sampleCnt greater than zero, + creates an intermediate MSAA SkSurface which is used for drawing backendTexture. + + SkSurface is returned if all parameters are valid. backendTexture is valid if + its pixel configuration agrees with colorSpace and context; for instance, if + backendTexture has an sRGB configuration, then context must support sRGB, + and colorSpace must be present. Further, backendTexture width and height must + not exceed context capabilities, and the context must be able to support + back-end textures. + + If SK_SUPPORT_GPU is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param backendTexture texture residing on GPU + @param origin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin + @param sampleCnt samples per pixel, or 0 to disable full scene anti-aliasing + @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 colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeFromBackendTexture(GrContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, int sampleCnt, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps); + + /** Wraps a GPU-backed buffer into SkSurface. Caller must ensure backendRenderTarget + is valid for the lifetime of returned SkSurface. + + SkSurface is returned if all parameters are valid. backendRenderTarget is valid if + its pixel configuration agrees with colorSpace and context; for instance, if + backendRenderTarget has an sRGB configuration, then context must support sRGB, + and colorSpace must be present. Further, backendRenderTarget width and height must + not exceed context capabilities, and the context must be able to support + back-end render targets. + + If SK_SUPPORT_GPU is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param backendRenderTarget GPU intermediate memory buffer + @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 colorSpace range of colors + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeFromBackendRenderTarget(GrContext* context, + const GrBackendRenderTarget& backendRenderTarget, + GrSurfaceOrigin origin, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps); + + /** Wraps a GPU-backed texture into SkSurface. Caller must ensure backendTexture is + valid for the lifetime of returned SkSurface. If sampleCnt greater than zero, + creates an intermediate MSAA SkSurface which is used for drawing backendTexture. + + SkSurface is returned if all parameters are valid. backendTexture is valid if + its pixel configuration agrees with colorSpace and context; for instance, if + backendTexture has an sRGB configuration, then context must support sRGB, + and colorSpace must be present. Further, backendTexture width and height must + not exceed context capabilities. + + Returned SkSurface is available only for drawing into, and cannot generate an + SkImage. + + If SK_SUPPORT_GPU is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param backendTexture texture residing on GPU + @param origin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin + @param sampleCnt samples per pixel, or 0 to disable full scene anti-aliasing + @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 colorSpace range of colors; may be nullptr + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeFromBackendTextureAsRenderTarget(GrContext* context, + const GrBackendTexture& backendTexture, + GrSurfaceOrigin origin, + int sampleCnt, + SkColorType colorType, + sk_sp colorSpace, + const SkSurfaceProps* surfaceProps); + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + sampleCount requests the number of samples per pixel. + Pass zero to disable multi-sample anti-aliasing. The request is rounded + up to the next supported count, or rounded down if it is larger than the + maximum supported count. + + surfaceOrigin pins either the top-left or the bottom-left corner to the origin. + + shouldCreateWithMips hints that SkImage returned by makeImageSnapshot() is mip map. + + If SK_SUPPORT_GPU is defined as zero, has no effect and returns nullptr. + + @param context GPU context + @param budgeted one of: SkBudgeted::kNo, SkBudgeted::kYes + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace; + width, or height, or both, may be zero + @param sampleCount samples per pixel, or 0 to disable full scene anti-aliasing + @param surfaceOrigin one of: kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin + @param surfaceProps LCD striping orientation and setting for device independent + fonts; may be nullptr + @param shouldCreateWithMips hint that SkSurface will host mip map images + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrContext* context, SkBudgeted budgeted, + const SkImageInfo& imageInfo, + int sampleCount, GrSurfaceOrigin surfaceOrigin, + const SkSurfaceProps* surfaceProps, + bool shouldCreateWithMips = false); + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + sampleCount requests the number of samples per pixel. + Pass zero to disable multi-sample anti-aliasing. The request is rounded + up to the next supported count, or rounded down if it is larger than the + maximum supported count. + + SkSurface bottom-left corner is pinned to the origin. + + @param context GPU context + @param budgeted one of: SkBudgeted::kNo, SkBudgeted::kYes + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width, or height, or both, may be zero + @param sampleCount samples per pixel, or 0 to disable multi-sample anti-aliasing + @param props LCD striping orientation and setting for device independent + fonts; may be nullptr + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrContext* context, SkBudgeted budgeted, + const SkImageInfo& imageInfo, int sampleCount, + const SkSurfaceProps* props) { + return MakeRenderTarget(context, budgeted, imageInfo, sampleCount, + kBottomLeft_GrSurfaceOrigin, props); + } + + /** Returns SkSurface on GPU indicated by context. Allocates memory for + pixels, based on the width, height, and SkColorType in SkImageInfo. budgeted + selects whether allocation for pixels is tracked by context. imageInfo + describes the pixel format in SkColorType, and transparency in + SkAlphaType, and color matching in SkColorSpace. + + SkSurface bottom-left corner is pinned to the origin. + + @param context GPU context + @param budgeted one of: SkBudgeted::kNo, SkBudgeted::kYes + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of raster surface; width, or height, or both, may be zero + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrContext* context, SkBudgeted budgeted, + const SkImageInfo& imageInfo) { + if (!imageInfo.width() || !imageInfo.height()) { + return nullptr; + } + return MakeRenderTarget(context, budgeted, imageInfo, 0, kBottomLeft_GrSurfaceOrigin, + nullptr); + } + + /** Returns SkSurface on GPU indicated by context that is compatible with the provided + characterization. budgeted selects whether allocation for pixels is tracked by context. + + @param context GPU context + @param characterization description of the desired SkSurface + @param budgeted one of: SkBudgeted::kNo, SkBudgeted::kYes + @return SkSurface if all parameters are valid; otherwise, nullptr + */ + static sk_sp MakeRenderTarget(GrContext* context, + const SkSurfaceCharacterization& characterization, + SkBudgeted budgeted); + + /** Returns SkSurface without backing pixels. Drawing to SkCanvas returned from SkSurface + has no effect. Calling makeImageSnapshot() on returned SkSurface returns nullptr. + + @param width one or greater + @param height one or greater + @return SkSurface if width and height are positive; otherwise, nullptr + */ + static sk_sp MakeNull(int width, int height); + + /** Returns pixel count in each row; may be zero or greater. + + @return number of pixel columns + */ + int width() const { return fWidth; } + + /** Returns pixel row count; may be zero or greater. + + @return number of pixel rows + */ + int height() const { return fHeight; } + + /** Returns unique value identifying the content of SkSurface. Returned value changes + each time the content changes. Content is changed by drawing, or by calling + notifyContentWillChange(). + + @return unique content identifier + */ + uint32_t generationID(); + + /** \enum SkSurface::ContentChangeMode + ContentChangeMode members are parameters to notifyContentWillChange(). + */ + enum ContentChangeMode { + kDiscard_ContentChangeMode, //!< discards surface on change + kRetain_ContentChangeMode, //!< preserves surface on change + }; + + /** Notifies that SkSurface contents will be changed by code outside of Skia. + Subsequent calls to generationID() return a different value. + + TODO: Can kRetain_ContentChangeMode be deprecated? + + @param mode one of: kDiscard_ContentChangeMode, kRetain_ContentChangeMode + */ + void notifyContentWillChange(ContentChangeMode mode); + + enum BackendHandleAccess { + kFlushRead_BackendHandleAccess, //!< back-end object is readable + kFlushWrite_BackendHandleAccess, //!< back-end object is writable + kDiscardWrite_BackendHandleAccess, //!< back-end object must be overwritten + }; + + /** Deprecated. + */ + static const BackendHandleAccess kFlushRead_TextureHandleAccess = + kFlushRead_BackendHandleAccess; + + /** Deprecated. + */ + static const BackendHandleAccess kFlushWrite_TextureHandleAccess = + kFlushWrite_BackendHandleAccess; + + /** Deprecated. + */ + static const BackendHandleAccess kDiscardWrite_TextureHandleAccess = + kDiscardWrite_BackendHandleAccess; + + /** Retrieves the back-end texture. If SkSurface has no back-end texture, an invalid + object is returned. Call GrBackendTexture::isValid to determine if the result + is valid. + + The returned GrBackendTexture should be discarded if the SkSurface is drawn to or deleted. + + @param backendHandleAccess one of: kFlushRead_BackendHandleAccess, + kFlushWrite_BackendHandleAccess, + kDiscardWrite_BackendHandleAccess + @return GPU texture reference; invalid on failure + */ + GrBackendTexture getBackendTexture(BackendHandleAccess backendHandleAccess); + + /** Retrieves the back-end render target. If SkSurface has no back-end render target, an invalid + object is returned. Call GrBackendRenderTarget::isValid to determine if the result + is valid. + + The returned GrBackendRenderTarget should be discarded if the SkSurface is drawn to + or deleted. + + @param backendHandleAccess one of: kFlushRead_BackendHandleAccess, + kFlushWrite_BackendHandleAccess, + kDiscardWrite_BackendHandleAccess + @return GPU render target reference; invalid on failure + */ + GrBackendRenderTarget getBackendRenderTarget(BackendHandleAccess backendHandleAccess); + + /** Returns SkCanvas that draws into SkSurface. Subsequent calls return the same SkCanvas. + SkCanvas returned is managed and owned by SkSurface, and is deleted when SkSurface + is deleted. + + @return drawing SkCanvas for SkSurface + */ + SkCanvas* getCanvas(); + + /** Returns a compatible SkSurface, or nullptr. Returned SkSurface contains + the same raster, GPU, or null properties as the original. Returned SkSurface + does not share the same pixels. + + Returns nullptr if imageInfo width or height are zero, or if imageInfo + is incompatible with SkSurface. + + @param imageInfo width, height, SkColorType, SkAlphaType, SkColorSpace, + of SkSurface; width and height must be greater than zero + @return compatible SkSurface or nullptr + */ + sk_sp makeSurface(const SkImageInfo& imageInfo); + + /** Returns SkImage capturing SkSurface contents. Subsequent drawing to SkSurface contents + are not captured. SkImage allocation is accounted for if SkSurface was created with + SkBudgeted::kYes. + + @return SkImage initialized with SkSurface contents + */ + sk_sp makeImageSnapshot(); + + /** + * Like the no-parameter version, this returns an image of the current surface contents. + * This variant takes a rectangle specifying the subset of the surface that is of interest. + * These bounds will be sanitized before being used. + * - If bounds extends beyond the surface, it will be trimmed to just the intersection of + * it and the surface. + * - If bounds does not intersect the surface, then this returns nullptr. + * - If bounds == the surface, then this is the same as calling the no-parameter variant. + */ + sk_sp makeImageSnapshot(const SkIRect& bounds); + + /** Draws SkSurface contents to canvas, with its top-left corner at (x, y). + + If SkPaint paint is not nullptr, apply SkColorFilter, alpha, SkImageFilter, + SkBlendMode, and SkDrawLooper. + + @param canvas SkCanvas drawn into + @param x horizontal offset in SkCanvas + @param y vertical offset in SkCanvas + @param paint SkPaint containing SkBlendMode, SkColorFilter, SkImageFilter, + and so on; or nullptr + */ + void draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint); + + /** Copies SkSurface pixel address, row bytes, and SkImageInfo to SkPixmap, if address + is available, and returns true. If pixel address is not available, return + false and leave SkPixmap unchanged. + + pixmap contents become invalid on any future change to SkSurface. + + @param pixmap storage for pixel state if pixels are readable; otherwise, ignored + @return true if SkSurface has direct access to pixels + */ + bool peekPixels(SkPixmap* pixmap); + + /** Copies SkRect of pixels to dst. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), height()). + Destination SkRect corners are (0, 0) and (dst.width(), dst.height()). + Copies each readable pixel intersecting both rectangles, without scaling, + converting to dst.colorType() and dst.alphaType() if required. + + Pixels are readable when SkSurface is raster, or backed by a GPU. + + 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. dst 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. + - SkPixmap pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @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& dst, int srcX, int srcY); + + /** Copies SkRect of pixels from SkCanvas into dstPixels. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), 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 SkSurface is raster, or backed by a GPU. + + 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. + - SkSurface pixels could not be converted to dstInfo.colorType() or dstInfo.alphaType(). + - 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 SkSurface into bitmap. + + Source SkRect corners are (srcX, srcY) and SkSurface (width(), 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 SkSurface is raster, or backed by a GPU. + + 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. dst 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. + - SkSurface pixels could not be converted to dst.colorType() or dst.alphaType(). + - dst pixels could not be allocated. + - dst.rowBytes() is too small to contain one row of pixels. + + @param dst storage for pixels copied from SkSurface + @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& dst, int srcX, int srcY); + + /** Copies SkRect of pixels from the src SkPixmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + */ + void writePixels(const SkPixmap& src, int dstX, int dstY); + + /** Copies SkRect of pixels from the src SkBitmap to the SkSurface. + + Source SkRect corners are (0, 0) and (src.width(), src.height()). + Destination SkRect corners are (dstX, dstY) and + (dstX + Surface width(), dstY + Surface height()). + + Copies each readable pixel intersecting both rectangles, without scaling, + converting to SkSurface colorType() and SkSurface alphaType() if required. + + @param src storage for pixels to copy to SkSurface + @param dstX x-axis position relative to SkSurface to begin copy; may be negative + @param dstY y-axis position relative to SkSurface to begin copy; may be negative + */ + void writePixels(const SkBitmap& src, int dstX, int dstY); + + /** Returns SkSurfaceProps for surface. + + @return LCD striping orientation and setting for device independent fonts + */ + const SkSurfaceProps& props() const { return fProps; } + + /** Deprecated. + */ + void prepareForExternalIO(); + + /** Issues pending SkSurface commands to the GPU-backed API and resolves any SkSurface MSAA. + + Skia flushes as needed, so it is not necessary to call this if Skia manages + drawing and object lifetime. Call when interleaving Skia calls with native + GPU calls. + */ + void flush(); + + /** Issues pending SkSurface commands to the GPU-backed API and resolves any SkSurface MSAA. + After issuing all commands, signalSemaphores of count numSemaphores semaphores + are signaled by the GPU. + + For each GrBackendSemaphore in signalSemaphores: + if GrBackendSemaphore is initialized, the GPU back-end uses the semaphore as is; + otherwise, a new semaphore is created and initializes GrBackendSemaphore. + + The caller must delete the semaphores created and returned in signalSemaphores. + GrBackendSemaphore can be deleted as soon as this function returns. + + If the back-end API is OpenGL only uninitialized backend semaphores are supported. + + If the back-end API is Vulkan semaphores may be initialized or uninitialized. + If uninitialized, created semaphores are valid only with the VkDevice + with which they were created. + + If GrSemaphoresSubmitted::kNo is returned, the GPU back-end did not create or + add any semaphores to signal on the GPU; the caller should not instruct the GPU + to wait on any of the semaphores. + + Pending surface commands are flushed regardless of the return result. + + @param numSemaphores size of signalSemaphores array + @param signalSemaphores array of semaphore containers + @return one of: GrSemaphoresSubmitted::kYes, GrSemaphoresSubmitted::kNo + */ + GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores, + GrBackendSemaphore signalSemaphores[]); + + /** Inserts a list of GPU semaphores that the current GPU-backed API must wait on before + executing any more commands on the GPU for this surface. Skia will take ownership of the + underlying semaphores and delete them once they have been signaled and waited on. + If this call returns false, then the GPU back-end will not wait on any passed in semaphores, + and the client will still own the semaphores. + + @param numSemaphores size of waitSemaphores array + @param waitSemaphores array of semaphore containers + @return true if GPU is waiting on semaphores + */ + bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores); + + /** Initializes SkSurfaceCharacterization that can be used to perform GPU back-end + processing in a separate thread. Typically this is used to divide drawing + into multiple tiles. SkDeferredDisplayListRecorder records the drawing commands + for each tile. + + Return true if SkSurface supports characterization. raster surface returns false. + + @param characterization properties for parallel drawing + @return true if supported + */ + bool characterize(SkSurfaceCharacterization* characterization) const; + + /** Draws deferred display list created using SkDeferredDisplayListRecorder. + Has no effect and returns false if SkSurfaceCharacterization stored in + deferredDisplayList is not compatible with SkSurface. + + raster surface returns false. + + @param deferredDisplayList drawing commands + @return false if deferredDisplayList is not compatible + */ + bool draw(SkDeferredDisplayList* deferredDisplayList); + +protected: + SkSurface(int width, int height, const SkSurfaceProps* surfaceProps); + SkSurface(const SkImageInfo& imageInfo, const SkSurfaceProps* surfaceProps); + + // called by subclass if their contents have changed + void dirtyGenerationID() { + fGenerationID = 0; + } + +private: + const SkSurfaceProps fProps; + const int fWidth; + const int fHeight; + uint32_t fGenerationID; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/core/SkSurfaceCharacterization.h b/skia/include/core/SkSurfaceCharacterization.h new file mode 100644 index 00000000..2abd5b65 --- /dev/null +++ b/skia/include/core/SkSurfaceCharacterization.h @@ -0,0 +1,186 @@ +/* + * 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 SkSurfaceCharacterization_DEFINED +#define SkSurfaceCharacterization_DEFINED + +#include "GrTypes.h" + +#include "SkColorSpace.h" +#include "SkRefCnt.h" +#include "SkSurfaceProps.h" + +class SkColorSpace; + +#if SK_SUPPORT_GPU +#include "GrContext.h" + +/** \class SkSurfaceCharacterization + A surface characterization contains all the information Ganesh requires to makes its internal + rendering decisions. When passed into a SkDeferredDisplayListRecorder it will copy the + data and pass it on to the SkDeferredDisplayList if/when it is created. Note that both of + those objects (the Recorder and the DisplayList) will take a ref on the + GrContextThreadSafeProxy and SkColorSpace objects. +*/ +class SK_API SkSurfaceCharacterization { +public: + enum class Textureable : bool { kNo = false, kYes = true }; + enum class MipMapped : bool { kNo = false, kYes = true }; + enum class UsesGLFBO0 : bool { kNo = false, kYes = true }; + + SkSurfaceCharacterization() + : fCacheMaxResourceBytes(0) + , fOrigin(kBottomLeft_GrSurfaceOrigin) + , fConfig(kUnknown_GrPixelConfig) + , fFSAAType(GrFSAAType::kNone) + , fStencilCnt(0) + , fIsTextureable(Textureable::kYes) + , fIsMipMapped(MipMapped::kYes) + , fUsesGLFBO0(UsesGLFBO0::kNo) + , fSurfaceProps(0, kUnknown_SkPixelGeometry) { + } + + SkSurfaceCharacterization(SkSurfaceCharacterization&&) = default; + SkSurfaceCharacterization& operator=(SkSurfaceCharacterization&&) = default; + + SkSurfaceCharacterization(const SkSurfaceCharacterization&) = default; + SkSurfaceCharacterization& operator=(const SkSurfaceCharacterization& other) = default; + bool operator==(const SkSurfaceCharacterization& other) const; + bool operator!=(const SkSurfaceCharacterization& other) const { + return !(*this == other); + } + + SkSurfaceCharacterization createResized(int width, int height) const; + + GrContextThreadSafeProxy* contextInfo() const { return fContextInfo.get(); } + sk_sp refContextInfo() const { return fContextInfo; } + size_t cacheMaxResourceBytes() const { return fCacheMaxResourceBytes; } + + bool isValid() const { return kUnknown_SkColorType != fImageInfo.colorType(); } + + const SkImageInfo& imageInfo() const { return fImageInfo; } + GrSurfaceOrigin origin() const { return fOrigin; } + int width() const { return fImageInfo.width(); } + int height() const { return fImageInfo.height(); } + SkColorType colorType() const { return fImageInfo.colorType(); } + GrFSAAType fsaaType() const { return fFSAAType; } + int stencilCount() const { return fStencilCnt; } + bool isTextureable() const { return Textureable::kYes == fIsTextureable; } + bool isMipMapped() const { return MipMapped::kYes == fIsMipMapped; } + bool usesGLFBO0() const { return UsesGLFBO0::kYes == fUsesGLFBO0; } + SkColorSpace* colorSpace() const { return fImageInfo.colorSpace(); } + sk_sp refColorSpace() const { return fImageInfo.refColorSpace(); } + const SkSurfaceProps& surfaceProps()const { return fSurfaceProps; } + +private: + friend class SkSurface_Gpu; // for 'set' & 'config' + friend class GrContextThreadSafeProxy; // for private ctor + friend class SkDeferredDisplayListRecorder; // for 'config' + friend class SkSurface; // for 'config' + + GrPixelConfig config() const { return fConfig; } + + SkSurfaceCharacterization(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + GrSurfaceOrigin origin, + GrPixelConfig config, + GrFSAAType FSAAType, int stencilCnt, + Textureable isTextureable, MipMapped isMipMapped, + UsesGLFBO0 usesGLFBO0, + const SkSurfaceProps& surfaceProps) + : fContextInfo(std::move(contextInfo)) + , fCacheMaxResourceBytes(cacheMaxResourceBytes) + , fImageInfo(ii) + , fOrigin(origin) + , fConfig(config) + , fFSAAType(FSAAType) + , fStencilCnt(stencilCnt) + , fIsTextureable(isTextureable) + , fIsMipMapped(isMipMapped) + , fUsesGLFBO0(usesGLFBO0) + , fSurfaceProps(surfaceProps) { + } + + void set(sk_sp contextInfo, + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, + GrSurfaceOrigin origin, + GrPixelConfig config, + GrFSAAType fsaaType, + int stencilCnt, + Textureable isTextureable, + MipMapped isMipMapped, + UsesGLFBO0 usesGLFBO0, + const SkSurfaceProps& surfaceProps) { + SkASSERT(MipMapped::kNo == isMipMapped || Textureable::kYes == isTextureable); + SkASSERT(Textureable::kNo == isTextureable || UsesGLFBO0::kNo == usesGLFBO0); + + fContextInfo = contextInfo; + fCacheMaxResourceBytes = cacheMaxResourceBytes; + + fImageInfo = ii; + fOrigin = origin; + fConfig = config; + fFSAAType = fsaaType; + fStencilCnt = stencilCnt; + fIsTextureable = isTextureable; + fIsMipMapped = isMipMapped; + fUsesGLFBO0 = usesGLFBO0; + fSurfaceProps = surfaceProps; + } + + sk_sp fContextInfo; + size_t fCacheMaxResourceBytes; + + SkImageInfo fImageInfo; + GrSurfaceOrigin fOrigin; + GrPixelConfig fConfig; + GrFSAAType fFSAAType; + int fStencilCnt; + Textureable fIsTextureable; + MipMapped fIsMipMapped; + UsesGLFBO0 fUsesGLFBO0; + SkSurfaceProps fSurfaceProps; +}; + +#else// !SK_SUPPORT_GPU + +class SK_API SkSurfaceCharacterization { +public: + SkSurfaceCharacterization() : fSurfaceProps(0, kUnknown_SkPixelGeometry) { } + + SkSurfaceCharacterization createResized(int width, int height) const { + return *this; + } + + bool operator==(const SkSurfaceCharacterization& other) const { return false; } + bool operator!=(const SkSurfaceCharacterization& other) const { + return !(*this == other); + } + + size_t cacheMaxResourceBytes() const { return 0; } + + bool isValid() const { return false; } + + int width() const { return 0; } + int height() const { return 0; } + int stencilCount() const { return 0; } + bool isTextureable() const { return false; } + bool isMipMapped() const { return false; } + bool usesGLFBO0() const { return false; } + SkColorSpace* colorSpace() const { return nullptr; } + sk_sp refColorSpace() const { return nullptr; } + const SkSurfaceProps& surfaceProps()const { return fSurfaceProps; } + +private: + SkSurfaceProps fSurfaceProps; +}; + +#endif + +#endif diff --git a/skia/include/core/SkSurfaceProps.h b/skia/include/core/SkSurfaceProps.h new file mode 100644 index 00000000..66617995 --- /dev/null +++ b/skia/include/core/SkSurfaceProps.h @@ -0,0 +1,86 @@ +/* + * 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 SkSurfaceProps_DEFINED +#define SkSurfaceProps_DEFINED + +#include "SkTypes.h" + +/** + * Description of how the LCD strips are arranged for each pixel. If this is unknown, or the + * pixels are meant to be "portable" and/or transformed before showing (e.g. rotated, scaled) + * then use kUnknown_SkPixelGeometry. + */ +enum SkPixelGeometry { + kUnknown_SkPixelGeometry, + kRGB_H_SkPixelGeometry, + kBGR_H_SkPixelGeometry, + kRGB_V_SkPixelGeometry, + kBGR_V_SkPixelGeometry, +}; + +// Returns true iff geo is a known geometry and is RGB. +static inline bool SkPixelGeometryIsRGB(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kRGB_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is BGR. +static inline bool SkPixelGeometryIsBGR(SkPixelGeometry geo) { + return kBGR_H_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is horizontal. +static inline bool SkPixelGeometryIsH(SkPixelGeometry geo) { + return kRGB_H_SkPixelGeometry == geo || kBGR_H_SkPixelGeometry == geo; +} + +// Returns true iff geo is a known geometry and is vertical. +static inline bool SkPixelGeometryIsV(SkPixelGeometry geo) { + return kRGB_V_SkPixelGeometry == geo || kBGR_V_SkPixelGeometry == geo; +} + +/** + * Describes properties and constraints of a given SkSurface. The rendering engine can parse these + * during drawing, and can sometimes optimize its performance (e.g. disabling an expensive + * feature). + */ +class SK_API SkSurfaceProps { +public: + enum Flags { + kUseDeviceIndependentFonts_Flag = 1 << 0, + }; + /** Deprecated alias used by Chromium. Will be removed. */ + static const Flags kUseDistanceFieldFonts_Flag = kUseDeviceIndependentFonts_Flag; + + SkSurfaceProps(uint32_t flags, SkPixelGeometry); + + enum InitType { + kLegacyFontHost_InitType + }; + SkSurfaceProps(InitType); + SkSurfaceProps(uint32_t flags, InitType); + SkSurfaceProps(const SkSurfaceProps& other); + + uint32_t flags() const { return fFlags; } + SkPixelGeometry pixelGeometry() const { return fPixelGeometry; } + + bool isUseDeviceIndependentFonts() const { + return SkToBool(fFlags & kUseDeviceIndependentFonts_Flag); + } + + bool operator==(const SkSurfaceProps& that) const { + return fFlags == that.fFlags && fPixelGeometry == that.fPixelGeometry; + } + +private: + SkSurfaceProps(); + + uint32_t fFlags; + SkPixelGeometry fPixelGeometry; +}; + +#endif diff --git a/skia/include/core/SkSwizzle.h b/skia/include/core/SkSwizzle.h new file mode 100644 index 00000000..253f4e39 --- /dev/null +++ b/skia/include/core/SkSwizzle.h @@ -0,0 +1,19 @@ +/* + * 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 SkSwizzle_DEFINED +#define SkSwizzle_DEFINED + +#include "SkTypes.h" + +/** + Swizzles byte order of |count| 32-bit pixels, swapping R and B. + (RGBA <-> BGRA) +*/ +SK_API void SkSwapRB(uint32_t* dest, const uint32_t* src, int count); + +#endif diff --git a/skia/include/core/SkTLazy.h b/skia/include/core/SkTLazy.h new file mode 100644 index 00000000..26ee9229 --- /dev/null +++ b/skia/include/core/SkTLazy.h @@ -0,0 +1,209 @@ +/* + * 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 SkTLazy_DEFINED +#define SkTLazy_DEFINED + +#include "../private/SkTemplates.h" +#include "SkTypes.h" +#include +#include + +/** + * Efficient way to defer allocating/initializing a class until it is needed + * (if ever). + */ +template class SkTLazy { +public: + SkTLazy() : fPtr(nullptr) {} + + explicit SkTLazy(const T* src) + : fPtr(src ? new (fStorage.get()) T(*src) : nullptr) {} + + SkTLazy(const SkTLazy& that) : fPtr(nullptr) { *this = that; } + SkTLazy(SkTLazy&& that) : fPtr(nullptr) { *this = std::move(that); } + + ~SkTLazy() { + if (this->isValid()) { + fPtr->~T(); + } + } + + SkTLazy& operator=(const SkTLazy& that) { + if (that.isValid()) { + this->set(*that.get()); + } else { + this->reset(); + } + return *this; + } + + SkTLazy& operator=(SkTLazy&& that) { + if (that.isValid()) { + this->set(std::move(*that.get())); + } else { + this->reset(); + } + return *this; + } + + /** + * Return a pointer to an instance of the class initialized with 'args'. + * If a previous instance had been initialized (either from init() or + * set()) it will first be destroyed, so that a freshly initialized + * instance is always returned. + */ + template T* init(Args&&... args) { + if (this->isValid()) { + fPtr->~T(); + } + fPtr = new (reinterpret_cast(fStorage.get())) T(std::forward(args)...); + return fPtr; + } + + /** + * Copy src into this, and return a pointer to a copy of it. Note this + * will always return the same pointer, so if it is called on a lazy that + * has already been initialized, then this will copy over the previous + * contents. + */ + T* set(const T& src) { + if (this->isValid()) { + *fPtr = src; + } else { + fPtr = new (reinterpret_cast(fStorage.get())) T(src); + } + return fPtr; + } + + T* set(T&& src) { + if (this->isValid()) { + *fPtr = std::move(src); + } else { + fPtr = new (reinterpret_cast(fStorage.get())) T(std::move(src)); + } + return fPtr; + } + + /** + * Destroy the lazy object (if it was created via init() or set()) + */ + void reset() { + if (this->isValid()) { + fPtr->~T(); + fPtr = nullptr; + } + } + + /** + * Returns true if a valid object has been initialized in the SkTLazy, + * false otherwise. + */ + bool isValid() const { return SkToBool(fPtr); } + + /** + * Returns the object. This version should only be called when the caller + * knows that the object has been initialized. + */ + T* get() const { SkASSERT(this->isValid()); return fPtr; } + + /** + * Like above but doesn't assert if object isn't initialized (in which case + * nullptr is returned). + */ + T* getMaybeNull() const { return fPtr; } + +private: + SkAlignedSTStorage<1, T> fStorage; + T* fPtr; // nullptr or fStorage +}; + +/** + * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized + * with a const pointer but provides a non-const pointer accessor. The first time the + * accessor is called (if ever) the object is cloned. + * + * In the following example at most one copy of constThing is made: + * + * SkTCopyOnFirstWrite thing(&constThing); + * ... + * function_that_takes_a_const_thing_ptr(thing); // constThing is passed + * ... + * if (need_to_modify_thing()) { + * thing.writable()->modifyMe(); // makes a copy of constThing + * } + * ... + * x = thing->readSomething(); + * ... + * if (need_to_modify_thing_now()) { + * thing.writable()->changeMe(); // makes a copy of constThing if we didn't call modifyMe() + * } + * + * consume_a_thing(thing); // could be constThing or a modified copy. + */ +template +class SkTCopyOnFirstWrite { +public: + explicit SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {} + + explicit SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {} + + // Constructor for delayed initialization. + SkTCopyOnFirstWrite() : fObj(nullptr) {} + + SkTCopyOnFirstWrite(const SkTCopyOnFirstWrite& that) { *this = that; } + SkTCopyOnFirstWrite( SkTCopyOnFirstWrite&& that) { *this = std::move(that); } + + SkTCopyOnFirstWrite& operator=(const SkTCopyOnFirstWrite& that) { + fLazy = that.fLazy; + fObj = fLazy.isValid() ? fLazy.get() : that.fObj; + return *this; + } + + SkTCopyOnFirstWrite& operator=(SkTCopyOnFirstWrite&& that) { + fLazy = std::move(that.fLazy); + fObj = fLazy.isValid() ? fLazy.get() : that.fObj; + return *this; + } + + // Should only be called once, and only if the default constructor was used. + void init(const T& initial) { + SkASSERT(nullptr == fObj); + SkASSERT(!fLazy.isValid()); + fObj = &initial; + } + + /** + * Returns a writable T*. The first time this is called the initial object is cloned. + */ + T* writable() { + SkASSERT(fObj); + if (!fLazy.isValid()) { + fLazy.set(*fObj); + fObj = fLazy.get(); + } + return const_cast(fObj); + } + + const T* get() const { return fObj; } + + /** + * Operators for treating this as though it were a const pointer. + */ + + const T *operator->() const { return fObj; } + + operator const T*() const { return fObj; } + + const T& operator *() const { return *fObj; } + +private: + const T* fObj; + SkTLazy fLazy; +}; + +#endif diff --git a/skia/include/core/SkTextBlob.h b/skia/include/core/SkTextBlob.h new file mode 100644 index 00000000..7d439d17 --- /dev/null +++ b/skia/include/core/SkTextBlob.h @@ -0,0 +1,349 @@ +/* + * Copyright 2014 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/SkTextBlob.h and docs/SkTextBlob_Reference.bmh + on 2018-08-10 12:59:44. Additional documentation and examples can be found at: + https://skia.org/user/api/SkTextBlob_Reference + + You may edit either file directly. Structural changes to public interfaces require + editing both files. After editing docs/SkTextBlob_Reference.bmh, run: + bookmaker -b docs -i include/core/SkTextBlob.h -p + to create an updated version of this file. + */ + +#ifndef SkTextBlob_DEFINED +#define SkTextBlob_DEFINED + +#include "../private/SkTemplates.h" +#include "SkFont.h" +#include "SkPaint.h" +#include "SkString.h" +#include "SkRefCnt.h" + +#include + +struct SkSerialProcs; +struct SkDeserialProcs; + +/** \class SkTextBlob + SkTextBlob combines multiple text runs into an immutable container. Each text + run consists of glyphs, SkPaint, and position. Only parts of SkPaint related to + fonts and text rendering are used by run. +*/ +class SK_API SkTextBlob final : public SkNVRefCnt { +public: + + /** Returns conservative bounding box. Uses SkPaint associated with each glyph to + determine glyph bounds, and unions all bounds. Returned bounds may be + larger than the bounds of all glyphs in runs. + + @return conservative bounding box + */ + const SkRect& bounds() const { return fBounds; } + + /** Returns a non-zero value unique among all text blobs. + + @return identifier for SkTextBlob + */ + uint32_t uniqueID() const { return fUniqueID; } + + /** Creates SkTextBlob with a single run. + + font contains attributes used to define the run text. + + @param text character code points or glyphs drawn + @param byteLength byte length of text array + @param font text size, typeface, text scale, and so on, used to draw + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromText(const void* text, size_t byteLength, const SkFont& font, + SkPaint::TextEncoding encoding = SkPaint::kUTF8_TextEncoding); + + /** Creates SkTextBlob with a single run. string meaning depends on SkPaint::TextEncoding; + by default, string is encoded as UTF-8. + + font contains attributes used to define the run text. + + @param string character code points or glyphs drawn + @param font text size, typeface, text scale, and so on, used to draw + @return SkTextBlob constructed from one run + */ + static sk_sp MakeFromString(const char* string, const SkFont& font, + SkPaint::TextEncoding encoding = SkPaint::kUTF8_TextEncoding) { + if (!string) { + return nullptr; + } + return MakeFromText(string, strlen(string), font, encoding); + } + + /** Writes data to allow later reconstruction of SkTextBlob. memory points to storage + to receive the encoded data, and memory_size describes the size of storage. + Returns bytes used if provided storage is large enough to hold all data; + otherwise, returns zero. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @param memory storage for data + @param memory_size size of storage + @return bytes written, or zero if required storage is larger than memory_size + */ + size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const; + + /** Returns storage containing SkData describing SkTextBlob, using optional custom + encoders. + + procs.fTypefaceProc permits supplying a custom function to encode SkTypeface. + If procs.fTypefaceProc is nullptr, default encoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface and user context. + + @param procs custom serial data encoders; may be nullptr + @return storage containing serialized SkTextBlob + */ + sk_sp serialize(const SkSerialProcs& procs) const; + + /** Recreates SkTextBlob that was serialized into data. Returns constructed SkTextBlob + if successful; otherwise, returns nullptr. Fails if size is smaller than + required data length, or if data does not permit constructing valid SkTextBlob. + + procs.fTypefaceProc permits supplying a custom function to decode SkTypeface. + If procs.fTypefaceProc is nullptr, default decoding is used. procs.fTypefaceCtx + may be used to provide user context to procs.fTypefaceProc; procs.fTypefaceProc + is called with a pointer to SkTypeface data, data byte length, and user context. + + @param data pointer for serial data + @param size size of data + @param procs custom serial data decoders; may be nullptr + @return SkTextBlob constructed from data in memory + */ + static sk_sp Deserialize(const void* data, size_t size, + const SkDeserialProcs& procs); + +private: + friend class SkNVRefCnt; + class RunRecord; + + enum GlyphPositioning : uint8_t; + + explicit SkTextBlob(const SkRect& bounds); + + ~SkTextBlob(); + + // Memory for objects of this class is created with sk_malloc rather than operator new and must + // be freed with sk_free. + void operator delete(void* p); + void* operator new(size_t); + void* operator new(size_t, void* p); + + static unsigned ScalarsPerGlyph(GlyphPositioning pos); + + // Call when this blob is part of the key to a cache entry. This allows the cache + // to know automatically those entries can be purged when this SkTextBlob is deleted. + void notifyAddedToCache(uint32_t cacheID) const { + fCacheID.store(cacheID); + } + + friend class SkGlyphRunList; + friend class GrTextBlobCache; + friend class SkTextBlobBuilder; + friend class SkTextBlobPriv; + friend class SkTextBlobRunIterator; + + const SkRect fBounds; + const uint32_t fUniqueID; + mutable std::atomic fCacheID; + + SkDEBUGCODE(size_t fStorageSize;) + + // The actual payload resides in externally-managed storage, following the object. + // (see the .cpp for more details) + + typedef SkRefCnt INHERITED; +}; + +/** \class SkTextBlobBuilder + Helper class for constructing SkTextBlob. +*/ +class SK_API SkTextBlobBuilder { +public: + + /** Constructs empty SkTextBlobBuilder. By default, SkTextBlobBuilder has no runs. + + @return empty SkTextBlobBuilder + */ + SkTextBlobBuilder(); + + /** Deletes data allocated internally by SkTextBlobBuilder. + */ + ~SkTextBlobBuilder(); + + /** Returns SkTextBlob built from runs of glyphs added by builder. Returned + SkTextBlob is immutable; it may be copied, but its contents may not be altered. + Returns nullptr if no runs of glyphs were added by builder. + + Resets SkTextBlobBuilder to its initial empty state, allowing it to be + reused to build a new set of runs. + + @return SkTextBlob or nullptr + */ + sk_sp make(); + + /** \struct SkTextBlobBuilder::RunBuffer + RunBuffer supplies storage for glyphs and positions within a run. + + A run is a sequence of glyphs sharing font metrics and positioning. + Each run may position its glyphs in one of three ways: + by specifying where the first glyph is drawn, and allowing font metrics to + determine the advance to subsequent glyphs; by specifying a baseline, and + the position on that baseline for each glyph in run; or by providing SkPoint + array, one per glyph. + */ + struct RunBuffer { + SkGlyphID* glyphs; //!< storage for glyphs in run + SkScalar* pos; //!< storage for positions in run + char* utf8text; //!< reserved for future use + uint32_t* clusters; //!< reserved for future use + }; + + /** Returns run with storage for glyphs. Caller must write count glyphs to + RunBuffer::glyphs before next call to SkTextBlobBuilder. + + RunBuffer::utf8text, and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at (x, y), using font metrics to + determine their relative placement. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from (x, y) and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param x horizontal offset within the blob + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer + */ + const RunBuffer& allocRun(const SkFont& font, int count, SkScalar x, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and positions along baseline. Caller must + write count glyphs to RunBuffer::glyphs, and count scalars to RunBuffer::pos; + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text, and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned on a baseline at y, using x-axis positions written by + caller to RunBuffer::pos. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from y, RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param y vertical offset within the blob + @param bounds optional run bounding box + @return writable glyph buffer and x-axis position buffer + */ + const RunBuffer& allocRunPosH(const SkFont& font, int count, SkScalar y, + const SkRect* bounds = nullptr); + + /** Returns run with storage for glyphs and SkPoint positions. Caller must + write count glyphs to RunBuffer::glyphs, and count SkPoint to RunBuffer::pos; + before next call to SkTextBlobBuilder. + + RunBuffer::utf8text, and RunBuffer::clusters should be ignored. + + Glyphs share metrics in font. + + Glyphs are positioned using SkPoint written by caller to RunBuffer::pos, using + two scalar values for each SkPoint. + + bounds defines an optional bounding box, used to suppress drawing when SkTextBlob + bounds does not intersect SkSurface bounds. If bounds is nullptr, SkTextBlob bounds + is computed from RunBuffer::pos, and RunBuffer::glyphs metrics. + + @param font SkFont used for this run + @param count number of glyphs + @param bounds optional run bounding box + @return writable glyph buffer and SkPoint buffer + */ + const RunBuffer& allocRunPos(const SkFont& font, int count, + const SkRect* bounds = nullptr); + +#ifdef SK_SUPPORT_LEGACY_TEXTBLOBBUILD_WITH_PAINT + /** Deprecated. + */ + const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y, + const SkRect* bounds = nullptr) { + return this->allocRunText(font, count, x, y, 0, SkString(), bounds); + } + + /** Deprecated. + */ + const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y, + const SkRect* bounds = nullptr) { + return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds); + } + + /** Deprecated. + */ + const RunBuffer& allocRunPos(const SkPaint& font, int count, + const SkRect* bounds = nullptr) { + return this->allocRunTextPos(font, count, 0, SkString(), bounds); + } +#endif + +private: + const RunBuffer& allocRunText(const SkPaint& font, + int count, + SkScalar x, + SkScalar y, + int textByteCount, + SkString lang, + const SkRect* bounds = nullptr); + const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y, + int textByteCount, SkString lang, + const SkRect* bounds = nullptr); + const RunBuffer& allocRunTextPos(const SkPaint& font, int count, + int textByteCount, SkString lang, + const SkRect* bounds = nullptr); + void reserve(size_t size); + void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, + int count, int textBytes, SkPoint offset, const SkRect* bounds); + bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, + uint32_t count, SkPoint offset); + void updateDeferredBounds(); + + static SkRect ConservativeRunBounds(const SkTextBlob::RunRecord&); + static SkRect TightRunBounds(const SkTextBlob::RunRecord&); + + friend class SkTextBlobPriv; + friend class SkTextBlobBuilderPriv; + + SkAutoTMalloc fStorage; + size_t fStorageSize; + size_t fStorageUsed; + + SkRect fBounds; + int fRunCount; + bool fDeferredBounds; + size_t fLastRun; // index into fStorage + + RunBuffer fCurrentRunBuffer; +}; + +#endif // SkTextBlob_DEFINED diff --git a/skia/include/core/SkTime.h b/skia/include/core/SkTime.h new file mode 100644 index 00000000..8a40c213 --- /dev/null +++ b/skia/include/core/SkTime.h @@ -0,0 +1,62 @@ + +/* + * 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 SkTime_DEFINED +#define SkTime_DEFINED + +#include "../private/SkMacros.h" +#include "SkTypes.h" + +class SkString; + +/** \class SkTime + Platform-implemented utilities to return time of day, and millisecond counter. +*/ +class SK_API SkTime { +public: + struct DateTime { + int16_t fTimeZoneMinutes; // The number of minutes that GetDateTime() + // is ahead of or behind UTC. + uint16_t fYear; //!< e.g. 2005 + uint8_t fMonth; //!< 1..12 + uint8_t fDayOfWeek; //!< 0..6, 0==Sunday + uint8_t fDay; //!< 1..31 + uint8_t fHour; //!< 0..23 + uint8_t fMinute; //!< 0..59 + uint8_t fSecond; //!< 0..59 + + void toISO8601(SkString* dst) const; + }; + static void GetDateTime(DateTime*); + + static double GetSecs() { return GetNSecs() * 1e-9; } + static double GetMSecs() { return GetNSecs() * 1e-6; } + static double GetNSecs(); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SkAutoTime { +public: + // The label is not deep-copied, so its address must remain valid for the + // lifetime of this object + SkAutoTime(const char* label = nullptr) + : fLabel(label) + , fNow(SkTime::GetMSecs()) {} + ~SkAutoTime() { + uint64_t dur = static_cast(SkTime::GetMSecs() - fNow); + SkDebugf("%s %ld\n", fLabel ? fLabel : "", dur); + } +private: + const char* fLabel; + double fNow; +}; +#define SkAutoTime(...) SK_REQUIRE_LOCAL_VAR(SkAutoTime) + +#endif diff --git a/skia/include/core/SkTraceMemoryDump.h b/skia/include/core/SkTraceMemoryDump.h new file mode 100644 index 00000000..e9cb5b20 --- /dev/null +++ b/skia/include/core/SkTraceMemoryDump.h @@ -0,0 +1,90 @@ +/* + * 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 SkTraceMemoryDump_DEFINED +#define SkTraceMemoryDump_DEFINED + +#include "SkTypes.h" + +class SkDiscardableMemory; + +/** + * Interface for memory tracing. + * This interface is meant to be passed as argument to the memory dump methods of Skia objects. + * The implementation of this interface is provided by the embedder. + */ +class SK_API SkTraceMemoryDump { +public: + /** + * Enum to specify the level of the requested details for the dump from the Skia objects. + */ + enum LevelOfDetail { + // Dump only the minimal details to get the total memory usage (Usually just the totals). + kLight_LevelOfDetail, + + // Dump the detailed breakdown of the objects in the caches. + kObjectsBreakdowns_LevelOfDetail + }; + + /** + * Appends a new memory dump (i.e. a row) to the trace memory infrastructure. + * If dumpName does not exist yet, a new one is created. Otherwise, a new column is appended to + * the previously created dump. + * Arguments: + * dumpName: an absolute, slash-separated, name for the item being dumped + * e.g., "skia/CacheX/EntryY". + * valueName: a string indicating the name of the column. + * e.g., "size", "active_size", "number_of_objects". + * This string is supposed to be long lived and is NOT copied. + * units: a string indicating the units for the value. + * e.g., "bytes", "objects". + * This string is supposed to be long lived and is NOT copied. + * value: the actual value being dumped. + */ + virtual void dumpNumericValue(const char* dumpName, + const char* valueName, + const char* units, + uint64_t value) = 0; + + virtual void dumpStringValue(const char* /*dumpName*/, + const char* /*valueName*/, + const char* /*value*/) { } + + /** + * Sets the memory backing for an existing dump. + * backingType and backingObjectId are used by the embedder to associate the memory dumped via + * dumpNumericValue with the corresponding dump that backs the memory. + */ + virtual void setMemoryBacking(const char* dumpName, + const char* backingType, + const char* backingObjectId) = 0; + + /** + * Specialization for memory backed by discardable memory. + */ + virtual void setDiscardableMemoryBacking( + const char* dumpName, + const SkDiscardableMemory& discardableMemoryObject) = 0; + + /** + * Returns the type of details requested in the dump. The granularity of the dump is supposed to + * match the LevelOfDetail argument. The level of detail must not affect the total size + * reported, but only granularity of the child entries. + */ + virtual LevelOfDetail getRequestedDetails() const = 0; + + /** + * Returns true if we should dump wrapped objects. Wrapped objects come from outside Skia, and + * may be independently tracked there. + */ + virtual bool shouldDumpWrappedObjects() const { return true; } + +protected: + virtual ~SkTraceMemoryDump() { } +}; + +#endif diff --git a/skia/include/core/SkTypeface.h b/skia/include/core/SkTypeface.h new file mode 100644 index 00000000..3d52e7a7 --- /dev/null +++ b/skia/include/core/SkTypeface.h @@ -0,0 +1,450 @@ +/* + * 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 SkTypeface_DEFINED +#define SkTypeface_DEFINED + +#include "../private/SkNoncopyable.h" +#include "../private/SkOnce.h" +#include "../private/SkWeakRefCnt.h" +#include "SkFontArguments.h" +#include "SkFontParameters.h" +#include "SkFontStyle.h" +#include "SkRect.h" +#include "SkString.h" + +class SkData; +class SkDescriptor; +class SkFontData; +class SkFontDescriptor; +class SkScalerContext; +class SkStream; +class SkStreamAsset; +class SkWStream; +struct SkAdvancedTypefaceMetrics; +struct SkScalerContextEffects; +struct SkScalerContextRec; + +typedef uint32_t SkFontID; +/** Machine endian. */ +typedef uint32_t SkFontTableTag; + +/** \class SkTypeface + + The SkTypeface class specifies the typeface and intrinsic style of a font. + This is used in the paint, along with optionally algorithmic settings like + textSize, textSkewX, textScaleX, kFakeBoldText_Mask, to specify + how text appears when drawn (and measured). + + Typeface objects are immutable, and so they can be shared between threads. +*/ +class SK_API SkTypeface : public SkWeakRefCnt { +public: + /** Returns the typeface's intrinsic style attributes. */ + SkFontStyle fontStyle() const { + return fStyle; + } + + /** Returns true if style() has the kBold bit set. */ + bool isBold() const { return fStyle.weight() >= SkFontStyle::kSemiBold_Weight; } + + /** Returns true if style() has the kItalic bit set. */ + bool isItalic() const { return fStyle.slant() != SkFontStyle::kUpright_Slant; } + + /** Returns true if the typeface claims to be fixed-pitch. + * This is a style bit, advance widths may vary even if this returns true. + */ + bool isFixedPitch() const { return fIsFixedPitch; } + + /** Copy into 'coordinates' (allocated by the caller) the design variation coordinates. + * + * @param coordinates the buffer into which to write the design variation coordinates. + * @param coordinateCount the number of entries available through 'coordinates'. + * + * @return The number of axes, or -1 if there is an error. + * If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be + * filled with the variation coordinates describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual position + * cannot. + */ + int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const; + + /** Copy into 'parameters' (allocated by the caller) the design variation parameters. + * + * @param parameters the buffer into which to write the design variation parameters. + * @param coordinateCount the number of entries available through 'parameters'. + * + * @return The number of axes, or -1 if there is an error. + * If 'parameters != nullptr' and 'parameterCount >= numAxes' then 'parameters' will be + * filled with the variation parameters describing the position of this typeface in design + * variation space. It is possible the number of axes can be retrieved but actual parameters + * cannot. + */ + int getVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const; + + /** Return a 32bit value for this typeface, unique for the underlying font + data. Will never return 0. + */ + SkFontID uniqueID() const { return fUniqueID; } + + /** Return the uniqueID for the specified typeface. If the face is null, + resolve it to the default font and return its uniqueID. Will never + return 0. + */ + static SkFontID UniqueID(const SkTypeface* face); + + /** Returns true if the two typefaces reference the same underlying font, + handling either being null (treating null as the default font) + */ + static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); + + /** Returns the default normal typeface, which is never nullptr. */ + static sk_sp MakeDefault(); + + /** Creates a new reference to the typeface that most closely matches the + requested familyName and fontStyle. This method allows extended font + face specifiers as in the SkFontStyle type. Will never return null. + + @param familyName May be NULL. The name of the font family. + @param fontStyle The style of the typeface. + @return reference to the closest-matching typeface. Call must call + unref() when they are done. + */ + static sk_sp MakeFromName(const char familyName[], SkFontStyle fontStyle); + + /** Return a new typeface given a file. If the file does not exist, or is + not a valid font file, returns nullptr. + */ + static sk_sp MakeFromFile(const char path[], int index = 0); + + /** Return a new typeface given a stream. If the stream is + not a valid font file, returns nullptr. Ownership of the stream is + transferred, so the caller must not reference it again. + */ + static sk_sp MakeFromStream(std::unique_ptr stream, int index = 0); + + /** Return a new typeface given a SkData. If the data is null, or is not a valid font file, + * returns nullptr. + */ + static sk_sp MakeFromData(sk_sp, int index = 0); + + /** Return a new typeface given font data and configuration. If the data + is not valid font data, returns nullptr. + */ + static sk_sp MakeFromFontData(std::unique_ptr); + + /** Return a new typeface based on this typeface but parameterized as specified in the + SkFontArguments. If the SkFontArguments does not supply an argument for a parameter + in the font then the value from this typeface will be used as the value for that + argument. If the cloned typeface would be exaclty the same as this typeface then + this typeface may be ref'ed and returned. May return nullptr on failure. + */ + sk_sp makeClone(const SkFontArguments&) const; + + /** + * A typeface can serialize just a descriptor (names, etc.), or it can also include the + * actual font data (which can be large). This enum controls how serialize() decides what + * to serialize. + */ + enum class SerializeBehavior { + kDoIncludeData, + kDontIncludeData, + kIncludeDataIfLocal, + }; + + /** Write a unique signature to a stream, sufficient to reconstruct a + typeface referencing the same font when Deserialize is called. + */ + void serialize(SkWStream*, SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** + * Same as serialize(SkWStream*, ...) but returns the serialized data in SkData, instead of + * writing it to a stream. + */ + sk_sp serialize(SerializeBehavior = SerializeBehavior::kIncludeDataIfLocal) const; + + /** Given the data previously written by serialize(), return a new instance + of a typeface referring to the same font. If that font is not available, + return nullptr. + Does not affect ownership of SkStream. + */ + static sk_sp MakeDeserialize(SkStream*); + + enum Encoding : uint8_t { + kUTF8_Encoding, + kUTF16_Encoding, + kUTF32_Encoding + }; + + /** + * Given an array of character codes, of the specified encoding, + * optionally return their corresponding glyph IDs (if glyphs is not NULL). + * + * @param chars pointer to the array of character codes + * @param encoding how the characters are encoded + * @param glyphs (optional) returns the corresponding glyph IDs for each + * character code, up to glyphCount values. If a character code is + * not found in the typeface, the corresponding glyph ID will be 0. + * @param glyphCount number of code points in 'chars' to process. If glyphs + * is not NULL, then it must point sufficient memory to write + * glyphCount values into it. + * @return the number of number of continuous non-zero glyph IDs computed + * from the beginning of chars. This value is valid, even if the + * glyphs parameter is NULL. + */ + int charsToGlyphs(const void* chars, Encoding encoding, SkGlyphID glyphs[], + int glyphCount) const; + + /** + * Return the glyphID that corresponds to the specified unicode code-point + * (in UTF32 encoding). If the unichar is not supported, returns 0. + * + * This is a short-cut for calling charsToGlyphs() with kUTF32_Encoding for one code-point. + */ + SkGlyphID unicharToGlyph(SkUnichar unichar) const; + + /** + * Return the number of glyphs in the typeface. + */ + int countGlyphs() const; + + // Table getters -- may fail if the underlying font format is not organized + // as 4-byte tables. + + /** Return the number of tables in the font. */ + int countTables() const; + + /** Copy into tags[] (allocated by the caller) the list of table tags in + * the font, and return the number. This will be the same as CountTables() + * or 0 if an error occured. If tags == NULL, this only returns the count + * (the same as calling countTables()). + */ + int getTableTags(SkFontTableTag tags[]) const; + + /** Given a table tag, return the size of its contents, or 0 if not present + */ + size_t getTableSize(SkFontTableTag) const; + + /** Copy the contents of a table into data (allocated by the caller). Note + * that the contents of the table will be in their native endian order + * (which for most truetype tables is big endian). If the table tag is + * not found, or there is an error copying the data, then 0 is returned. + * If this happens, it is possible that some or all of the memory pointed + * to by data may have been written to, even though an error has occured. + * + * @param fontID the font to copy the table from + * @param tag The table tag whose contents are to be copied + * @param offset The offset in bytes into the table's contents where the + * copy should start from. + * @param length The number of bytes, starting at offset, of table data + * to copy. + * @param data storage address where the table contents are copied to + * @return the number of bytes actually copied into data. If offset+length + * exceeds the table's size, then only the bytes up to the table's + * size are actually copied, and this is the value returned. If + * offset > the table's size, or tag is not a valid table, + * then 0 is returned. + */ + size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, + void* data) const; + + /** + * Return the units-per-em value for this typeface, or zero if there is an + * error. + */ + int getUnitsPerEm() const; + + /** + * Given a run of glyphs, return the associated horizontal adjustments. + * Adjustments are in "design units", which are integers relative to the + * typeface's units per em (see getUnitsPerEm). + * + * Some typefaces are known to never support kerning. Calling this method + * with all zeros (e.g. getKerningPairAdustments(NULL, 0, NULL)) returns + * a boolean indicating if the typeface might support kerning. If it + * returns false, then it will always return false (no kerning) for all + * possible glyph runs. If it returns true, then it *may* return true for + * somne glyph runs. + * + * If count is non-zero, then the glyphs parameter must point to at least + * [count] valid glyph IDs, and the adjustments parameter must be + * sized to at least [count - 1] entries. If the method returns true, then + * [count-1] entries in the adjustments array will be set. If the method + * returns false, then no kerning should be applied, and the adjustments + * array will be in an undefined state (possibly some values may have been + * written, but none of them should be interpreted as valid values). + */ + bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + struct LocalizedString { + SkString fString; + SkString fLanguage; + }; + class LocalizedStrings : ::SkNoncopyable { + public: + virtual ~LocalizedStrings() { } + virtual bool next(LocalizedString* localizedString) = 0; + void unref() { delete this; } + }; + /** + * Returns an iterator which will attempt to enumerate all of the + * family names specified by the font. + * It is the caller's responsibility to unref() the returned pointer. + */ + LocalizedStrings* createFamilyNameIterator() const; + + /** + * Return the family name for this typeface. It will always be returned + * encoded as UTF8, but the language of the name is whatever the host + * platform chooses. + */ + void getFamilyName(SkString* name) const; + + /** + * Return a stream for the contents of the font data, or NULL on failure. + * If ttcIndex is not null, it is set to the TrueTypeCollection index + * of this typeface within the stream, or 0 if the stream is not a + * collection. + * The caller is responsible for deleting the stream. + */ + SkStreamAsset* openStream(int* ttcIndex) const; + + /** + * Return the font data, or nullptr on failure. + */ + std::unique_ptr makeFontData() const; + + /** + * Return a scalercontext for the given descriptor. If this fails, then + * if allowFailure is true, this returns NULL, else it returns a + * dummy scalercontext that will not crash, but will draw nothing. + */ + std::unique_ptr createScalerContext(const SkScalerContextEffects&, + const SkDescriptor*, + bool allowFailure = false) const; + + /** + * Return a rectangle (scaled to 1-pt) that represents the union of the bounds of all + * of the glyphs, but each one positioned at (0,). This may be conservatively large, and + * will not take into account any hinting or other size-specific adjustments. + */ + SkRect getBounds() const; + + // PRIVATE / EXPERIMENTAL -- do not call + void filterRec(SkScalerContextRec* rec) const { + this->onFilterRec(rec); + } + // PRIVATE / EXPERIMENTAL -- do not call + void getFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { + this->onGetFontDescriptor(desc, isLocal); + } + // PRIVATE / EXPERIMENTAL -- do not call + void* internal_private_getCTFontRef() const { + return this->onGetCTFontRef(); + } + +protected: + /** uniqueID must be unique and non-zero + */ + SkTypeface(const SkFontStyle& style, bool isFixedPitch = false); + virtual ~SkTypeface(); + + virtual sk_sp onMakeClone(const SkFontArguments&) const; + + /** Sets the fixedPitch bit. If used, must be called in the constructor. */ + void setIsFixedPitch(bool isFixedPitch) { fIsFixedPitch = isFixedPitch; } + /** Sets the font style. If used, must be called in the constructor. */ + void setFontStyle(SkFontStyle style) { fStyle = style; } + + virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const = 0; + virtual void onFilterRec(SkScalerContextRec*) const = 0; + friend class SkScalerContext; // onFilterRec + + // Subclasses *must* override this method to work with the PDF backend. + virtual std::unique_ptr onGetAdvancedMetrics() const; + // For type1 postscript fonts only, set the glyph names for each glyph. + // destination array is non-null, and points to an array of size this->countGlyphs(). + // Backends that do not suport type1 fonts should not override. + virtual void getPostScriptGlyphNames(SkString*) const {} + + // The mapping from glyph to Unicode; array indices are glyph ids. + // For each glyph, give the default Unicode value, if it exists. + // dstArray is non-null, and points to an array of size this->countGlyphs(). + virtual void getGlyphToUnicodeMap(SkUnichar* dstArray) const; + + virtual SkStreamAsset* onOpenStream(int* ttcIndex) const = 0; + // TODO: make pure virtual. + virtual std::unique_ptr onMakeFontData() const; + + virtual int onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const = 0; + + virtual int onGetVariationDesignParameters( + SkFontParameters::Variation::Axis parameters[], int parameterCount) const; + + virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; + + virtual int onCharsToGlyphs(const void* chars, Encoding, SkGlyphID glyphs[], + int glyphCount) const = 0; + virtual int onCountGlyphs() const = 0; + + virtual int onGetUPEM() const = 0; + virtual bool onGetKerningPairAdjustments(const SkGlyphID glyphs[], int count, + int32_t adjustments[]) const; + + /** Returns the family name of the typeface as known by its font manager. + * This name may or may not be produced by the family name iterator. + */ + virtual void onGetFamilyName(SkString* familyName) const = 0; + + /** Returns an iterator over the family names in the font. */ + virtual LocalizedStrings* onCreateFamilyNameIterator() const = 0; + + virtual int onGetTableTags(SkFontTableTag tags[]) const = 0; + virtual size_t onGetTableData(SkFontTableTag, size_t offset, + size_t length, void* data) const = 0; + + virtual bool onComputeBounds(SkRect*) const; + + virtual void* onGetCTFontRef() const { return nullptr; } + +private: + /** Retrieve detailed typeface metrics. Used by the PDF backend. */ + std::unique_ptr getAdvancedMetrics() const; + friend class SkRandomTypeface; // getAdvancedMetrics + friend class SkPDFFont; // getAdvancedMetrics + + /** Style specifies the intrinsic style attributes of a given typeface */ + enum Style { + kNormal = 0, + kBold = 0x01, + kItalic = 0x02, + + // helpers + kBoldItalic = 0x03 + }; + static SkFontStyle FromOldStyle(Style oldStyle); + static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal); + + friend class SkFontPriv; // GetDefaultTypeface + friend class SkPaintPriv; // GetDefaultTypeface + +private: + SkFontID fUniqueID; + SkFontStyle fStyle; + mutable SkRect fBounds; + mutable SkOnce fBoundsOnce; + bool fIsFixedPitch; + + typedef SkWeakRefCnt INHERITED; +}; +#endif diff --git a/skia/include/core/SkTypes.h b/skia/include/core/SkTypes.h new file mode 100644 index 00000000..697afc84 --- /dev/null +++ b/skia/include/core/SkTypes.h @@ -0,0 +1,228 @@ +/* + * 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 SkTypes_DEFINED +#define SkTypes_DEFINED + +// IWYU pragma: begin_exports +#include "SkPreConfig.h" +#include "SkUserConfig.h" +#include "SkPostConfig.h" +#include +#include +// IWYU pragma: end_exports + +/** \file SkTypes.h +*/ + +/** See SkGraphics::GetVersion() to retrieve these at runtime +*/ +#define SKIA_VERSION_MAJOR 1 +#define SKIA_VERSION_MINOR 0 +#define SKIA_VERSION_PATCH 0 + + +/** Called internally if we hit an unrecoverable error. + The platform implementation must not return, but should either throw + an exception or otherwise exit. +*/ +SK_API extern void sk_abort_no_print(void); + +#ifndef SkDebugf + SK_API void SkDebugf(const char format[], ...); +#endif + +// SkASSERT, SkASSERTF and SkASSERT_RELEASE can be used as stand alone assertion expressions, e.g. +// uint32_t foo(int x) { +// SkASSERT(x > 4); +// return x - 4; +// } +// and are also written to be compatible with constexpr functions: +// constexpr uint32_t foo(int x) { +// return SkASSERT(x > 4), +// x - 4; +// } +#define SkASSERT_RELEASE(cond) \ + static_cast( (cond) ? (void)0 : []{ SK_ABORT("assert(" #cond ")"); }() ) + +#ifdef SK_DEBUG + #define SkASSERT(cond) SkASSERT_RELEASE(cond) + #define SkASSERTF(cond, fmt, ...) static_cast( (cond) ? (void)0 : [&]{ \ + SkDebugf(fmt"\n", __VA_ARGS__); \ + SK_ABORT("assert(" #cond ")"); \ + }() ) + #define SkDEBUGFAIL(message) SK_ABORT(message) + #define SkDEBUGFAILF(fmt, ...) SkASSERTF(false, fmt, ##__VA_ARGS__) + #define SkDEBUGCODE(...) __VA_ARGS__ + #define SkDEBUGF(...) SkDebugf(__VA_ARGS__) + #define SkAssertResult(cond) SkASSERT(cond) +#else + #define SkASSERT(cond) static_cast(0) + #define SkASSERTF(cond, fmt, ...) static_cast(0) + #define SkDEBUGFAIL(message) + #define SkDEBUGFAILF(fmt, ...) + #define SkDEBUGCODE(...) + #define SkDEBUGF(...) + + // unlike SkASSERT, this macro executes its condition in the non-debug build. + // The if is present so that this can be used with functions marked SK_WARN_UNUSED_RESULT. + #define SkAssertResult(cond) if (cond) {} do {} while(false) +#endif + +//////////////////////////////////////////////////////////////////////////////// + +/** Fast type for unsigned 8 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U8CPU; + +/** Fast type for unsigned 16 bits. Use for parameter passing and local + variables, not for storage +*/ +typedef unsigned U16CPU; + +/** @return false or true based on the condition +*/ +template static constexpr bool SkToBool(const T& x) { return 0 != x; } + +static constexpr int16_t SK_MaxS16 = INT16_MAX; +static constexpr int16_t SK_MinS16 = -SK_MaxS16; + +static constexpr int32_t SK_MaxS32 = INT32_MAX; +static constexpr int32_t SK_MinS32 = -SK_MaxS32; +static constexpr int32_t SK_NaN32 = INT32_MIN; + +static constexpr int64_t SK_MaxS64 = INT64_MAX; +static constexpr int64_t SK_MinS64 = -SK_MaxS64; + +static inline constexpr int32_t SkLeftShift(int32_t value, int32_t shift) { + return (int32_t) ((uint32_t) value << shift); +} + +static inline constexpr int64_t SkLeftShift(int64_t value, int32_t shift) { + return (int64_t) ((uint64_t) value << shift); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** @return the number of entries in an array (not a pointer) +*/ +template char (&SkArrayCountHelper(T (&array)[N]))[N]; +#define SK_ARRAY_COUNT(array) (sizeof(SkArrayCountHelper(array))) + +//////////////////////////////////////////////////////////////////////////////// + +template static constexpr T SkAlign2(T x) { return (x + 1) >> 1 << 1; } +template static constexpr T SkAlign4(T x) { return (x + 3) >> 2 << 2; } +template static constexpr T SkAlign8(T x) { return (x + 7) >> 3 << 3; } + +template static constexpr bool SkIsAlign2(T x) { return 0 == (x & 1); } +template static constexpr bool SkIsAlign4(T x) { return 0 == (x & 3); } +template static constexpr bool SkIsAlign8(T x) { return 0 == (x & 7); } + +template static constexpr T SkAlignPtr(T x) { + return sizeof(void*) == 8 ? SkAlign8(x) : SkAlign4(x); +} +template static constexpr bool SkIsAlignPtr(T x) { + return sizeof(void*) == 8 ? SkIsAlign8(x) : SkIsAlign4(x); +} + +typedef uint32_t SkFourByteTag; +static inline constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d) { + return (((uint8_t)a << 24) | ((uint8_t)b << 16) | ((uint8_t)c << 8) | (uint8_t)d); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** 32 bit integer to hold a unicode value +*/ +typedef int32_t SkUnichar; + +/** 16 bit unsigned integer to hold a glyph index +*/ +typedef uint16_t SkGlyphID; + +/** 32 bit value to hold a millisecond duration + Note that SK_MSecMax is about 25 days. +*/ +typedef uint32_t SkMSec; + +/** Maximum representable milliseconds; 24d 20h 31m 23.647s. +*/ +static constexpr SkMSec SK_MSecMax = INT32_MAX; + +/** The generation IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidGenID = 0; + +/** The unique IDs in Skia reserve 0 has an invalid marker. +*/ +static constexpr uint32_t SK_InvalidUniqueID = 0; + +static inline int32_t SkAbs32(int32_t value) { + SkASSERT(value != SK_NaN32); // The most negative int32_t can't be negated. + if (value < 0) { + value = -value; + } + return value; +} + +template static inline T SkTAbs(T value) { + if (value < 0) { + value = -value; + } + return value; +} + +static inline int32_t SkMax32(int32_t a, int32_t b) { + if (a < b) + a = b; + return a; +} + +static inline int32_t SkMin32(int32_t a, int32_t b) { + if (a > b) + a = b; + return a; +} + +template constexpr const T& SkTMin(const T& a, const T& b) { + return (a < b) ? a : b; +} + +template constexpr const T& SkTMax(const T& a, const T& b) { + return (b < a) ? a : b; +} + +template constexpr const T& SkTClamp(const T& x, const T& lo, const T& hi) { + return (x < lo) ? lo : SkTMin(x, hi); +} + +/** @return value pinned (clamped) between min and max, inclusively. +*/ +template static constexpr const T& SkTPin(const T& value, const T& min, const T& max) { + return SkTMax(SkTMin(value, max), min); +} + +//////////////////////////////////////////////////////////////////////////////// + +/** Indicates whether an allocation should count against a cache budget. +*/ +enum class SkBudgeted : bool { + kNo = false, + kYes = true +}; + +/** Indicates whether a backing store needs to be an exact match or can be + larger than is strictly necessary +*/ +enum class SkBackingFit { + kApprox, + kExact +}; + +#endif diff --git a/skia/include/core/SkUnPreMultiply.h b/skia/include/core/SkUnPreMultiply.h new file mode 100644 index 00000000..4fa5d579 --- /dev/null +++ b/skia/include/core/SkUnPreMultiply.h @@ -0,0 +1,56 @@ + +/* + * 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 SkUnPreMultiply_DEFINED +#define SkUnPreMultiply_DEFINED + +#include "SkColor.h" + +class SK_API SkUnPreMultiply { +public: + typedef uint32_t Scale; + + // index this table with alpha [0..255] + static const Scale* GetScaleTable() { + return gTable; + } + + static Scale GetScale(U8CPU alpha) { + SkASSERT(alpha <= 255); + return gTable[alpha]; + } + + /** Usage: + + const Scale* table = SkUnPreMultiply::GetScaleTable(); + + for (...) { + unsigned a = ... + SkUnPreMultiply::Scale scale = table[a]; + + red = SkUnPreMultiply::ApplyScale(scale, red); + ... + // now red is unpremultiplied + } + */ + static U8CPU ApplyScale(Scale scale, U8CPU component) { + SkASSERT(component <= 255); + return (scale * component + (1 << 23)) >> 24; + } + + static SkColor PMColorToColor(SkPMColor c); + +private: + static const uint32_t gTable[256]; +}; + +#endif diff --git a/skia/include/core/SkVertices.h b/skia/include/core/SkVertices.h new file mode 100644 index 00000000..63a27a0a --- /dev/null +++ b/skia/include/core/SkVertices.h @@ -0,0 +1,281 @@ +/* + * 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 SkVertices_DEFINED +#define SkVertices_DEFINED + +#include "SkColor.h" +#include "SkData.h" +#include "SkPoint.h" +#include "SkRect.h" +#include "SkRefCnt.h" + +/** + * An immutable set of vertex data that can be used with SkCanvas::drawVertices. + */ +class SK_API SkVertices : public SkNVRefCnt { +public: + // BoneIndices indicates which (of a maximum of 4 bones) a given vertex will interpolate + // between. To indicate that a slot is not used, the convention is to assign the bone index + // to 0. + struct BoneIndices { + uint32_t indices[4]; + + uint32_t& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return indices[i]; + } + + const uint32_t& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return indices[i]; + } + }; + + // BoneWeights stores the interpolation weight for each of the (maximum of 4) bones a given + // vertex interpolates between. To indicate that a slot is not used, the weight for that + // slot should be 0. + struct BoneWeights { + float weights[4]; + + float& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return weights[i]; + } + + const float& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 4); + return weights[i]; + } + }; + + // Bone stores a 3x2 transformation matrix in column major order: + // | scaleX skewX transX | + // | skewY scaleY transY | + // SkRSXform is insufficient because bones can have non uniform scale. + struct Bone { + float values[6]; + + float& operator[] (int i) { + SkASSERT(i >= 0); + SkASSERT(i < 6); + return values[i]; + } + + const float& operator[] (int i) const { + SkASSERT(i >= 0); + SkASSERT(i < 6); + return values[i]; + } + + SkPoint mapPoint(const SkPoint& point) const { + float x = values[0] * point.x() + values[2] * point.y() + values[4]; + float y = values[1] * point.x() + values[3] * point.y() + values[5]; + return SkPoint::Make(x, y); + } + + SkRect mapRect(const SkRect& rect) const { + SkRect dst = SkRect::MakeEmpty(); + SkPoint quad[4]; + rect.toQuad(quad); + for (int i = 0; i < 4; i ++) { + quad[i] = mapPoint(quad[i]); + } + dst.setBoundsNoCheck(quad, 4); + return dst; + } + }; + + enum VertexMode { + kTriangles_VertexMode, + kTriangleStrip_VertexMode, + kTriangleFan_VertexMode, + + kLast_VertexMode = kTriangleFan_VertexMode, + }; + + /** + * Create a vertices by copying the specified arrays. texs, colors, boneIndices, and + * boneWeights may be nullptr, and indices is ignored if indexCount == 0. + * + * boneIndices and boneWeights must either both be nullptr or both point to valid data. + * If specified, they must both contain 'vertexCount' entries. + */ + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + const BoneIndices boneIndices[], + const BoneWeights boneWeights[], + int indexCount, + const uint16_t indices[], + bool isVolatile = true); + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + const BoneIndices boneIndices[], + const BoneWeights boneWeights[], + bool isVolatile = true) { + return MakeCopy(mode, + vertexCount, + positions, + texs, + colors, + boneIndices, + boneWeights, + 0, + nullptr, + isVolatile); + } + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + int indexCount, + const uint16_t indices[], + bool isVolatile = true) { + return MakeCopy(mode, + vertexCount, + positions, + texs, + colors, + nullptr, + nullptr, + indexCount, + indices, + isVolatile); + } + + static sk_sp MakeCopy(VertexMode mode, int vertexCount, + const SkPoint positions[], + const SkPoint texs[], + const SkColor colors[], + bool isVolatile = true) { + return MakeCopy(mode, vertexCount, positions, texs, colors, nullptr, nullptr, isVolatile); + } + + struct Sizes; + + enum BuilderFlags { + kHasTexCoords_BuilderFlag = 1 << 0, + kHasColors_BuilderFlag = 1 << 1, + kHasBones_BuilderFlag = 1 << 2, + kIsNonVolatile_BuilderFlag = 1 << 3, + }; + class Builder { + public: + Builder(VertexMode mode, int vertexCount, int indexCount, uint32_t flags); + + bool isValid() const { return fVertices != nullptr; } + + // if the builder is invalid, these will return 0 + int vertexCount() const; + int indexCount() const; + bool isVolatile() const; + SkPoint* positions(); + SkPoint* texCoords(); // returns null if there are no texCoords + SkColor* colors(); // returns null if there are no colors + BoneIndices* boneIndices(); // returns null if there are no bone indices + BoneWeights* boneWeights(); // returns null if there are no bone weights + uint16_t* indices(); // returns null if there are no indices + + // Detach the built vertices object. After the first call, this will always return null. + sk_sp detach(); + + private: + Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&); + + void init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, const Sizes&); + + // holds a partially complete object. only completed in detach() + sk_sp fVertices; + // Extra storage for intermediate vertices in the case where the client specifies indexed + // triangle fans. These get converted to indexed triangles when the Builder is finalized. + std::unique_ptr fIntermediateFanIndices; + + friend class SkVertices; + }; + + uint32_t uniqueID() const { return fUniqueID; } + VertexMode mode() const { return fMode; } + const SkRect& bounds() const { return fBounds; } + + bool hasColors() const { return SkToBool(this->colors()); } + bool hasTexCoords() const { return SkToBool(this->texCoords()); } + bool hasBones() const { return SkToBool(this->boneIndices()); } + bool hasIndices() const { return SkToBool(this->indices()); } + + int vertexCount() const { return fVertexCnt; } + const SkPoint* positions() const { return fPositions; } + const SkPoint* texCoords() const { return fTexs; } + const SkColor* colors() const { return fColors; } + + const BoneIndices* boneIndices() const { return fBoneIndices; } + const BoneWeights* boneWeights() const { return fBoneWeights; } + + int indexCount() const { return fIndexCnt; } + const uint16_t* indices() const { return fIndices; } + + bool isVolatile() const { return fIsVolatile; } + + sk_sp applyBones(const Bone bones[], int boneCount) const; + + // returns approximate byte size of the vertices object + size_t approximateSize() const; + + /** + * Recreate a vertices from a buffer previously created by calling encode(). + * Returns null if the data is corrupt or the length is incorrect for the contents. + */ + static sk_sp Decode(const void* buffer, size_t length); + + /** + * Pack the vertices object into a byte buffer. This can be used to recreate the vertices + * by calling Decode() with the buffer. + */ + sk_sp encode() const; + +private: + SkVertices() {} + + // these are needed since we've manually sized our allocation (see Builder::init) + friend class SkNVRefCnt; + void operator delete(void* p); + + static sk_sp Alloc(int vCount, int iCount, uint32_t builderFlags, + size_t* arraySize); + + // we store this first, to pair with the refcnt in our base-class, so we don't have an + // unnecessary pad between it and the (possibly 8-byte aligned) ptrs. + uint32_t fUniqueID; + + // these point inside our allocation, so none of these can be "freed" + SkPoint* fPositions; + SkPoint* fTexs; + SkColor* fColors; + BoneIndices* fBoneIndices; + BoneWeights* fBoneWeights; + uint16_t* fIndices; + + SkRect fBounds; // computed to be the union of the fPositions[] + int fVertexCnt; + int fIndexCnt; + + bool fIsVolatile; + + VertexMode fMode; + // below here is where the actual array data is stored. +}; + +#endif diff --git a/skia/include/core/SkYUVAIndex.h b/skia/include/core/SkYUVAIndex.h new file mode 100644 index 00000000..f52786c5 --- /dev/null +++ b/skia/include/core/SkYUVAIndex.h @@ -0,0 +1,92 @@ +/* + * 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 SkYUVAIndex_DEFINED +#define SkYUVAIndex_DEFINED + +#include "SkTypes.h" + +/** \enum SkColorChannel + Describes different color channels one can manipulate +*/ +enum class SkColorChannel { + kR, // the red channel + kG, // the green channel + kB, // the blue channel + kA, // the alpha channel + + kLastEnum = kA, +}; + +/** \struct SkYUVAIndex + Describes from which image source and which channel to read each individual YUVA plane. + + SkYUVAIndex contains a index for which image source to read from and a enum for which channel + to read from. +*/ +struct SK_API SkYUVAIndex { + bool operator==(const SkYUVAIndex& that) const { + return this->fIndex == that.fIndex && this->fChannel == that.fChannel; + } + + bool operator!=(const SkYUVAIndex& that) const { + return !(*this == that); + } + + // Index in the array of SkYUVAIndex + // TODO: rename as Component + enum Index { + kY_Index = 0, + kU_Index = 1, + kV_Index = 2, + kA_Index = 3, + + kLast_Index = kA_Index + }; + static constexpr int kIndexCount = kLast_Index + 1; + + /** The index is a number between -1..3 which definies which image source to read from, where -1 + * means the image source doesn't exist. The assumption is we will always have image sources for + * each of YUV planes, but optionally have image source for A plane. */ + int fIndex; + /** The channel describes from which channel to read the info from. Currently we only deal with + * YUV and NV12 and channel info is ignored. */ + SkColorChannel fChannel; + + static bool AreValidIndices(const SkYUVAIndex yuvaIndices[4], int* numPlanes) { + // Note that 'numPlanes' is always filled in even if the indices are not valid. + // This means it can always be used to process the backing resources (but be careful + // of empty intervening slots). + int maxSlotUsed = -1; + bool used[4] = { false, false, false, false }; + bool valid = true; + for (int i = 0; i < 4; ++i) { + if (yuvaIndices[i].fIndex < 0) { + if (SkYUVAIndex::kA_Index != i) { + valid = false; // only the 'A' plane can be omitted + } + } else if (yuvaIndices[i].fIndex > 3) { + valid = false; // A maximum of four input textures is allowed + } else { + maxSlotUsed = SkTMax(yuvaIndices[i].fIndex, maxSlotUsed); + used[i] = true; + } + } + + // All the used slots should be packed starting at 0 with no gaps + for (int i = 0; i <= maxSlotUsed; ++i) { + if (!used[i]) { + valid = false; + } + } + + *numPlanes = maxSlotUsed + 1; + return valid; + } +}; + +#endif diff --git a/skia/include/core/SkYUVASizeInfo.h b/skia/include/core/SkYUVASizeInfo.h new file mode 100644 index 00000000..4f2e2f5a --- /dev/null +++ b/skia/include/core/SkYUVASizeInfo.h @@ -0,0 +1,61 @@ +/* + * 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 SkYUVASizeInfo_DEFINED +#define SkYUVASizeInfo_DEFINED + +#include "SkImageInfo.h" +#include "SkSize.h" + +struct SK_API SkYUVASizeInfo { + static constexpr auto kMaxCount = 4; + + SkISize fSizes[kMaxCount]; + + /** + * While the widths of the Y, U, V and A planes are not restricted, the + * implementation often requires that the width of the memory allocated + * for each plane be a multiple of 8. + * + * This struct allows us to inform the client how many "widthBytes" + * that we need. Note that we use the new idea of "widthBytes" + * because this idea is distinct from "rowBytes" (used elsewhere in + * Skia). "rowBytes" allow the last row of the allocation to not + * include any extra padding, while, in this case, every single row of + * the allocation must be at least "widthBytes". + */ + size_t fWidthBytes[kMaxCount]; + + bool operator==(const SkYUVASizeInfo& that) const { + for (int i = 0; i < kMaxCount; ++i) { + SkASSERT((!fSizes[i].isEmpty() && fWidthBytes[i]) || + (fSizes[i].isEmpty() && !fWidthBytes[i])); + if (fSizes[i] != that.fSizes[i] || fWidthBytes[i] != that.fWidthBytes[i]) { + return false; + } + } + + return true; + } + + size_t computeTotalBytes() const { + size_t totalBytes = 0; + + for (int i = 0; i < kMaxCount; ++i) { + SkASSERT((!fSizes[i].isEmpty() && fWidthBytes[i]) || + (fSizes[i].isEmpty() && !fWidthBytes[i])); + totalBytes += fWidthBytes[i] * fSizes[i].height(); + } + + return totalBytes; + } + + void computePlanes(void* base, void* planes[kMaxCount]) const; + +}; + +#endif // SkYUVASizeInfo_DEFINED diff --git a/skia/include/docs/SkPDFDocument.h b/skia/include/docs/SkPDFDocument.h new file mode 100644 index 00000000..4623c7ac --- /dev/null +++ b/skia/include/docs/SkPDFDocument.h @@ -0,0 +1,176 @@ +// Copyright 2018 Google LLC. +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +#ifndef SkPDFDocument_DEFINED +#define SkPDFDocument_DEFINED + +#include "SkDocument.h" + +#include "SkScalar.h" +#include "SkString.h" +#include "SkTime.h" + +namespace SkPDF { + +/** Table 333 in PDF 32000-1:2008 +*/ +enum class DocumentStructureType { + kDocument, + kPart, + kArt, // Article + kSect, // Section + kDiv, + kBlockQuote, + kCaption, + kTOC, // Table of Contents + kTOCI, // Table of Contents Item + kIndex, + kNonStruct, + kPrivate, + kH, // Heading + kH1, // Heading level 1 + kH2, + kH3, + kH4, + kH5, + kH6, // Heading level 6 + kP, // Paragraph + kL, // List + kLI, // List item + kLbl, // List item label + kLBody, // List item body + kTable, + kTR, + kTH, + kTD, + kTHead, + kTBody, + kTFoot, + kSpan, + kQuote, + kNote, + kReference, + kBibEntry, + kCode, + kLink, + kAnnot, + kRuby, + kWarichu, + kFigure, + kFormula, + kForm, // Form control (not like an HTML FORM element) +}; + +/** + * A node in a PDF structure tree, giving a semantic representation + * of the content. Each node ID is associated with content + * by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing. + */ +struct StructureElementNode { + const StructureElementNode* fChildren = nullptr; + size_t fChildCount; + int fNodeId; + DocumentStructureType fType; +}; + +/** Optional metadata to be passed into the PDF factory function. +*/ +struct Metadata { + /** The document's title. + */ + SkString fTitle; + + /** The name of the person who created the document. + */ + SkString fAuthor; + + /** The subject of the document. + */ + SkString fSubject; + + /** Keywords associated with the document. Commas may be used to delineate + keywords within the string. + */ + SkString fKeywords; + + /** If the document was converted to PDF from another format, + the name of the conforming product that created the + original document from which it was converted. + */ + SkString fCreator; + + /** The product that is converting this document to PDF. + Leave fProducer empty to get the default, correct value. + */ + SkString fProducer; + + /** The date and time the document was created. + The zero default value represents an unknown/unset time. + */ + SkTime::DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The date and time the document was most recently modified. + The zero default value represents an unknown/unset time. + */ + SkTime::DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0}; + + /** The DPI (pixels-per-inch) at which features without native PDF support + will be rasterized (e.g. draw image with perspective, draw text with + perspective, ...) A larger DPI would create a PDF that reflects the + original intent with better fidelity, but it can make for larger PDF + files too, which would use more memory while rendering, and it would be + slower to be processed or sent online or to printer. + */ + SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI; + + /** If true, include XMP metadata, a document UUID, and sRGB output intent + information. This adds length to the document and makes it + non-reproducable, but are necessary features for PDF/A-2b conformance + */ + bool fPDFA = false; + + /** Encoding quality controls the trade-off between size and quality. By + default this is set to 101 percent, which corresponds to lossless + encoding. If this value is set to a value <= 100, and the image is + opaque, it will be encoded (using JPEG) with that quality setting. + */ + int fEncodingQuality = 101; + + /** + * An optional tree of structured document tags that provide + * a semantic representation of the content. The caller + * should retain ownership. + */ + const StructureElementNode* fStructureElementTreeRoot = nullptr; +}; + +/** Associate a node ID with subsequent drawing commands in an + SkCanvas. The same node ID can appear in a StructureElementNode + in order to associate a document's structure element tree with + its content. + + A node ID of zero indicates no node ID. + + @param canvas The canvas used to draw to the PDF. + @param nodeId The node ID for subsequent drawing commands. +*/ +SK_API void SetNodeId(SkCanvas* dst, int nodeID); + +/** Create a PDF-backed document, writing the results into a SkWStream. + + PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm. + + @param stream A PDF document will be written to this stream. The document may write + to the stream at anytime during its lifetime, until either close() is + called or the document is deleted. + @param metadata a PDFmetadata object. Any fields may be left empty. + + @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument. +*/ +SK_API sk_sp MakeDocument(SkWStream* stream, const Metadata& metadata); + +static inline sk_sp MakeDocument(SkWStream* stream) { + return MakeDocument(stream, Metadata()); +} + +} // namespace SkPDF +#endif // SkPDFDocument_DEFINED diff --git a/skia/include/docs/SkXPSDocument.h b/skia/include/docs/SkXPSDocument.h new file mode 100644 index 00000000..a669f471 --- /dev/null +++ b/skia/include/docs/SkXPSDocument.h @@ -0,0 +1,27 @@ +/* + * 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 SkXPSDocument_DEFINED +#define SkXPSDocument_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN + +#include "SkDocument.h" + +struct IXpsOMObjectFactory; + +namespace SkXPS { + +SK_API sk_sp MakeDocument(SkWStream* stream, + IXpsOMObjectFactory* xpsFactory, + SkScalar dpi = SK_ScalarDefaultRasterDPI); + +} // namespace SkXPS +#endif // SK_BUILD_FOR_WIN +#endif // SkXPSDocument_DEFINED diff --git a/skia/include/effects/Sk1DPathEffect.h b/skia/include/effects/Sk1DPathEffect.h new file mode 100644 index 00000000..13310050 --- /dev/null +++ b/skia/include/effects/Sk1DPathEffect.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 Sk1DPathEffect_DEFINED +#define Sk1DPathEffect_DEFINED + +#include "SkFlattenable.h" +#include "SkPathEffect.h" +#include "SkPath.h" + +class SkPathMeasure; + +// This class is not exported to java. +class SK_API Sk1DPathEffect : public SkPathEffect { +public: +protected: + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; + + /** Called at the start of each contour, returns the initial offset + into that contour. + */ + virtual SkScalar begin(SkScalar contourLength) const = 0; + /** Called with the current distance along the path, with the current matrix + for the point/tangent at the specified distance. + Return the distance to travel for the next call. If return <= 0, then that + contour is done. + */ + virtual SkScalar next(SkPath* dst, SkScalar dist, SkPathMeasure&) const = 0; + +private: + typedef SkPathEffect INHERITED; +}; + +class SK_API SkPath1DPathEffect : public Sk1DPathEffect { +public: + enum Style { + kTranslate_Style, // translate the shape to each position + kRotate_Style, // rotate the shape about its center + kMorph_Style, // transform each point, and turn lines into curves + + kLastEnum_Style = kMorph_Style, + }; + + /** Dash by replicating the specified path. + @param path The path to replicate (dash) + @param advance The space between instances of path + @param phase distance (mod advance) along path for its initial position + @param style how to transform path at each point (based on the current + position and tangent) + */ + static sk_sp Make(const SkPath& path, SkScalar advance, SkScalar phase, Style); + +protected: + SkPath1DPathEffect(const SkPath& path, SkScalar advance, SkScalar phase, Style); + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const override; + + // overrides from Sk1DPathEffect + SkScalar begin(SkScalar contourLength) const override; + SkScalar next(SkPath*, SkScalar, SkPathMeasure&) const override; + +private: + SK_FLATTENABLE_HOOKS(SkPath1DPathEffect) + + SkPath fPath; // copied from constructor + SkScalar fAdvance; // copied from constructor + SkScalar fInitialOffset; // computed from phase + Style fStyle; // copied from constructor + + typedef Sk1DPathEffect INHERITED; +}; + +#endif diff --git a/skia/include/effects/Sk2DPathEffect.h b/skia/include/effects/Sk2DPathEffect.h new file mode 100644 index 00000000..5d7a208d --- /dev/null +++ b/skia/include/effects/Sk2DPathEffect.h @@ -0,0 +1,105 @@ +/* + * 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 Sk2DPathEffect_DEFINED +#define Sk2DPathEffect_DEFINED + +#include "SkFlattenable.h" +#include "SkPath.h" +#include "SkPathEffect.h" +#include "SkMatrix.h" + +class SK_API Sk2DPathEffect : public SkPathEffect { +protected: + /** New virtual, to be overridden by subclasses. + This is called once from filterPath, and provides the + uv parameter bounds for the path. Subsequent calls to + next() will receive u and v values within these bounds, + and then a call to end() will signal the end of processing. + */ + virtual void begin(const SkIRect& uvBounds, SkPath* dst) const; + virtual void next(const SkPoint& loc, int u, int v, SkPath* dst) const; + virtual void end(SkPath* dst) const; + + /** Low-level virtual called per span of locations in the u-direction. + The default implementation calls next() repeatedly with each + location. + */ + virtual void nextSpan(int u, int v, int ucount, SkPath* dst) const; + + const SkMatrix& getMatrix() const { return fMatrix; } + + // protected so that subclasses can call this during unflattening + explicit Sk2DPathEffect(const SkMatrix& mat); + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath*, const SkPath&, SkStrokeRec*, const SkRect*) const override; + +private: + SkMatrix fMatrix, fInverse; + bool fMatrixIsInvertible; + + // illegal + Sk2DPathEffect(const Sk2DPathEffect&); + Sk2DPathEffect& operator=(const Sk2DPathEffect&); + + friend class Sk2DPathEffectBlitter; + typedef SkPathEffect INHERITED; +}; + +class SK_API SkLine2DPathEffect : public Sk2DPathEffect { +public: + static sk_sp Make(SkScalar width, const SkMatrix& matrix) { + if (!(width >= 0)) { + return nullptr; + } + return sk_sp(new SkLine2DPathEffect(width, matrix)); + } + + +protected: + SkLine2DPathEffect(SkScalar width, const SkMatrix& matrix) + : Sk2DPathEffect(matrix), fWidth(width) { + SkASSERT(width >= 0); + } + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; + + void nextSpan(int u, int v, int ucount, SkPath*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkLine2DPathEffect) + + SkScalar fWidth; + + typedef Sk2DPathEffect INHERITED; +}; + +class SK_API SkPath2DPathEffect : public Sk2DPathEffect { +public: + /** + * Stamp the specified path to fill the shape, using the matrix to define + * the latice. + */ + static sk_sp Make(const SkMatrix& matrix, const SkPath& path) { + return sk_sp(new SkPath2DPathEffect(matrix, path)); + } + +protected: + SkPath2DPathEffect(const SkMatrix&, const SkPath&); + void flatten(SkWriteBuffer&) const override; + + void next(const SkPoint&, int u, int v, SkPath*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkPath2DPathEffect) + + SkPath fPath; + + typedef Sk2DPathEffect INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkAlphaThresholdFilter.h b/skia/include/effects/SkAlphaThresholdFilter.h new file mode 100644 index 00000000..4a9dc5c8 --- /dev/null +++ b/skia/include/effects/SkAlphaThresholdFilter.h @@ -0,0 +1,32 @@ +/* + * 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 SkAlphaThresholdFilter_DEFINED +#define SkAlphaThresholdFilter_DEFINED + +#include "SkImageFilter.h" + +class SkRegion; + +class SK_API SkAlphaThresholdFilter { +public: + /** + * Creates an image filter that samples a region. If the sample is inside the + * region the alpha of the image is boosted up to a threshold value. If it is + * outside the region then the alpha is decreased to the threshold value. + * The 0,0 point of the region corresponds to the upper left corner of the + * source image. + */ + static sk_sp Make(const SkRegion& region, SkScalar innerMin, + SkScalar outerMax, sk_sp input, + const SkImageFilter::CropRect* cropRect = nullptr); + + + static void RegisterFlattenables(); +}; + +#endif diff --git a/skia/include/effects/SkArithmeticImageFilter.h b/skia/include/effects/SkArithmeticImageFilter.h new file mode 100644 index 00000000..a2587746 --- /dev/null +++ b/skia/include/effects/SkArithmeticImageFilter.h @@ -0,0 +1,35 @@ +/* + * 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 SkArithmeticImageFilter_DEFINED +#define SkArithmeticImageFilter_DEFINED + +#include "SkImageFilter.h" + +struct ArithmeticFPInputs { + ArithmeticFPInputs() { + memset(this, 0, sizeof(*this)); + } + + float k[4]; + bool enforcePMColor; +}; + +class SK_API SkArithmeticImageFilter { +public: + static sk_sp Make(float k1, float k2, float k3, float k4, bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); + + static void RegisterFlattenables(); + +private: + SkArithmeticImageFilter(); // can't instantiate +}; + +#endif diff --git a/skia/include/effects/SkBlurDrawLooper.h b/skia/include/effects/SkBlurDrawLooper.h new file mode 100644 index 00000000..08e77666 --- /dev/null +++ b/skia/include/effects/SkBlurDrawLooper.h @@ -0,0 +1,22 @@ +/* + * 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 SkBlurDrawLooper_DEFINED +#define SkBlurDrawLooper_DEFINED + +#include "SkDrawLooper.h" + +/** + * Draws a shadow of the object (possibly offset), and then draws the original object in + * its original position. + */ +namespace SkBlurDrawLooper { + sk_sp SK_API Make(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy); +}; + +#endif diff --git a/skia/include/effects/SkBlurImageFilter.h b/skia/include/effects/SkBlurImageFilter.h new file mode 100644 index 00000000..2bd9d61a --- /dev/null +++ b/skia/include/effects/SkBlurImageFilter.h @@ -0,0 +1,33 @@ +/* + * 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 SkBlurImageFilter_DEFINED +#define SkBlurImageFilter_DEFINED + +#include "SkImageFilter.h" + +class SK_API SkBlurImageFilter { +public: + /*! \enum TileMode */ + enum TileMode { + kClamp_TileMode = 0, /*!< Clamp to the image's edge pixels. */ + /*!< This re-weights the filter so samples outside have no effect */ + kRepeat_TileMode, /*!< Wrap around to the image's opposite edge. */ + kClampToBlack_TileMode, /*!< Fill with transparent black. */ + kLast_TileMode = kClampToBlack_TileMode, + + // TODO: remove kMax - it is non-standard but Chromium uses it + kMax_TileMode = kClampToBlack_TileMode + }; + + static sk_sp Make(SkScalar sigmaX, SkScalar sigmaY, + sk_sp input, + const SkImageFilter::CropRect* cropRect = nullptr, + TileMode tileMode = TileMode::kClampToBlack_TileMode); +}; + +#endif diff --git a/skia/include/effects/SkBlurMaskFilter.h b/skia/include/effects/SkBlurMaskFilter.h new file mode 100644 index 00000000..86e7d12e --- /dev/null +++ b/skia/include/effects/SkBlurMaskFilter.h @@ -0,0 +1,35 @@ +/* + * 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 SkBlurMaskFilter_DEFINED +#define SkBlurMaskFilter_DEFINED + +// we include this since our callers will need to at least be able to ref/unref +#include "SkMaskFilter.h" +#include "SkRect.h" +#include "SkScalar.h" +#include "SkBlurTypes.h" + +class SkRRect; + +class SK_API SkBlurMaskFilter { +public: +#ifdef SK_SUPPORT_LEGACY_EMBOSSMASKFILTER + /** Create an emboss maskfilter + @param blurSigma standard deviation of the Gaussian blur to apply + before applying lighting (e.g. 3) + @param direction array of 3 scalars [x, y, z] specifying the direction of the light source + @param ambient 0...1 amount of ambient light + @param specular coefficient for specular highlights (e.g. 8) + @return the emboss maskfilter + */ + static sk_sp MakeEmboss(SkScalar blurSigma, const SkScalar direction[3], + SkScalar ambient, SkScalar specular); +#endif +}; + +#endif diff --git a/skia/include/effects/SkColorFilterImageFilter.h b/skia/include/effects/SkColorFilterImageFilter.h new file mode 100644 index 00000000..99be9edd --- /dev/null +++ b/skia/include/effects/SkColorFilterImageFilter.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 SkColorFilterImageFilter_DEFINED +#define SkColorFilterImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkColorFilter.h" + +class SK_API SkColorFilterImageFilter : public SkImageFilter { +public: + static sk_sp Make(sk_sp cf, + sk_sp input, + const CropRect* cropRect = nullptr); + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + bool onIsColorFilterNode(SkColorFilter**) const override; + bool onCanHandleComplexCTM() const override { return true; } + bool affectsTransparentBlack() const override; + +private: + SK_FLATTENABLE_HOOKS(SkColorFilterImageFilter) + + SkColorFilterImageFilter(sk_sp cf, + sk_sp input, + const CropRect* cropRect); + + sk_sp fColorFilter; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkColorMatrix.h b/skia/include/effects/SkColorMatrix.h new file mode 100644 index 00000000..9a03b94f --- /dev/null +++ b/skia/include/effects/SkColorMatrix.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef SkColorMatrix_DEFINED +#define SkColorMatrix_DEFINED + +#include "SkScalar.h" + +class SK_API SkColorMatrix { +public: + enum { + kCount = 20 + }; + SkScalar fMat[kCount]; + + enum Elem { + kR_Scale = 0, + kG_Scale = 6, + kB_Scale = 12, + kA_Scale = 18, + + kR_Trans = 4, + kG_Trans = 9, + kB_Trans = 14, + kA_Trans = 19, + }; + + void setIdentity(); + void setScale(SkScalar rScale, SkScalar gScale, SkScalar bScale, + SkScalar aScale = SK_Scalar1); + void postTranslate(SkScalar rTrans, SkScalar gTrans, SkScalar bTrans, + SkScalar aTrans = 0); + + enum Axis { + kR_Axis = 0, + kG_Axis = 1, + kB_Axis = 2 + }; + void setRotate(Axis, SkScalar degrees); + void setSinCos(Axis, SkScalar sine, SkScalar cosine); + void preRotate(Axis, SkScalar degrees); + void postRotate(Axis, SkScalar degrees); + + void setConcat(const SkColorMatrix& a, const SkColorMatrix& b); + void preConcat(const SkColorMatrix& mat) { this->setConcat(*this, mat); } + void postConcat(const SkColorMatrix& mat) { this->setConcat(mat, *this); } + + void setSaturation(SkScalar sat); + void setRGB2YUV(); + void setYUV2RGB(); + + bool operator==(const SkColorMatrix& other) const { + return 0 == memcmp(fMat, other.fMat, sizeof(fMat)); + } + + bool operator!=(const SkColorMatrix& other) const { return !((*this) == other); } + + static bool NeedsClamping(const SkScalar[20]); + static void SetConcat(SkScalar result[20], const SkScalar outer[20], const SkScalar inner[20]); +}; + +#endif diff --git a/skia/include/effects/SkColorMatrixFilter.h b/skia/include/effects/SkColorMatrixFilter.h new file mode 100644 index 00000000..c2937176 --- /dev/null +++ b/skia/include/effects/SkColorMatrixFilter.h @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#ifndef SkColorMatrixFilter_DEFINED +#define SkColorMatrixFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkColorMatrix.h" + +class SK_API SkColorMatrixFilter : public SkColorFilter { +public: + /** + * Create a colorfilter that multiplies the RGB channels by one color, and + * then adds a second color, pinning the result for each component to + * [0..255]. The alpha components of the mul and add arguments + * are ignored. + */ + static sk_sp MakeLightingFilter(SkColor mul, SkColor add); +}; + +#endif diff --git a/skia/include/effects/SkComposeImageFilter.h b/skia/include/effects/SkComposeImageFilter.h new file mode 100644 index 00000000..ab3ce637 --- /dev/null +++ b/skia/include/effects/SkComposeImageFilter.h @@ -0,0 +1,38 @@ +/* + * 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 SkComposeImageFilter_DEFINED +#define SkComposeImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" + +class SK_API SkComposeImageFilter : public SkImageFilter { +public: + static sk_sp Make(sk_sp outer, sk_sp inner); + + SkRect computeFastBounds(const SkRect& src) const override; + +protected: + explicit SkComposeImageFilter(sk_sp inputs[2]) : INHERITED(inputs, 2, nullptr) { + SkASSERT(inputs[0].get()); + SkASSERT(inputs[1].get()); + } + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkIRect onFilterBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + bool onCanHandleComplexCTM() const override { return true; } + +private: + SK_FLATTENABLE_HOOKS(SkComposeImageFilter) + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkCornerPathEffect.h b/skia/include/effects/SkCornerPathEffect.h new file mode 100644 index 00000000..539453a5 --- /dev/null +++ b/skia/include/effects/SkCornerPathEffect.h @@ -0,0 +1,43 @@ +/* + * 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 SkCornerPathEffect_DEFINED +#define SkCornerPathEffect_DEFINED + +#include "SkFlattenable.h" +#include "SkPathEffect.h" + +/** \class SkCornerPathEffect + + SkCornerPathEffect is a subclass of SkPathEffect that can turn sharp corners + into various treatments (e.g. rounded corners) +*/ +class SK_API SkCornerPathEffect : public SkPathEffect { +public: + /** radius must be > 0 to have an effect. It specifies the distance from each corner + that should be "rounded". + */ + static sk_sp Make(SkScalar radius) { + return radius > 0 ? sk_sp(new SkCornerPathEffect(radius)) : nullptr; + } + +protected: + ~SkCornerPathEffect() override; + + explicit SkCornerPathEffect(SkScalar radius); + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkCornerPathEffect) + + SkScalar fRadius; + + typedef SkPathEffect INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkDashPathEffect.h b/skia/include/effects/SkDashPathEffect.h new file mode 100644 index 00000000..78ddb165 --- /dev/null +++ b/skia/include/effects/SkDashPathEffect.h @@ -0,0 +1,39 @@ +/* + * 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 SkDashPathEffect_DEFINED +#define SkDashPathEffect_DEFINED + +#include "SkPathEffect.h" + +class SK_API SkDashPathEffect { +public: + /** intervals: array containing an even number of entries (>=2), with + the even indices specifying the length of "on" intervals, and the odd + indices specifying the length of "off" intervals. This array will be + copied in Make, and can be disposed of freely after. + count: number of elements in the intervals array + phase: offset into the intervals array (mod the sum of all of the + intervals). + + For example: if intervals[] = {10, 20}, count = 2, and phase = 25, + this will set up a dashed path like so: + 5 pixels off + 10 pixels on + 20 pixels off + 10 pixels on + 20 pixels off + ... + A phase of -5, 25, 55, 85, etc. would all result in the same path, + because the sum of all the intervals is 30. + + Note: only affects stroked paths. + */ + static sk_sp Make(const SkScalar intervals[], int count, SkScalar phase); +}; + +#endif diff --git a/skia/include/effects/SkDiscretePathEffect.h b/skia/include/effects/SkDiscretePathEffect.h new file mode 100644 index 00000000..dffb39e6 --- /dev/null +++ b/skia/include/effects/SkDiscretePathEffect.h @@ -0,0 +1,53 @@ +/* + * 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 SkDiscretePathEffect_DEFINED +#define SkDiscretePathEffect_DEFINED + +#include "SkFlattenable.h" +#include "SkPathEffect.h" + +/** \class SkDiscretePathEffect + + This path effect chops a path into discrete segments, and randomly displaces them. +*/ +class SK_API SkDiscretePathEffect : public SkPathEffect { +public: + /** Break the path into segments of segLength length, and randomly move the endpoints + away from the original path by a maximum of deviation. + Note: works on filled or framed paths + + @param seedAssist This is a caller-supplied seedAssist that modifies + the seed value that is used to randomize the path + segments' endpoints. If not supplied it defaults to 0, + in which case filtering a path multiple times will + result in the same set of segments (this is useful for + testing). If a caller does not want this behaviour + they can pass in a different seedAssist to get a + different set of path segments. + */ + static sk_sp Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist = 0); + +protected: + SkDiscretePathEffect(SkScalar segLength, + SkScalar deviation, + uint32_t seedAssist); + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkDiscretePathEffect) + + SkScalar fSegLength, fPerterb; + + /* Caller-supplied 32 bit seed assist */ + uint32_t fSeedAssist; + + typedef SkPathEffect INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkDisplacementMapEffect.h b/skia/include/effects/SkDisplacementMapEffect.h new file mode 100644 index 00000000..a5fd1bd3 --- /dev/null +++ b/skia/include/effects/SkDisplacementMapEffect.h @@ -0,0 +1,63 @@ +/* + * 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 SkDisplacementMapEffect_DEFINED +#define SkDisplacementMapEffect_DEFINED + +#include "SkImageFilter.h" + +class SK_API SkDisplacementMapEffect : public SkImageFilter { +public: + enum ChannelSelectorType { + kUnknown_ChannelSelectorType, + kR_ChannelSelectorType, + kG_ChannelSelectorType, + kB_ChannelSelectorType, + kA_ChannelSelectorType, + + kLast_ChannelSelectorType = kA_ChannelSelectorType + }; + + ~SkDisplacementMapEffect() override; + + static sk_sp Make(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, + sk_sp displacement, + sk_sp color, + const CropRect* cropRect = nullptr); + + SkRect computeFastBounds(const SkRect& src) const override; + + virtual SkIRect onFilterBounds(const SkIRect& src, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + +protected: + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + + SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, sk_sp inputs[2], + const CropRect* cropRect); + void flatten(SkWriteBuffer&) const override; + +private: + SK_FLATTENABLE_HOOKS(SkDisplacementMapEffect) + + ChannelSelectorType fXChannelSelector; + ChannelSelectorType fYChannelSelector; + SkScalar fScale; + typedef SkImageFilter INHERITED; + const SkImageFilter* getDisplacementInput() const { return getInput(0); } + const SkImageFilter* getColorInput() const { return getInput(1); } +}; + +#endif diff --git a/skia/include/effects/SkDropShadowImageFilter.h b/skia/include/effects/SkDropShadowImageFilter.h new file mode 100644 index 00000000..b28d2444 --- /dev/null +++ b/skia/include/effects/SkDropShadowImageFilter.h @@ -0,0 +1,56 @@ +/* + * 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 SkDropShadowImageFilter_DEFINED +#define SkDropShadowImageFilter_DEFINED + +#include "SkColor.h" +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkScalar.h" + +class SK_API SkDropShadowImageFilter : public SkImageFilter { +public: + enum ShadowMode { + kDrawShadowAndForeground_ShadowMode, + kDrawShadowOnly_ShadowMode, + + kLast_ShadowMode = kDrawShadowOnly_ShadowMode + }; + + static const int kShadowModeCount = kLast_ShadowMode+1; + + static sk_sp Make(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, + SkColor color, ShadowMode shadowMode, + sk_sp input, + const CropRect* cropRect = nullptr); + + SkRect computeFastBounds(const SkRect&) const override; + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + +private: + SK_FLATTENABLE_HOOKS(SkDropShadowImageFilter) + + SkDropShadowImageFilter(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor, + ShadowMode shadowMode, sk_sp input, + const CropRect* cropRect); + + SkScalar fDx, fDy, fSigmaX, fSigmaY; + SkColor fColor; + ShadowMode fShadowMode; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkGradientShader.h b/skia/include/effects/SkGradientShader.h new file mode 100644 index 00000000..3b537a53 --- /dev/null +++ b/skia/include/effects/SkGradientShader.h @@ -0,0 +1,259 @@ +/* + * 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 SkGradientShader_DEFINED +#define SkGradientShader_DEFINED + +#include "SkShader.h" + +/** \class SkGradientShader + + SkGradientShader hosts factories for creating subclasses of SkShader that + render linear and radial gradients. In general, degenerate cases should not + produce surprising results, but there are several types of degeneracies: + + * A linear gradient made from the same two points. + * A radial gradient with a radius of zero. + * A sweep gradient where the start and end angle are the same. + * A two point conical gradient where the two centers and the two radii are + the same. + + For any degenerate gradient with a decal tile mode, it will draw empty since the interpolating + region is zero area and the outer region is discarded by the decal mode. + + For any degenerate gradient with a repeat or mirror tile mode, it will draw a solid color that + is the average gradient color, since infinitely many repetitions of the gradients will fill the + shape. + + For a clamped gradient, every type is well-defined at the limit except for linear gradients. The + radial gradient with zero radius becomes the last color. The sweep gradient draws the sector + from 0 to the provided angle with the first color, with a hardstop switching to the last color. + When the provided angle is 0, this is just the solid last color again. Similarly, the two point + conical gradient becomes a circle filled with the first color, sized to the provided radius, + with a hardstop switching to the last color. When the two radii are both zero, this is just the + solid last color. + + As a linear gradient approaches the degenerate case, its shader will approach the appearance of + two half planes, each filled by the first and last colors of the gradient. The planes will be + oriented perpendicular to the vector between the two defining points of the gradient. However, + once they become the same point, Skia cannot reconstruct what that expected orientation is. To + provide a stable and predictable color in this case, Skia just uses the last color as a solid + fill to be similar to many of the other degenerate gradients' behaviors in clamp mode. +*/ +class SK_API SkGradientShader { +public: + enum Flags { + /** By default gradients will interpolate their colors in unpremul space + * and then premultiply each of the results. By setting this flag, the + * gradients will premultiply their colors first, and then interpolate + * between them. + */ + kInterpolateColorsInPremul_Flag = 1 << 0, + }; + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos 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 count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode) { + return MakeLinear(pts, colors, pos, count, mode, 0, nullptr); + } + + /** Returns a shader that generates a linear gradient between the two specified points. +

+ @param pts The start and end points for the gradient. + @param colors The array[count] of colors, to be distributed between the two points + @param pos 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 count Must be >=2. The number of colors (and pos if not NULL) entries. + @param mode The tiling mode + */ + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeLinear(const SkPoint pts[2], + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkShader::TileMode mode) { + return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, 0, nullptr); + } + + /** 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 pos May be NULL. The 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 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 mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode) { + return MakeRadial(center, radius, colors, pos, count, mode, 0, nullptr); + } + + /** 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 pos May be NULL. The 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 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 mode The tiling mode + */ + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeRadial(const SkPoint& center, SkScalar radius, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, SkShader::TileMode mode) { + return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, + 0, nullptr); + } + + /** + * 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 + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor colors[], const SkScalar pos[], + int count, SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor colors[], const SkScalar pos[], + int count, SkShader::TileMode mode) { + return MakeTwoPointConical(start, startRadius, end, endRadius, colors, pos, count, mode, + 0, nullptr); + } + + /** + * 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 + */ + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkShader::TileMode mode, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, + const SkPoint& end, SkScalar endRadius, + const SkColor4f colors[], + sk_sp colorSpace, const SkScalar pos[], + int count, SkShader::TileMode mode) { + return MakeTwoPointConical(start, startRadius, end, endRadius, colors, + std::move(colorSpace), pos, count, mode, 0, nullptr); + } + + /** Returns a shader that generates a sweep gradient given a center. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + 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 mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + SkShader::TileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count, + uint32_t flags, const SkMatrix* localMatrix) { + return MakeSweep(cx, cy, colors, pos, count, SkShader::kClamp_TileMode, 0, 360, flags, + localMatrix); + } + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor colors[], const SkScalar pos[], int count) { + return MakeSweep(cx, cy, colors, pos, count, 0, nullptr); + } + + /** Returns a shader that generates a sweep gradient given a center. +

+ @param cx The X coordinate of the center of the sweep + @param cx The Y coordinate of the center of the sweep + @param colors The array[count] of colors, to be distributed around the center, within + the gradient angle range. + @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative + position of each corresponding color in the colors array. If this is + NULL, then the colors are distributed evenly within the angular range. + 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 mode Tiling mode: controls drawing outside of the gradient angular range. + @param startAngle Start of the angular range, corresponding to pos == 0. + @param endAngle End of the angular range, corresponding to pos == 1. + */ + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + SkShader::TileMode mode, + SkScalar startAngle, SkScalar endAngle, + uint32_t flags, const SkMatrix* localMatrix); + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count, + uint32_t flags, const SkMatrix* localMatrix) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, + SkShader::kClamp_TileMode, 0, 360, flags, localMatrix); + } + static sk_sp MakeSweep(SkScalar cx, SkScalar cy, + const SkColor4f colors[], sk_sp colorSpace, + const SkScalar pos[], int count) { + return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, nullptr); + } + + static void RegisterFlattenables(); +}; + +#endif diff --git a/skia/include/effects/SkHighContrastFilter.h b/skia/include/effects/SkHighContrastFilter.h new file mode 100644 index 00000000..8d7dd18c --- /dev/null +++ b/skia/include/effects/SkHighContrastFilter.h @@ -0,0 +1,84 @@ +/* +* 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 SkHighContrastFilter_DEFINED +#define SkHighContrastFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkPaint.h" + +/** + * Configuration struct for SkHighContrastFilter. + * + * Provides transformations to improve contrast for users with low vision. + */ +struct SkHighContrastConfig { + enum class InvertStyle { + kNoInvert, + kInvertBrightness, + kInvertLightness, + + kLast = kInvertLightness + }; + + SkHighContrastConfig() { + fGrayscale = false; + fInvertStyle = InvertStyle::kNoInvert; + fContrast = 0.0f; + } + + SkHighContrastConfig(bool grayscale, + InvertStyle invertStyle, + SkScalar contrast) + : fGrayscale(grayscale), + fInvertStyle(invertStyle), + fContrast(contrast) {} + + // Returns true if all of the fields are set within the valid range. + bool isValid() const { + return fInvertStyle >= InvertStyle::kNoInvert && + fInvertStyle <= InvertStyle::kInvertLightness && + fContrast >= -1.0 && + fContrast <= 1.0; + } + + // If true, the color will be converted to grayscale. + bool fGrayscale; + + // Whether to invert brightness, lightness, or neither. + InvertStyle fInvertStyle; + + // After grayscale and inverting, the contrast can be adjusted linearly. + // The valid range is -1.0 through 1.0, where 0.0 is no adjustment. + SkScalar fContrast; +}; + +/** + * Color filter that provides transformations to improve contrast + * for users with low vision. + * + * Applies the following transformations in this order. Each of these + * can be configured using SkHighContrastConfig. + * + * - Conversion to grayscale + * - Color inversion (either in RGB or HSL space) + * - Increasing the resulting contrast. + * + * Calling SkHighContrastFilter::Make will return nullptr if the config is + * not valid, e.g. if you try to call it with a contrast outside the range of + * -1.0 to 1.0. + */ + +class SK_API SkHighContrastFilter { +public: + // Returns the filter, or nullptr if the config is invalid. + static sk_sp Make(const SkHighContrastConfig& config); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/skia/include/effects/SkImageSource.h b/skia/include/effects/SkImageSource.h new file mode 100644 index 00000000..13aede1b --- /dev/null +++ b/skia/include/effects/SkImageSource.h @@ -0,0 +1,51 @@ +/* + * 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 SkImageSource_DEFINED +#define SkImageSource_DEFINED + +#include "SkFlattenable.h" +#include "SkImage.h" +#include "SkImageFilter.h" + +class SK_API SkImageSource : public SkImageFilter { +public: + static sk_sp Make(sk_sp image); + static sk_sp Make(sk_sp image, + const SkRect& srcRect, + const SkRect& dstRect, + SkFilterQuality filterQuality); + + SkRect computeFastBounds(const SkRect& src) const override; + +protected: + void flatten(SkWriteBuffer&) const override; + + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + + SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + +private: + SK_FLATTENABLE_HOOKS(SkImageSource) + + explicit SkImageSource(sk_sp); + SkImageSource(sk_sp, + const SkRect& srcRect, + const SkRect& dstRect, + SkFilterQuality); + + sk_sp fImage; + SkRect fSrcRect, fDstRect; + SkFilterQuality fFilterQuality; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkLayerDrawLooper.h b/skia/include/effects/SkLayerDrawLooper.h new file mode 100644 index 00000000..b18b32c4 --- /dev/null +++ b/skia/include/effects/SkLayerDrawLooper.h @@ -0,0 +1,151 @@ +/* + * 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 SkLayerDrawLooper_DEFINED +#define SkLayerDrawLooper_DEFINED + +#include "SkDrawLooper.h" +#include "SkPaint.h" +#include "SkPoint.h" +#include "SkBlendMode.h" + +class SK_API SkLayerDrawLooper : public SkDrawLooper { +public: + ~SkLayerDrawLooper() override; + + /** + * Bits specifies which aspects of the layer's paint should replace the + * corresponding aspects on the draw's paint. + * kEntirePaint_Bits means use the layer's paint completely. + * 0 means ignore the layer's paint... except for fColorMode, which is + * always applied. + */ + enum Bits { + kStyle_Bit = 1 << 0, //!< use this layer's Style/stroke settings + kTextSkewX_Bit = 1 << 1, //!< use this layer's textskewx + kPathEffect_Bit = 1 << 2, //!< use this layer's patheffect + kMaskFilter_Bit = 1 << 3, //!< use this layer's maskfilter + kShader_Bit = 1 << 4, //!< use this layer's shader + kColorFilter_Bit = 1 << 5, //!< use this layer's colorfilter + kXfermode_Bit = 1 << 6, //!< use this layer's xfermode + + /** + * Use the layer's paint entirely, with these exceptions: + * - We never override the draw's paint's text_encoding, since that is + * used to interpret the text/len parameters in draw[Pos]Text. + * - Color is always computed using the LayerInfo's fColorMode. + */ + kEntirePaint_Bits = -1 + + }; + typedef int32_t BitFlags; + + /** + * Info for how to apply the layer's paint and offset. + * + * fColorMode controls how we compute the final color for the layer: + * The layer's paint's color is treated as the SRC + * The draw's paint's color is treated as the DST + * final-color = Mode(layers-color, draws-color); + * Any SkBlendMode will work. Two common choices are: + * kSrc: to use the layer's color, ignoring the draw's + * kDst: to just keep the draw's color, ignoring the layer's + */ + struct SK_API LayerInfo { + BitFlags fPaintBits; + SkBlendMode fColorMode; + SkVector fOffset; + bool fPostTranslate; //!< applies to fOffset + + /** + * Initial the LayerInfo. Defaults to settings that will draw the + * layer with no changes: e.g. + * fPaintBits == 0 + * fColorMode == kDst_Mode + * fOffset == (0, 0) + */ + LayerInfo(); + }; + + SkDrawLooper::Context* makeContext(SkCanvas*, SkArenaAlloc*) const override; + + bool asABlurShadow(BlurShadowRec* rec) const override; + +protected: + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + + SkLayerDrawLooper(); + + void flatten(SkWriteBuffer&) const override; + +private: + SK_FLATTENABLE_HOOKS(SkLayerDrawLooper) + + struct Rec { + Rec* fNext; + SkPaint fPaint; + LayerInfo fInfo; + }; + Rec* fRecs; + int fCount; + + // state-machine during the init/next cycle + class LayerDrawLooperContext : public SkDrawLooper::Context { + public: + explicit LayerDrawLooperContext(const SkLayerDrawLooper* looper); + + protected: + bool next(SkCanvas*, SkPaint* paint) override; + + private: + Rec* fCurrRec; + + static void ApplyInfo(SkPaint* dst, const SkPaint& src, const LayerInfo&); + }; + + typedef SkDrawLooper INHERITED; + +public: + class SK_API Builder { + public: + Builder(); + ~Builder(); + + /** + * Call for each layer you want to add (from top to bottom). + * This returns a paint you can modify, but that ptr is only valid until + * the next call made to addLayer(). + */ + SkPaint* addLayer(const LayerInfo&); + + /** + * This layer will draw with the original paint, at the specified offset + */ + void addLayer(SkScalar dx, SkScalar dy); + + /** + * This layer will with the original paint and no offset. + */ + void addLayer() { this->addLayer(0, 0); } + + /// Similar to addLayer, but adds a layer to the top. + SkPaint* addLayerOnTop(const LayerInfo&); + + /** + * Pass list of layers on to newly built looper and return it. This will + * also reset the builder, so it can be used to build another looper. + */ + sk_sp detach(); + + private: + Rec* fRecs; + Rec* fTopRec; + int fCount; + }; +}; + +#endif diff --git a/skia/include/effects/SkLightingImageFilter.h b/skia/include/effects/SkLightingImageFilter.h new file mode 100644 index 00000000..ed1341a9 --- /dev/null +++ b/skia/include/effects/SkLightingImageFilter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2012 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 SkLightingImageFilter_DEFINED +#define SkLightingImageFilter_DEFINED + +#include "SkImageFilter.h" +#include "SkColor.h" + + +class SkImageFilterLight; +struct SkPoint3; + +class SK_API SkLightingImageFilter : public SkImageFilter { +public: + static sk_sp MakeDistantLitDiffuse(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakePointLitDiffuse(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakeSpotLitDiffuse(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakeDistantLitSpecular(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakePointLitSpecular(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakeSpotLitSpecular(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, sk_sp input, const CropRect* cropRect = nullptr); + ~SkLightingImageFilter() override; + + static void RegisterFlattenables(); + +protected: + SkLightingImageFilter(sk_sp light, + SkScalar surfaceScale, + sk_sp input, + const CropRect* cropRect); + void flatten(SkWriteBuffer&) const override; + const SkImageFilterLight* light() const { return fLight.get(); } + inline sk_sp refLight() const; + SkScalar surfaceScale() const { return fSurfaceScale; } + bool affectsTransparentBlack() const override { return true; } + +private: + sk_sp fLight; + SkScalar fSurfaceScale; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkLumaColorFilter.h b/skia/include/effects/SkLumaColorFilter.h new file mode 100644 index 00000000..500dae9e --- /dev/null +++ b/skia/include/effects/SkLumaColorFilter.h @@ -0,0 +1,52 @@ +/* + * 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 SkLumaColorFilter_DEFINED +#define SkLumaColorFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkRefCnt.h" + +class SkRasterPipeline; + +/** + * Luminance-to-alpha color filter, as defined in + * http://www.w3.org/TR/SVG/masking.html#Masking + * http://www.w3.org/TR/css-masking/#MaskValues + * + * The resulting color is black with transparency equal to the + * luminance value modulated by alpha: + * + * C' = [ Lum * a, 0, 0, 0 ] + * + */ + + #include "SkFlattenable.h" + +class SK_API SkLumaColorFilter : public SkColorFilter { +public: + static sk_sp Make(); + +#if SK_SUPPORT_GPU + std::unique_ptr asFragmentProcessor( + GrContext*, const GrColorSpaceInfo&) const override; +#endif + +protected: + void flatten(SkWriteBuffer&) const override; + +private: + SK_FLATTENABLE_HOOKS(SkLumaColorFilter) + + SkLumaColorFilter(); + void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const override; + + typedef SkColorFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkMagnifierImageFilter.h b/skia/include/effects/SkMagnifierImageFilter.h new file mode 100644 index 00000000..f060b480 --- /dev/null +++ b/skia/include/effects/SkMagnifierImageFilter.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 SkMagnifierImageFilter_DEFINED +#define SkMagnifierImageFilter_DEFINED + +#include "SkRect.h" +#include "SkImageFilter.h" + +class SK_API SkMagnifierImageFilter : public SkImageFilter { +public: + static sk_sp Make(const SkRect& srcRect, SkScalar inset, + sk_sp input, + const CropRect* cropRect = nullptr); + +protected: + SkMagnifierImageFilter(const SkRect& srcRect, + SkScalar inset, + sk_sp input, + const CropRect* cropRect); + void flatten(SkWriteBuffer&) const override; + + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkMagnifierImageFilter) + + SkRect fSrcRect; + SkScalar fInset; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkMatrixConvolutionImageFilter.h b/skia/include/effects/SkMatrixConvolutionImageFilter.h new file mode 100644 index 00000000..bde0863f --- /dev/null +++ b/skia/include/effects/SkMatrixConvolutionImageFilter.h @@ -0,0 +1,127 @@ +/* + * Copyright 2012 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 SkMatrixConvolutionImageFilter_DEFINED +#define SkMatrixConvolutionImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkScalar.h" +#include "SkSize.h" +#include "SkPoint.h" + +class SkBitmap; + +/*! \class SkMatrixConvolutionImageFilter + Matrix convolution image filter. This filter applies an NxM image + processing kernel to a given input image. This can be used to produce + effects such as sharpening, blurring, edge detection, etc. + */ + +class SK_API SkMatrixConvolutionImageFilter : public SkImageFilter { +public: + /*! \enum TileMode */ + enum TileMode { + kClamp_TileMode = 0, /*!< Clamp to the image's edge pixels. */ + kRepeat_TileMode, /*!< Wrap around to the image's opposite edge. */ + kClampToBlack_TileMode, /*!< Fill with transparent black. */ + kLast_TileMode = kClampToBlack_TileMode, + + // TODO: remove kMax - it is non-standard but used by Chromium! + kMax_TileMode = kClampToBlack_TileMode + }; + + ~SkMatrixConvolutionImageFilter() override; + + /** Construct a matrix convolution image filter. + @param kernelSize The kernel size in pixels, in each dimension (N by M). + @param kernel The image processing kernel. Must contain N * M + elements, in row order. + @param gain A scale factor applied to each pixel after + convolution. This can be used to normalize the + kernel, if it does not sum to 1. + @param bias A bias factor added to each pixel after convolution. + @param kernelOffset An offset applied to each pixel coordinate before + convolution. This can be used to center the kernel + over the image (e.g., a 3x3 kernel should have an + offset of {1, 1}). + @param tileMode How accesses outside the image are treated. (@see + TileMode). + @param convolveAlpha If true, all channels are convolved. If false, + only the RGB channels are convolved, and + alpha is copied from the source image. + @param input The input image filter. If NULL, the src bitmap + passed to filterImage() is used instead. + @param cropRect The rectangle to which the output processing will be limited. + */ + static sk_sp Make(const SkISize& kernelSize, + const SkScalar* kernel, + SkScalar gain, + SkScalar bias, + const SkIPoint& kernelOffset, + TileMode tileMode, + bool convolveAlpha, + sk_sp input, + const CropRect* cropRect = nullptr); + +protected: + SkMatrixConvolutionImageFilter(const SkISize& kernelSize, + const SkScalar* kernel, + SkScalar gain, + SkScalar bias, + const SkIPoint& kernelOffset, + TileMode tileMode, + bool convolveAlpha, + sk_sp input, + const CropRect* cropRect); + void flatten(SkWriteBuffer&) const override; + + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + bool affectsTransparentBlack() const override; + +private: + SK_FLATTENABLE_HOOKS(SkMatrixConvolutionImageFilter) + + SkISize fKernelSize; + SkScalar* fKernel; + SkScalar fGain; + SkScalar fBias; + SkIPoint fKernelOffset; + TileMode fTileMode; + bool fConvolveAlpha; + + template + void filterPixels(const SkBitmap& src, + SkBitmap* result, + SkIVector& offset, + const SkIRect& rect, + const SkIRect& bounds) const; + template + void filterPixels(const SkBitmap& src, + SkBitmap* result, + SkIVector& offset, + const SkIRect& rect, + const SkIRect& bounds) const; + void filterInteriorPixels(const SkBitmap& src, + SkBitmap* result, + SkIVector& offset, + const SkIRect& rect, + const SkIRect& bounds) const; + void filterBorderPixels(const SkBitmap& src, + SkBitmap* result, + SkIVector& offset, + const SkIRect& rect, + const SkIRect& bounds) const; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkMergeImageFilter.h b/skia/include/effects/SkMergeImageFilter.h new file mode 100644 index 00000000..ed665968 --- /dev/null +++ b/skia/include/effects/SkMergeImageFilter.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 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 SkMergeImageFilter_DEFINED +#define SkMergeImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" + +class SK_API SkMergeImageFilter : public SkImageFilter { +public: + static sk_sp Make(sk_sp* const filters, int count, + const CropRect* cropRect = nullptr); + + static sk_sp Make(sk_sp first, sk_sp second, + const CropRect* cropRect = nullptr) { + sk_sp array[] = { + std::move(first), + std::move(second), + }; + return Make(array, 2, cropRect); + } + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + bool onCanHandleComplexCTM() const override { return true; } + +private: + SK_FLATTENABLE_HOOKS(SkMergeImageFilter) + + SkMergeImageFilter(sk_sp* const filters, int count, const CropRect* cropRect); + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkMorphologyImageFilter.h b/skia/include/effects/SkMorphologyImageFilter.h new file mode 100644 index 00000000..5ed624fc --- /dev/null +++ b/skia/include/effects/SkMorphologyImageFilter.h @@ -0,0 +1,99 @@ +/* + * Copyright 2012 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 SkMorphologyImageFilter_DEFINED +#define SkMorphologyImageFilter_DEFINED + +#include "SkColor.h" +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkSize.h" + +/////////////////////////////////////////////////////////////////////////////// +class SK_API SkMorphologyImageFilter : public SkImageFilter { +public: + SkRect computeFastBounds(const SkRect& src) const override; + SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + + /** + * All morphology procs have the same signature: src is the source buffer, dst the + * destination buffer, radius is the morphology radius, width and height are the bounds + * of the destination buffer (in pixels), and srcStride and dstStride are the + * number of pixels per row in each buffer. All buffers are 8888. + */ + + typedef void (*Proc)(const SkPMColor* src, SkPMColor* dst, int radius, + int width, int height, int srcStride, int dstStride); + +protected: + enum Op { + kErode_Op, + kDilate_Op, + }; + + virtual Op op() const = 0; + + SkMorphologyImageFilter(int radiusX, int radiusY, + sk_sp input, + const CropRect* cropRect); + sk_sp onFilterImage(SkSpecialImage* source, + const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + void flatten(SkWriteBuffer&) const override; + + SkISize radius() const { return fRadius; } + +private: + SkISize fRadius; + + typedef SkImageFilter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// +class SK_API SkDilateImageFilter : public SkMorphologyImageFilter { +public: + static sk_sp Make(int radiusX, int radiusY, + sk_sp input, + const CropRect* cropRect = nullptr); + +protected: + Op op() const override { return kDilate_Op; } + +private: + SK_FLATTENABLE_HOOKS(SkDilateImageFilter) + + SkDilateImageFilter(int radiusX, int radiusY, + sk_sp input, + const CropRect* cropRect) + : INHERITED(radiusX, radiusY, input, cropRect) {} + + typedef SkMorphologyImageFilter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// +class SK_API SkErodeImageFilter : public SkMorphologyImageFilter { +public: + static sk_sp Make(int radiusX, int radiusY, + sk_sp input, + const CropRect* cropRect = nullptr); + +protected: + Op op() const override { return kErode_Op; } + +private: + SK_FLATTENABLE_HOOKS(SkErodeImageFilter) + + SkErodeImageFilter(int radiusX, int radiusY, + sk_sp input, const CropRect* cropRect) + : INHERITED(radiusX, radiusY, input, cropRect) {} + + typedef SkMorphologyImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkOffsetImageFilter.h b/skia/include/effects/SkOffsetImageFilter.h new file mode 100644 index 00000000..e9a771cd --- /dev/null +++ b/skia/include/effects/SkOffsetImageFilter.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 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 SkOffsetImageFilter_DEFINED +#define SkOffsetImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkPoint.h" + +class SK_API SkOffsetImageFilter : public SkImageFilter { +public: + static sk_sp Make(SkScalar dx, SkScalar dy, + sk_sp input, + const CropRect* cropRect = nullptr); + + SkRect computeFastBounds(const SkRect& src) const override; + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + +private: + SK_FLATTENABLE_HOOKS(SkOffsetImageFilter) + + SkOffsetImageFilter(SkScalar dx, SkScalar dy, sk_sp input, const CropRect*); + + SkVector fOffset; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkOpPathEffect.h b/skia/include/effects/SkOpPathEffect.h new file mode 100644 index 00000000..87080fc7 --- /dev/null +++ b/skia/include/effects/SkOpPathEffect.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 SkOpPathEffect_DEFINED +#define SkOpPathEffect_DEFINED + +#include "SkPathEffect.h" +#include "SkPaint.h" +#include "SkPathOps.h" + +class SkMergePathEffect { +public: + /* Defers to two other patheffects, and then combines their outputs using the specified op. + * e.g. + * result = output_one op output_two + * + * If either one or two is nullptr, then the original path is passed through to the op. + */ + static sk_sp Make(sk_sp one, sk_sp two, SkPathOp op); +}; + +class SkMatrixPathEffect { +public: + static sk_sp MakeTranslate(SkScalar dx, SkScalar dy); + static sk_sp Make(const SkMatrix&); +}; + +class SkStrokePathEffect { +public: + static sk_sp Make(SkScalar width, SkPaint::Join, SkPaint::Cap, + SkScalar miter = 4); +}; + +#endif diff --git a/skia/include/effects/SkOverdrawColorFilter.h b/skia/include/effects/SkOverdrawColorFilter.h new file mode 100644 index 00000000..cd2c1004 --- /dev/null +++ b/skia/include/effects/SkOverdrawColorFilter.h @@ -0,0 +1,54 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkColorFilter.h" +#include "SkFlattenable.h" + +#ifndef SkOverdrawColorFilter_DEFINED +#define SkOverdrawColorFilter_DEFINED + +/** + * Uses the value in the src alpha channel to set the dst pixel. + * 0 -> fColors[0] + * 1 -> fColors[1] + * ... + * 5 (or larger) -> fColors[5] + * + */ +class SK_API SkOverdrawColorFilter : public SkColorFilter { +public: + static constexpr int kNumColors = 6; + + static sk_sp Make(const SkPMColor colors[kNumColors]) { + return sk_sp(new SkOverdrawColorFilter(colors)); + } + +#if SK_SUPPORT_GPU + std::unique_ptr asFragmentProcessor( + GrContext*, const GrColorSpaceInfo&) const override; +#endif + + static void RegisterFlattenables(); + +protected: + void flatten(SkWriteBuffer& buffer) const override; + +private: + SK_FLATTENABLE_HOOKS(SkOverdrawColorFilter) + + SkOverdrawColorFilter(const SkPMColor colors[kNumColors]) { + memcpy(fColors, colors, kNumColors * sizeof(SkPMColor)); + } + + void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, bool) const override; + + SkPMColor fColors[kNumColors]; + + typedef SkColorFilter INHERITED; +}; + +#endif // SkOverdrawColorFilter_DEFINED diff --git a/skia/include/effects/SkPaintImageFilter.h b/skia/include/effects/SkPaintImageFilter.h new file mode 100644 index 00000000..4b6772eb --- /dev/null +++ b/skia/include/effects/SkPaintImageFilter.h @@ -0,0 +1,46 @@ +/* + * 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 SkPaintImageFilter_DEFINED +#define SkPaintImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkPaint.h" + +class SK_API SkPaintImageFilter : public SkImageFilter { +public: + /** Create a new image filter which fills the given rectangle using the + * given paint. If no rectangle is specified, an output is produced with + * the same bounds as the input primitive (even though the input + * primitive's pixels are not used for processing). + * @param paint Paint to use when filling the rect. + * @param rect Rectangle of output pixels. If NULL or a given crop edge is + * not specified, the source primitive's bounds are used + * instead. + */ + static sk_sp Make(const SkPaint& paint, const CropRect* cropRect = nullptr); + + bool affectsTransparentBlack() const override; + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer* xformer) const override; + +private: + SK_FLATTENABLE_HOOKS(SkPaintImageFilter) + + SkPaintImageFilter(const SkPaint& paint, const CropRect* rect); + + SkPaint fPaint; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkPerlinNoiseShader.h b/skia/include/effects/SkPerlinNoiseShader.h new file mode 100644 index 00000000..dba8c33f --- /dev/null +++ b/skia/include/effects/SkPerlinNoiseShader.h @@ -0,0 +1,60 @@ +/* + * 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 SkPerlinNoiseShader_DEFINED +#define SkPerlinNoiseShader_DEFINED + +#include "SkShader.h" + +/** \class SkPerlinNoiseShader + + SkPerlinNoiseShader creates an image using the Perlin turbulence function. + + It can produce tileable noise if asked to stitch tiles and provided a tile size. + In order to fill a large area with repeating noise, set the stitchTiles flag to + true, and render exactly a single tile of noise. Without this flag, the result + will contain visible seams between tiles. + + The algorithm used is described here : + http://www.w3.org/TR/SVG/filters.html#feTurbulenceElement +*/ +class SK_API SkPerlinNoiseShader { +public: + /** + * This will construct Perlin noise of the given type (Fractal Noise or Turbulence). + * + * Both base frequencies (X and Y) have a usual range of (0..1) and must be non-negative. + * + * The number of octaves provided should be fairly small, with a limit of 255 enforced. + * Each octave doubles the frequency, so 10 octaves would produce noise from + * baseFrequency * 1, * 2, * 4, ..., * 512, which quickly yields insignificantly small + * periods and resembles regular unstructured noise rather than Perlin noise. + * + * If tileSize isn't NULL or an empty size, the tileSize parameter will be used to modify + * the frequencies so that the noise will be tileable for the given tile size. If tileSize + * is NULL or an empty size, the frequencies will be used as is without modification. + */ + static sk_sp MakeFractalNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); + static sk_sp MakeTurbulence(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar seed, + const SkISize* tileSize = nullptr); + /** + * Creates an Improved Perlin Noise shader. The z value is roughly equivalent to the seed of the + * other two types, but minor variations to z will only slightly change the noise. + */ + static sk_sp MakeImprovedNoise(SkScalar baseFrequencyX, SkScalar baseFrequencyY, + int numOctaves, SkScalar z); + + static void RegisterFlattenables(); + +private: + SkPerlinNoiseShader() = delete; +}; + +#endif diff --git a/skia/include/effects/SkPictureImageFilter.h b/skia/include/effects/SkPictureImageFilter.h new file mode 100644 index 00000000..a1a5b383 --- /dev/null +++ b/skia/include/effects/SkPictureImageFilter.h @@ -0,0 +1,57 @@ +/* + * Copyright 2013 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 SkPictureImageFilter_DEFINED +#define SkPictureImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" +#include "SkPicture.h" + +class SK_API SkPictureImageFilter : public SkImageFilter { +public: + /** + * Refs the passed-in picture. + */ + static sk_sp Make(sk_sp picture); + + /** + * Refs the passed-in picture. cropRect can be used to crop or expand the destination rect when + * the picture is drawn. (No scaling is implied by the dest rect; only the CTM is applied.) + */ + static sk_sp Make(sk_sp picture, const SkRect& cropRect); + + +protected: + /* Constructs an SkPictureImageFilter object from an SkReadBuffer. + * Note: If the SkPictureImageFilter object construction requires bitmap + * decoding, the decoder must be set on the SkReadBuffer parameter by calling + * SkReadBuffer::setBitmapDecoder() before calling this constructor. + * @param SkReadBuffer Serialized picture data. + */ + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkPictureImageFilter) + + explicit SkPictureImageFilter(sk_sp picture); + SkPictureImageFilter(sk_sp picture, const SkRect& cropRect, sk_sp); + + sk_sp fPicture; + SkRect fCropRect; + + // Should never be set by a public constructor. This is only used when onMakeColorSpace() + // forces a deferred color space xform. + sk_sp fColorSpace; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkShaderMaskFilter.h b/skia/include/effects/SkShaderMaskFilter.h new file mode 100644 index 00000000..03ec5b88 --- /dev/null +++ b/skia/include/effects/SkShaderMaskFilter.h @@ -0,0 +1,24 @@ +/* + * 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 SkShaderMaskFilter_DEFINED +#define SkShaderMaskFilter_DEFINED + +#include "SkMaskFilter.h" + +class SkShader; + +class SK_API SkShaderMaskFilter { +public: + static sk_sp Make(sk_sp shader); + +private: + static void RegisterFlattenables(); + friend class SkFlattenable; +}; + +#endif diff --git a/skia/include/effects/SkTableColorFilter.h b/skia/include/effects/SkTableColorFilter.h new file mode 100644 index 00000000..69f525a2 --- /dev/null +++ b/skia/include/effects/SkTableColorFilter.h @@ -0,0 +1,42 @@ +/* +* 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 SkTableColorFilter_DEFINED +#define SkTableColorFilter_DEFINED + +#include "SkColorFilter.h" + +class SK_API SkTableColorFilter { +public: + /** + * Create a table colorfilter, copying the table into the filter, and + * applying it to all 4 components. + * a' = table[a]; + * r' = table[r]; + * g' = table[g]; + * b' = table[b]; + * Compoents are operated on in unpremultiplied space. If the incomming + * colors are premultiplied, they are temporarily unpremultiplied, then + * the table is applied, and then the result is remultiplied. + */ + static sk_sp Make(const uint8_t table[256]); + + /** + * Create a table colorfilter, with a different table for each + * component [A, R, G, B]. If a given table is NULL, then it is + * treated as identity, with the component left unchanged. If a table + * is not null, then its contents are copied into the filter. + */ + static sk_sp MakeARGB(const uint8_t tableA[256], + const uint8_t tableR[256], + const uint8_t tableG[256], + const uint8_t tableB[256]); + + static void RegisterFlattenables(); +}; + +#endif diff --git a/skia/include/effects/SkTableMaskFilter.h b/skia/include/effects/SkTableMaskFilter.h new file mode 100644 index 00000000..eb6ccb08 --- /dev/null +++ b/skia/include/effects/SkTableMaskFilter.h @@ -0,0 +1,37 @@ +/* + * 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 SkTableMaskFilter_DEFINED +#define SkTableMaskFilter_DEFINED + +#include "SkMaskFilter.h" +#include "SkScalar.h" + +/** \class SkTableMaskFilter + + Applies a table lookup on each of the alpha values in the mask. + Helper methods create some common tables (e.g. gamma, clipping) + */ +class SK_API SkTableMaskFilter { +public: + /** Utility that sets the gamma table + */ + static void MakeGammaTable(uint8_t table[256], SkScalar gamma); + + /** Utility that creates a clipping table: clamps values below min to 0 + and above max to 255, and rescales the remaining into 0..255 + */ + static void MakeClipTable(uint8_t table[256], uint8_t min, uint8_t max); + + static SkMaskFilter* Create(const uint8_t table[256]); + static SkMaskFilter* CreateGamma(SkScalar gamma); + static SkMaskFilter* CreateClip(uint8_t min, uint8_t max); + + SkTableMaskFilter() = delete; +}; + +#endif diff --git a/skia/include/effects/SkTileImageFilter.h b/skia/include/effects/SkTileImageFilter.h new file mode 100644 index 00000000..bcd2f5bb --- /dev/null +++ b/skia/include/effects/SkTileImageFilter.h @@ -0,0 +1,50 @@ +/* + * 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 SkTileImageFilter_DEFINED +#define SkTileImageFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkImageFilter.h" + +class SK_API SkTileImageFilter : public SkImageFilter { +public: + /** Create a tile image filter + @param src Defines the pixels to tile + @param dst Defines the pixels where tiles are drawn + @param input Input from which the subregion defined by srcRect will be tiled + */ + static sk_sp Make(const SkRect& src, + const SkRect& dst, + sk_sp input); + + SkIRect onFilterBounds(const SkIRect& src, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix& ctm, + MapDirection, const SkIRect* inputRect) const override; + SkRect computeFastBounds(const SkRect& src) const override; + +protected: + void flatten(SkWriteBuffer& buffer) const override; + + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + sk_sp onMakeColorSpace(SkColorSpaceXformer*) const override; + +private: + SK_FLATTENABLE_HOOKS(SkTileImageFilter) + + SkTileImageFilter(const SkRect& srcRect, const SkRect& dstRect, sk_sp input) + : INHERITED(&input, 1, nullptr), fSrcRect(srcRect), fDstRect(dstRect) {} + + SkRect fSrcRect; + SkRect fDstRect; + + typedef SkImageFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkToSRGBColorFilter.h b/skia/include/effects/SkToSRGBColorFilter.h new file mode 100644 index 00000000..f577fb95 --- /dev/null +++ b/skia/include/effects/SkToSRGBColorFilter.h @@ -0,0 +1,43 @@ +/* + * 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 SkToSRGBColorFilter_DEFINED +#define SkToSRGBColorFilter_DEFINED + +#include "SkFlattenable.h" +#include "SkColorFilter.h" +#include "SkRefCnt.h" + +class SkColorSpace; +class SkRasterPipeline; + +/** + * Color filter that converts from supplied color space to sRGB (both gamut and transfer function). + */ +class SK_API SkToSRGBColorFilter : public SkColorFilter { +public: + static sk_sp Make(sk_sp srcColorSpace); + +#if SK_SUPPORT_GPU + std::unique_ptr asFragmentProcessor( + GrContext*, const GrColorSpaceInfo&) const override; +#endif + +private: + SK_FLATTENABLE_HOOKS(SkToSRGBColorFilter) + + void flatten(SkWriteBuffer&) const override; + SkToSRGBColorFilter(sk_sp); + void onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*, + bool shaderIsOpaque) const override; + + sk_sp fSrcColorSpace; + + typedef SkColorFilter INHERITED; +}; + +#endif diff --git a/skia/include/effects/SkTrimPathEffect.h b/skia/include/effects/SkTrimPathEffect.h new file mode 100644 index 00000000..e96b94f8 --- /dev/null +++ b/skia/include/effects/SkTrimPathEffect.h @@ -0,0 +1,41 @@ +/* + * 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 SkTrimPathEffect_DEFINED +#define SkTrimPathEffect_DEFINED + +#include "SkPathEffect.h" + +class SK_API SkTrimPathEffect { +public: + enum class Mode { + kNormal, // return the subset path [start,stop] + kInverted, // return the complement/subset paths [0,start] + [stop,1] + }; + + /** + * Take start and stop "t" values (values between 0...1), and return a path that is that + * subset of the original path. + * + * e.g. + * Make(0.5, 1.0) --> return the 2nd half of the path + * Make(0.33333, 0.66667) --> return the middle third of the path + * + * The trim values apply to the entire path, so if it contains several contours, all of them + * are including in the calculation. + * + * startT and stopT must be 0..1 inclusive. If they are outside of that interval, they will + * be pinned to the nearest legal value. If either is NaN, null will be returned. + * + * Note: for Mode::kNormal, this will return one (logical) segment (even if it is spread + * across multiple contours). For Mode::kInverted, this will return 2 logical + * segments: 0...stopT and startT...1 + */ + static sk_sp Make(SkScalar startT, SkScalar stopT, Mode = Mode::kNormal); +}; + +#endif diff --git a/skia/include/effects/SkXfermodeImageFilter.h b/skia/include/effects/SkXfermodeImageFilter.h new file mode 100644 index 00000000..8ccceb2e --- /dev/null +++ b/skia/include/effects/SkXfermodeImageFilter.h @@ -0,0 +1,34 @@ +/* + * Copyright 2013 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 SkXfermodeImageFilter_DEFINED +#define SkXfermodeImageFilter_DEFINED + +#include "SkArithmeticImageFilter.h" +#include "SkBlendMode.h" +#include "SkImageFilter.h" + +/** + * This filter takes a SkBlendMode, and uses it to composite the foreground over the background. + * If foreground or background is NULL, the input bitmap (src) is used instead. + */ +class SK_API SkXfermodeImageFilter { +public: + static sk_sp Make(SkBlendMode, sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); + static sk_sp Make(SkBlendMode mode, sk_sp background) { + return Make(mode, std::move(background), nullptr, nullptr); + } + + static void RegisterFlattenables(); + +private: + SkXfermodeImageFilter(); // can't instantiate +}; + +#endif diff --git a/skia/include/encode/SkEncoder.h b/skia/include/encode/SkEncoder.h new file mode 100644 index 00000000..1b4f5594 --- /dev/null +++ b/skia/include/encode/SkEncoder.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 SkEncoder_DEFINED +#define SkEncoder_DEFINED + +#include "../private/SkNoncopyable.h" +#include "../private/SkTemplates.h" +#include "SkPixmap.h" + +class SK_API SkEncoder : SkNoncopyable { +public: + + /** + * Encode |numRows| rows of input. If the caller requests more rows than are remaining + * in the src, this will encode all of the remaining rows. |numRows| must be greater + * than zero. + */ + bool encodeRows(int numRows); + + virtual ~SkEncoder() {} + +protected: + + virtual bool onEncodeRows(int numRows) = 0; + + SkEncoder(const SkPixmap& src, size_t storageBytes) + : fSrc(src) + , fCurrRow(0) + , fStorage(storageBytes) + {} + + const SkPixmap& fSrc; + int fCurrRow; + SkAutoTMalloc fStorage; +}; + +#endif diff --git a/skia/include/encode/SkJpegEncoder.h b/skia/include/encode/SkJpegEncoder.h new file mode 100644 index 00000000..5e657a5b --- /dev/null +++ b/skia/include/encode/SkJpegEncoder.h @@ -0,0 +1,97 @@ +/* + * 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 SkJpegEncoder_DEFINED +#define SkJpegEncoder_DEFINED + +#include "SkEncoder.h" + +class SkJpegEncoderMgr; +class SkWStream; + +class SK_API SkJpegEncoder : public SkEncoder { +public: + + enum class AlphaOption { + kIgnore, + kBlendOnBlack, + }; + + enum class Downsample { + /** + * Reduction by a factor of two in both the horizontal and vertical directions. + */ + k420, + + /** + * Reduction by a factor of two in the horizontal direction. + */ + k422, + + /** + * No downsampling. + */ + k444, + }; + + struct Options { + /** + * |fQuality| must be in [0, 100] where 0 corresponds to the lowest quality. + */ + int fQuality = 100; + + /** + * Choose the downsampling factor for the U and V components. This is only + * meaningful if the |src| is not kGray, since kGray will not be encoded as YUV. + * + * Our default value matches the libjpeg-turbo default. + */ + Downsample fDownsample = Downsample::k420; + + /** + * Jpegs must be opaque. This instructs the encoder on how to handle input + * images with alpha. + * + * The default is to ignore the alpha channel and treat the image as opaque. + * Another option is to blend the pixels onto a black background before encoding. + * In the second case, the encoder supports linear or legacy blending. + */ + AlphaOption fAlphaOption = AlphaOption::kIgnore; + }; + + /** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + static bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + + /** + * Create a jpeg encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ + static std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, + const Options& options); + + ~SkJpegEncoder() override; + +protected: + bool onEncodeRows(int numRows) override; + +private: + SkJpegEncoder(std::unique_ptr, const SkPixmap& src); + + std::unique_ptr fEncoderMgr; + typedef SkEncoder INHERITED; +}; + +#endif diff --git a/skia/include/encode/SkPngEncoder.h b/skia/include/encode/SkPngEncoder.h new file mode 100644 index 00000000..2e1f7d73 --- /dev/null +++ b/skia/include/encode/SkPngEncoder.h @@ -0,0 +1,99 @@ +/* + * 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 SkPngEncoder_DEFINED +#define SkPngEncoder_DEFINED + +#include "SkEncoder.h" +#include "SkDataTable.h" + +class SkPngEncoderMgr; +class SkWStream; + +class SK_API SkPngEncoder : public SkEncoder { +public: + + enum class FilterFlag : int { + kZero = 0x00, + kNone = 0x08, + kSub = 0x10, + kUp = 0x20, + kAvg = 0x40, + kPaeth = 0x80, + kAll = kNone | kSub | kUp | kAvg | kPaeth, + }; + + struct Options { + /** + * Selects which filtering strategies to use. + * + * If a single filter is chosen, libpng will use that filter for every row. + * + * If multiple filters are chosen, libpng will use a heuristic to guess which filter + * will encode smallest, then apply that filter. This happens on a per row basis, + * different rows can use different filters. + * + * Using a single filter (or less filters) is typically faster. Trying all of the + * filters may help minimize the output file size. + * + * Our default value matches libpng's default. + */ + FilterFlag fFilterFlags = FilterFlag::kAll; + + /** + * Must be in [0, 9] where 9 corresponds to maximal compression. This value is passed + * directly to zlib. 0 is a special case to skip zlib entirely, creating dramatically + * larger pngs. + * + * Our default value matches libpng's default. + */ + int fZLibLevel = 6; + + /** + * Represents comments in the tEXt ancillary chunk of the png. + * The 2i-th entry is the keyword for the i-th comment, + * and the (2i + 1)-th entry is the text for the i-th comment. + */ + sk_sp fComments; + }; + + /** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + static bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); + + /** + * Create a png encoder that will encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * |dst| is unowned but must remain valid for the lifetime of the object. + * + * This returns nullptr on an invalid or unsupported |src|. + */ + static std::unique_ptr Make(SkWStream* dst, const SkPixmap& src, + const Options& options); + + ~SkPngEncoder() override; + +protected: + bool onEncodeRows(int numRows) override; + + SkPngEncoder(std::unique_ptr, const SkPixmap& src); + + std::unique_ptr fEncoderMgr; + typedef SkEncoder INHERITED; +}; + +static inline SkPngEncoder::FilterFlag operator|(SkPngEncoder::FilterFlag x, + SkPngEncoder::FilterFlag y) { + return (SkPngEncoder::FilterFlag)((int)x | (int)y); +} + +#endif diff --git a/skia/include/encode/SkWebpEncoder.h b/skia/include/encode/SkWebpEncoder.h new file mode 100644 index 00000000..8d5f4a6c --- /dev/null +++ b/skia/include/encode/SkWebpEncoder.h @@ -0,0 +1,48 @@ +/* + * 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 SkWebpEncoder_DEFINED +#define SkWebpEncoder_DEFINED + +#include "SkEncoder.h" + +class SkWStream; + +namespace SkWebpEncoder { + + enum class Compression { + kLossy, + kLossless, + }; + + struct SK_API Options { + /** + * |fCompression| determines whether we will use webp lossy or lossless compression. + * + * |fQuality| must be in [0.0f, 100.0f]. + * If |fCompression| is kLossy, |fQuality| corresponds to the visual quality of the + * encoding. Decreasing the quality will result in a smaller encoded image. + * If |fCompression| is kLossless, |fQuality| corresponds to the amount of effort + * put into the encoding. Lower values will compress faster into larger files, + * while larger values will compress slower into smaller files. + * + * This scheme is designed to match the libwebp API. + */ + Compression fCompression = Compression::kLossy; + float fQuality = 100.0f; + }; + + /** + * Encode the |src| pixels to the |dst| stream. + * |options| may be used to control the encoding behavior. + * + * Returns true on success. Returns false on an invalid or unsupported |src|. + */ + SK_API bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options); +}; + +#endif diff --git a/skia/include/gpu/GrBackendDrawableInfo.h b/skia/include/gpu/GrBackendDrawableInfo.h new file mode 100644 index 00000000..e25b954b --- /dev/null +++ b/skia/include/gpu/GrBackendDrawableInfo.h @@ -0,0 +1,44 @@ +/* + * 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 GrBackendDrawableInfo_DEFINED +#define GrBackendDrawableInfo_DEFINED + +#include "GrTypes.h" + +#include "vk/GrVkTypes.h" + +class SK_API GrBackendDrawableInfo { +public: + // Creates an invalid backend drawable info. + GrBackendDrawableInfo() : fIsValid(false) {} + + GrBackendDrawableInfo(const GrVkDrawableInfo& info) + : fIsValid(true) + , fBackend(GrBackendApi::kVulkan) + , fVkInfo(info) {} + + // Returns true if the backend texture has been initialized. + bool isValid() const { return fIsValid; } + + GrBackendApi backend() const { return fBackend; } + + bool getVkDrawableInfo(GrVkDrawableInfo* outInfo) const { + if (this->isValid() && GrBackendApi::kVulkan == fBackend) { + *outInfo = fVkInfo; + return true; + } + return false; + } + +private: + bool fIsValid; + GrBackendApi fBackend; + GrVkDrawableInfo fVkInfo; +}; + +#endif diff --git a/skia/include/gpu/GrBackendSemaphore.h b/skia/include/gpu/GrBackendSemaphore.h new file mode 100644 index 00000000..bf493565 --- /dev/null +++ b/skia/include/gpu/GrBackendSemaphore.h @@ -0,0 +1,66 @@ +/* + * 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 GrBackendSemaphore_DEFINED +#define GrBackendSemaphore_DEFINED + +#include "GrTypes.h" + +#include "gl/GrGLTypes.h" +#include "vk/GrVkTypes.h" + +/** + * Wrapper class for passing into and receiving data from Ganesh about a backend semaphore object. + */ +class GrBackendSemaphore { +public: + // For convenience we just set the backend here to OpenGL. The GrBackendSemaphore cannot be used + // until either initGL or initVulkan are called which will set the appropriate GrBackend. + GrBackendSemaphore() : fBackend(GrBackendApi::kOpenGL), fGLSync(0), fIsInitialized(false) {} + + void initGL(GrGLsync sync) { + fBackend = GrBackendApi::kOpenGL; + fGLSync = sync; + fIsInitialized = true; + } + + void initVulkan(VkSemaphore semaphore) { + fBackend = GrBackendApi::kVulkan; + fVkSemaphore = semaphore; +#ifdef SK_VULKAN + fIsInitialized = true; +#else + fIsInitialized = false; +#endif + } + + bool isInitialized() const { return fIsInitialized; } + + GrGLsync glSync() const { + if (!fIsInitialized || GrBackendApi::kOpenGL != fBackend) { + return 0; + } + return fGLSync; + } + + VkSemaphore vkSemaphore() const { + if (!fIsInitialized || GrBackendApi::kVulkan != fBackend) { + return VK_NULL_HANDLE; + } + return fVkSemaphore; + } + +private: + GrBackendApi fBackend; + union { + GrGLsync fGLSync; + VkSemaphore fVkSemaphore; + }; + bool fIsInitialized; +}; + +#endif diff --git a/skia/include/gpu/GrBackendSurface.h b/skia/include/gpu/GrBackendSurface.h new file mode 100644 index 00000000..1de6fb04 --- /dev/null +++ b/skia/include/gpu/GrBackendSurface.h @@ -0,0 +1,367 @@ +/* + * 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 GrBackendSurface_DEFINED +#define GrBackendSurface_DEFINED + +#include "GrTypes.h" +#include "gl/GrGLTypes.h" +#include "mock/GrMockTypes.h" +#include "vk/GrVkTypes.h" +#include "../private/GrVkTypesPriv.h" + +class GrVkImageLayout; + +#ifdef SK_METAL +#include "mtl/GrMtlTypes.h" +#endif + +#if !SK_SUPPORT_GPU + +// SkSurface and SkImage rely on a minimal version of these always being available +class SK_API GrBackendTexture { +public: + GrBackendTexture() {} + + bool isValid() const { return false; } +}; + +class SK_API GrBackendRenderTarget { +public: + GrBackendRenderTarget() {} + + bool isValid() const { return false; } +}; +#else + +class SK_API GrBackendFormat { +public: + // Creates an invalid backend format. + GrBackendFormat() : fValid(false) {} + + static GrBackendFormat MakeGL(GrGLenum format, GrGLenum target) { + return GrBackendFormat(format, target); + } + + static GrBackendFormat MakeVk(VkFormat format) { + return GrBackendFormat(format); + } + +#ifdef SK_METAL + static GrBackendFormat MakeMtl(GrMTLPixelFormat format) { + return GrBackendFormat(format); + } +#endif + + static GrBackendFormat MakeMock(GrPixelConfig config) { + return GrBackendFormat(config); + } + + GrBackendApi backend() const { return fBackend; } + GrTextureType textureType() const { return fTextureType; } + + // If the backend API is GL, these return a pointer to the format and target. Otherwise + // it returns nullptr. + const GrGLenum* getGLFormat() const; + const GrGLenum* getGLTarget() const; + + // If the backend API is Vulkan, this returns a pointer to a VkFormat. Otherwise + // it returns nullptr + const VkFormat* getVkFormat() const; + +#ifdef SK_METAL + // If the backend API is Metal, this returns a pointer to a GrMTLPixelFormat. Otherwise + // it returns nullptr + const GrMTLPixelFormat* getMtlFormat() const; +#endif + + // If the backend API is Mock, this returns a pointer to a GrPixelConfig. Otherwise + // it returns nullptr. + const GrPixelConfig* getMockFormat() const; + + // If possible, copies the GrBackendFormat and forces the texture type to be Texture2D + GrBackendFormat makeTexture2D() const; + + // Returns true if the backend format has been initialized. + bool isValid() const { return fValid; } + +private: + GrBackendFormat(GrGLenum format, GrGLenum target); + + GrBackendFormat(const VkFormat vkFormat); + +#ifdef SK_METAL + GrBackendFormat(const GrMTLPixelFormat mtlFormat); +#endif + + GrBackendFormat(const GrPixelConfig config); + + GrBackendApi fBackend; + bool fValid; + + union { + GrGLenum fGLFormat; // the sized, internal format of the GL resource + VkFormat fVkFormat; +#ifdef SK_METAL + GrMTLPixelFormat fMtlFormat; +#endif + GrPixelConfig fMockFormat; + }; + GrTextureType fTextureType; +}; + +class SK_API GrBackendTexture { +public: + // Creates an invalid backend texture. + GrBackendTexture() : fIsValid(false) {} + + // The GrGLTextureInfo must have a valid fFormat. + GrBackendTexture(int width, + int height, + GrMipMapped, + const GrGLTextureInfo& glInfo); + + GrBackendTexture(int width, + int height, + const GrVkImageInfo& vkInfo); + +#ifdef SK_METAL + GrBackendTexture(int width, + int height, + GrMipMapped, + const GrMtlTextureInfo& mtlInfo); +#endif + + GrBackendTexture(int width, + int height, + GrMipMapped, + const GrMockTextureInfo& mockInfo); + + GrBackendTexture(const GrBackendTexture& that); + + ~GrBackendTexture(); + + GrBackendTexture& operator=(const GrBackendTexture& that); + + int width() const { return fWidth; } + int height() const { return fHeight; } + bool hasMipMaps() const { return GrMipMapped::kYes == fMipMapped; } + GrBackendApi backend() const {return fBackend; } + + // If the backend API is GL, copies a snapshot of the GrGLTextureInfo struct into the passed in + // pointer and returns true. Otherwise returns false if the backend API is not GL. + bool getGLTextureInfo(GrGLTextureInfo*) const; + + // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed + // in pointer and returns true. This snapshot will set the fImageLayout to the current layout + // state. Otherwise returns false if the backend API is not Vulkan. + bool getVkImageInfo(GrVkImageInfo*) const; + + // Anytime the client changes the VkImageLayout of the VkImage captured by this + // GrBackendTexture, they must call this function to notify Skia of the changed layout. + void setVkImageLayout(VkImageLayout); + +#ifdef SK_METAL + // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Metal. + bool getMtlTextureInfo(GrMtlTextureInfo*) const; +#endif + + // If the backend API is Mock, copies a snapshot of the GrMockTextureInfo struct into the passed + // in pointer and returns true. Otherwise returns false if the backend API is not Mock. + bool getMockTextureInfo(GrMockTextureInfo*) const; + + // Returns true if the backend texture has been initialized. + bool isValid() const { return fIsValid; } + +#if GR_TEST_UTILS + // We can remove the pixelConfig getter and setter once we remove the GrPixelConfig from the + // GrBackendTexture and plumb the GrPixelconfig manually throughout our code (or remove all use + // of GrPixelConfig in general). + GrPixelConfig pixelConfig() const { return fConfig; } + void setPixelConfig(GrPixelConfig config) { fConfig = config; } + + static bool TestingOnly_Equals(const GrBackendTexture& , const GrBackendTexture&); +#endif + +private: + // Friending for access to the GrPixelConfig + friend class SkImage; + friend class SkImage_Gpu; + friend class SkImage_GpuBase; + friend class SkImage_GpuYUVA; + friend class SkPromiseImageHelper; + friend class SkSurface; + friend class GrAHardwareBufferImageGenerator; + friend class GrBackendTextureImageGenerator; + friend class GrProxyProvider; + friend class GrGpu; + friend class GrGLGpu; + friend class GrVkGpu; + friend class GrMtlGpu; + friend class PromiseImageHelper; + + GrPixelConfig config() const { return fConfig; } + + // Requires friending of GrVkGpu (done above already) + sk_sp getGrVkImageLayout() const; + + friend class GrVkTexture; +#ifdef SK_VULKAN + GrBackendTexture(int width, + int height, + const GrVkImageInfo& vkInfo, + sk_sp layout); +#endif + + // Free and release and resources being held by the GrBackendTexture. + void cleanup(); + + bool fIsValid; + int fWidth; // getGrVkImageLayout() const; + + friend class GrVkRenderTarget; + GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo, + sk_sp layout); + + // Free and release and resources being held by the GrBackendTexture. + void cleanup(); + + bool fIsValid; + int fWidth; //= kFirstAdvancedGrBlendEquation + && equation != kIllegal_GrBlendEquation; +} + +static constexpr bool GrBlendModifiesDst(GrBlendEquation equation, GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff) { + return (kAdd_GrBlendEquation != equation && kReverseSubtract_GrBlendEquation != equation) || + kZero_GrBlendCoeff != srcCoeff || kOne_GrBlendCoeff != dstCoeff; +} + +/** + * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp) + * + * For "add" and "reverse subtract" the blend equation with f=coverage is: + * + * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D + * = f * S * srcCoeff + D * (f * dstCoeff + (1 - f)) + * + * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the + * following relationship holds: + * + * (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f)) + * + * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.) + * + * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff + * does not reference S). For the dst term, this will work as long as the following is true: + *| + * dstCoeff' == f * dstCoeff + (1 - f) + * dstCoeff' == 1 - f * (1 - dstCoeff) + * + * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in + * dstCoeff references S. + * + * Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src + * color so folding in coverage is allowed. + */ +static constexpr bool GrBlendAllowsCoverageAsAlpha(GrBlendEquation equation, + GrBlendCoeff srcCoeff, + GrBlendCoeff dstCoeff) { + return GrBlendEquationIsAdvanced(equation) || + !GrBlendModifiesDst(equation, srcCoeff, dstCoeff) || + ((kAdd_GrBlendEquation == equation || kReverseSubtract_GrBlendEquation == equation) && + !GrBlendCoeffRefsSrc(srcCoeff) && + (kOne_GrBlendCoeff == dstCoeff || kISC_GrBlendCoeff == dstCoeff || + kISA_GrBlendCoeff == dstCoeff)); +} + +#endif diff --git a/skia/include/gpu/GrConfig.h b/skia/include/gpu/GrConfig.h new file mode 100644 index 00000000..e0349685 --- /dev/null +++ b/skia/include/gpu/GrConfig.h @@ -0,0 +1,176 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrConfig_DEFINED +#define GrConfig_DEFINED + +#include "SkTypes.h" + +/////////////////////////////////////////////////////////////////////////////// +// preconfig section: +// +// All the work before including GrUserConfig.h should center around guessing +// what platform we're on, and defining low-level symbols based on that. +// +// A build environment may have already defined symbols, so we first check +// for that +// + +// hack to ensure we know what sort of Apple platform we're on +#if defined(__APPLE_CPP__) || defined(__APPLE_CC__) + #include +#endif + +/** + * Gr defines are set to 0 or 1, rather than being undefined or defined + */ + +#if !defined(GR_CACHE_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #define GR_CACHE_STATS 1 + #else + #define GR_CACHE_STATS 0 + #endif +#endif + +#if !defined(GR_GPU_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #define GR_GPU_STATS 1 + #else + #define GR_GPU_STATS 0 + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +#if defined(SK_BUILD_FOR_WIN) +// VC8 doesn't support stdint.h, so we define those types here. +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* + * Include stdint.h with defines that trigger declaration of C99 limit/const + * macros here before anyone else has a chance to include stdint.h without + * these. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// postconfig section: +// + +/** + * GR_STRING makes a string of X where X is expanded before conversion to a string + * if X itself contains macros. + */ +#define GR_STRING(X) GR_STRING_IMPL(X) +#define GR_STRING_IMPL(X) #X + +/** + * GR_CONCAT concatenates X and Y where each is expanded before + * contanenation if either contains macros. + */ +#define GR_CONCAT(X,Y) GR_CONCAT_IMPL(X,Y) +#define GR_CONCAT_IMPL(X,Y) X##Y + +/** + * Creates a string of the form "() : " + */ +#define GR_FILE_AND_LINE_STR __FILE__ "(" GR_STRING(__LINE__) ") : " + +/** + * Compilers have different ways of issuing warnings. This macro + * attempts to abstract them, but may need to be specialized for your + * particular compiler. + * To insert compiler warnings use "#pragma message GR_WARN()" + */ +#if defined(_MSC_VER) + #define GR_WARN(MSG) (GR_FILE_AND_LINE_STR "WARNING: " MSG) +#else//__GNUC__ - may need other defines for different compilers + #define GR_WARN(MSG) ("WARNING: " MSG) +#endif + +/** + * GR_ALWAYSBREAK is an unconditional break in all builds. + */ +#if !defined(GR_ALWAYSBREAK) + #if defined(SK_BUILD_FOR_WIN) + #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); __debugbreak() + #else + // TODO: do other platforms really not have continuable breakpoints? + // sign extend for 64bit architectures to be sure this is + // in the high address range + #define GR_ALWAYSBREAK SkNO_RETURN_HINT(); *((int*)(int64_t)(int32_t)0xbeefcafe) = 0; + #endif +#endif + +/** + * GR_DEBUGBREAK is an unconditional break in debug builds. + */ +#if !defined(GR_DEBUGBREAK) + #ifdef SK_DEBUG + #define GR_DEBUGBREAK GR_ALWAYSBREAK + #else + #define GR_DEBUGBREAK + #endif +#endif + +/** + * GR_ALWAYSASSERT is an assertion in all builds. + */ +#if !defined(GR_ALWAYSASSERT) + #define GR_ALWAYSASSERT(COND) \ + do { \ + if (!(COND)) { \ + SkDebugf("%s %s failed\n", GR_FILE_AND_LINE_STR, #COND); \ + GR_ALWAYSBREAK; \ + } \ + } while (false) +#endif + +/** + * GR_DEBUGASSERT is an assertion in debug builds only. + */ +#if !defined(GR_DEBUGASSERT) + #ifdef SK_DEBUG + #define GR_DEBUGASSERT(COND) GR_ALWAYSASSERT(COND) + #else + #define GR_DEBUGASSERT(COND) + #endif +#endif + +/** + * Prettier forms of the above macros. + */ +#define GrAlwaysAssert(COND) GR_ALWAYSASSERT(COND) + +/** + * GR_STATIC_ASSERT is a compile time assertion. Depending on the platform + * it may print the message in the compiler log. Obviously, the condition must + * be evaluatable at compile time. + */ +#define GR_STATIC_ASSERT(CONDITION) static_assert(CONDITION, "bug") + +#endif diff --git a/skia/include/gpu/GrContext.h b/skia/include/gpu/GrContext.h new file mode 100644 index 00000000..84101a81 --- /dev/null +++ b/skia/include/gpu/GrContext.h @@ -0,0 +1,436 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrContext_DEFINED +#define GrContext_DEFINED + +#include "SkMatrix.h" +#include "SkPathEffect.h" +#include "SkTypes.h" +#include "../private/GrAuditTrail.h" +#include "../private/GrSingleOwner.h" +#include "../private/GrSkSLFPFactoryCache.h" +#include "GrContextOptions.h" + +// We shouldn't need this but currently Android is relying on this being include transitively. +#include "SkUnPreMultiply.h" + +class GrAtlasManager; +class GrBackendFormat; +class GrBackendSemaphore; +class GrCaps; +class GrContextPriv; +class GrContextThreadSafeProxy; +class GrContextThreadSafeProxyPriv; +class GrDrawingManager; +class GrFragmentProcessor; +struct GrGLInterface; +class GrGlyphCache; +class GrGpu; +struct GrMockOptions; +class GrOpMemoryPool; +class GrPath; +class GrProxyProvider; +class GrRenderTargetContext; +class GrResourceCache; +class GrResourceProvider; +class GrSamplerState; +class GrSurfaceProxy; +class GrSwizzle; +class GrTextBlobCache; +class GrTextContext; +class GrTextureProxy; +struct GrVkBackendContext; + +class SkImage; +class SkSurfaceCharacterization; +class SkSurfaceProps; +class SkTaskGroup; +class SkTraceMemoryDump; + +class SK_API GrContext : public SkRefCnt { +public: + /** + * Creates a GrContext for a backend context. If no GrGLInterface is provided then the result of + * GrGLMakeNativeInterface() is used if it succeeds. + */ + static sk_sp MakeGL(sk_sp, const GrContextOptions&); + static sk_sp MakeGL(sk_sp); + static sk_sp MakeGL(const GrContextOptions&); + static sk_sp MakeGL(); + + static sk_sp MakeVulkan(const GrVkBackendContext&, const GrContextOptions&); + static sk_sp MakeVulkan(const GrVkBackendContext&); + +#ifdef SK_METAL + /** + * Makes a GrContext which uses Metal as the backend. The device parameter is an MTLDevice + * and queue is an MTLCommandQueue which should be used by the backend. These objects must + * have a ref on them which can be transferred to Ganesh which will release the ref when the + * GrContext is destroyed. + */ + static sk_sp MakeMetal(void* device, void* queue, const GrContextOptions& options); + static sk_sp MakeMetal(void* device, void* queue); +#endif + + static sk_sp MakeMock(const GrMockOptions*, const GrContextOptions&); + static sk_sp MakeMock(const GrMockOptions*); + + virtual ~GrContext(); + + sk_sp threadSafeProxy(); + + /** + * The GrContext normally assumes that no outsider is setting state + * within the underlying 3D API's context/device/whatever. This call informs + * the context that the state was modified and it should resend. Shouldn't + * be called frequently for good performance. + * The flag bits, state, is dpendent on which backend is used by the + * context, either GL or D3D (possible in future). + */ + void resetContext(uint32_t state = kAll_GrBackendState); + + /** + * Abandons all GPU resources and assumes the underlying backend 3D API context is no longer + * usable. Call this if you have lost the associated GPU context, and thus internal texture, + * buffer, etc. references/IDs are now invalid. Calling this ensures that the destructors of the + * GrContext and any of its created resource objects will not make backend 3D API calls. Content + * rendered but not previously flushed may be lost. After this function is called all subsequent + * calls on the GrContext will fail or be no-ops. + * + * The typical use case for this function is that the underlying 3D context was lost and further + * API calls may crash. + */ + virtual void abandonContext(); + + /** + * Returns true if the context was abandoned. + */ + bool abandoned() const; + + /** + * This is similar to abandonContext() however the underlying 3D context is not yet lost and + * the GrContext will cleanup all allocated resources before returning. After returning it will + * assume that the underlying context may no longer be valid. + * + * The typical use case for this function is that the client is going to destroy the 3D context + * but can't guarantee that GrContext will be destroyed first (perhaps because it may be ref'ed + * elsewhere by either the client or Skia objects). + */ + virtual void releaseResourcesAndAbandonContext(); + + /////////////////////////////////////////////////////////////////////////// + // Resource Cache + + /** + * Return the current GPU resource cache limits. + * + * @param maxResources If non-null, returns maximum number of resources that + * can be held in the cache. + * @param maxResourceBytes If non-null, returns maximum number of bytes of + * video memory that can be held in the cache. + */ + void getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const; + + /** + * Gets the current GPU resource cache usage. + * + * @param resourceCount If non-null, returns the number of resources that are held in the + * cache. + * @param maxResourceBytes If non-null, returns the total number of bytes of video memory held + * in the cache. + */ + void getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const; + + /** + * Gets the number of bytes in the cache consumed by purgeable (e.g. unlocked) resources. + */ + size_t getResourceCachePurgeableBytes() const; + + /** + * Specify the GPU resource cache limits. If the current cache exceeds either + * of these, it will be purged (LRU) to keep the cache within these limits. + * + * @param maxResources The maximum number of resources that can be held in + * the cache. + * @param maxResourceBytes The maximum number of bytes of video memory + * that can be held in the cache. + */ + void setResourceCacheLimits(int maxResources, size_t maxResourceBytes); + + /** + * Frees GPU created by the context. Can be called to reduce GPU memory + * pressure. + */ + virtual void freeGpuResources(); + + /** + * Purge GPU resources that haven't been used in the past 'msNotUsed' milliseconds or are + * otherwise marked for deletion, regardless of whether the context is under budget. + */ + void performDeferredCleanup(std::chrono::milliseconds msNotUsed); + + // Temporary compatibility API for Android. + void purgeResourcesNotUsedInMs(std::chrono::milliseconds msNotUsed) { + this->performDeferredCleanup(msNotUsed); + } + + /** + * Purge unlocked resources from the cache until the the provided byte count has been reached + * or we have purged all unlocked resources. The default policy is to purge in LRU order, but + * can be overridden to prefer purging scratch resources (in LRU order) prior to purging other + * resource types. + * + * @param maxBytesToPurge the desired number of bytes to be purged. + * @param preferScratchResources If true scratch resources will be purged prior to other + * resource types. + */ + void purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources); + + /** + * This entry point is intended for instances where an app has been backgrounded or + * suspended. + * If 'scratchResourcesOnly' is true all unlocked scratch resources will be purged but the + * unlocked resources with persistent data will remain. If 'scratchResourcesOnly' is false + * then all unlocked resources will be purged. + * In either case, after the unlocked resources are purged a separate pass will be made to + * ensure that resource usage is under budget (i.e., even if 'scratchResourcesOnly' is true + * some resources with persistent data may be purged to be under budget). + * + * @param scratchResourcesOnly If true only unlocked scratch resources will be purged prior + * enforcing the budget requirements. + */ + void purgeUnlockedResources(bool scratchResourcesOnly); + + /** + * Gets the maximum supported texture size. + */ + int maxTextureSize() const; + + /** + * Gets the maximum supported render target size. + */ + int maxRenderTargetSize() const; + + /** + * Can a SkImage be created with the given color type. + */ + bool colorTypeSupportedAsImage(SkColorType) const; + + /** + * Can a SkSurface be created with the given color type. To check whether MSAA is supported + * use maxSurfaceSampleCountForColorType(). + */ + bool colorTypeSupportedAsSurface(SkColorType colorType) const { + return this->maxSurfaceSampleCountForColorType(colorType) > 0; + } + + /** + * Gets the maximum supported sample count for a color type. 1 is returned if only non-MSAA + * rendering is supported for the color type. 0 is returned if rendering to this color type + * is not supported at all. + */ + int maxSurfaceSampleCountForColorType(SkColorType) const; + + /////////////////////////////////////////////////////////////////////////// + // Misc. + + /** + * Call to ensure all drawing to the context has been issued to the underlying 3D API. + */ + void flush(); + + /** + * Call to ensure all drawing to the context has been issued to the underlying 3D API. After + * issuing all commands, numSemaphore semaphores will be signaled by the gpu. The client passes + * in an array of numSemaphores GrBackendSemaphores. In general these GrBackendSemaphore's can + * be either initialized or not. If they are initialized, the backend uses the passed in + * semaphore. If it is not initialized, a new semaphore is created and the GrBackendSemaphore + * object is initialized with that semaphore. + * + * The client will own and be responsible for deleting the underlying semaphores that are stored + * and returned in initialized GrBackendSemaphore objects. The GrBackendSemaphore objects + * themselves can be deleted as soon as this function returns. + * + * If the backend API is OpenGL only uninitialized GrBackendSemaphores are supported. + * If the backend API is Vulkan either initialized or unitialized semaphores are supported. + * If unitialized, the semaphores which are created will be valid for use only with the VkDevice + * with which they were created. + * + * If this call returns GrSemaphoresSubmited::kNo, the GPU backend will not have created or + * added any semaphores to signal on the GPU. Thus the client should not have the GPU wait on + * any of the semaphores. However, any pending commands to the context will still be flushed. + */ + GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores, + GrBackendSemaphore signalSemaphores[]); + + /** + * An ID associated with this context, guaranteed to be unique. + */ + uint32_t uniqueID() { return fUniqueID; } + + // Provides access to functions that aren't part of the public API. + GrContextPriv contextPriv(); + const GrContextPriv contextPriv() const; + + /** Enumerates all cached GPU resources and dumps their memory to traceMemoryDump. */ + // Chrome is using this! + void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; + + bool supportsDistanceFieldText() const; + +protected: + GrContext(GrBackendApi, int32_t id = SK_InvalidGenID); + + bool initCommon(const GrContextOptions&); + virtual bool init(const GrContextOptions&) = 0; // must be called after the ctor! + + virtual GrAtlasManager* onGetAtlasManager() = 0; + + const GrBackendApi fBackend; + sk_sp fCaps; + sk_sp fThreadSafeProxy; + sk_sp fFPFactoryCache; + +private: + sk_sp fGpu; + GrResourceCache* fResourceCache; + GrResourceProvider* fResourceProvider; + GrProxyProvider* fProxyProvider; + + // All the GrOp-derived classes use this pool. + sk_sp fOpMemoryPool; + + GrGlyphCache* fGlyphCache; + std::unique_ptr fTextBlobCache; + + bool fDisableGpuYUVConversion; + bool fSharpenMipmappedTextures; + bool fDidTestPMConversions; + // true if the PM/UPM conversion succeeded; false otherwise + bool fPMUPMConversionsRoundTrip; + + // In debug builds we guard against improper thread handling + // This guard is passed to the GrDrawingManager and, from there to all the + // GrRenderTargetContexts. It is also passed to the GrResourceProvider and SkGpuDevice. + mutable GrSingleOwner fSingleOwner; + + std::unique_ptr fTaskGroup; + + const uint32_t fUniqueID; + + std::unique_ptr fDrawingManager; + + GrAuditTrail fAuditTrail; + + GrContextOptions::PersistentCache* fPersistentCache; + + // TODO: have the GrClipStackClip use renderTargetContexts and rm this friending + friend class GrContextPriv; + + /** + * These functions create premul <-> unpremul effects, using the specialized round-trip effects + * from GrConfigConversionEffect. + */ + std::unique_ptr createPMToUPMEffect(std::unique_ptr); + std::unique_ptr createUPMToPMEffect(std::unique_ptr); + + /** + * Returns true if createPMToUPMEffect and createUPMToPMEffect will succeed. In other words, + * did we find a pair of round-trip preserving conversion effects? + */ + bool validPMUPMConversionExists(); + + /** + * A callback similar to the above for use by the TextBlobCache + * TODO move textblob draw calls below context so we can use the call above. + */ + static void TextBlobCacheOverBudgetCB(void* data); + + typedef SkRefCnt INHERITED; +}; + +/** + * Can be used to perform actions related to the generating GrContext in a thread safe manner. The + * proxy does not access the 3D API (e.g. OpenGL) that backs the generating GrContext. + */ +class SK_API GrContextThreadSafeProxy : public SkRefCnt { +public: + ~GrContextThreadSafeProxy(); + + bool matches(GrContext* context) const { return context->uniqueID() == fContextUniqueID; } + + /** + * Create a surface characterization for a DDL that will be replayed into the GrContext + * that created this proxy. On failure the resulting characterization will be invalid (i.e., + * "!c.isValid()"). + * + * @param cacheMaxResourceBytes The max resource bytes limit that will be in effect when the + * DDL created with this characterization is replayed. + * Note: the contract here is that the DDL will be created as + * if it had a full 'cacheMaxResourceBytes' to use. If replayed + * into a GrContext that already has locked GPU memory, the + * replay can exceed the budget. To rephrase, all resource + * allocation decisions are made at record time and at playback + * time the budget limits will be ignored. + * @param ii The image info specifying properties of the SkSurface that + * the DDL created with this characterization will be replayed + * into. + * Note: Ganesh doesn't make use of the SkImageInfo's alphaType + * @param backendFormat Information about the format of the GPU surface that will + * back the SkSurface upon replay + * @param sampleCount The sample count of the SkSurface that the DDL created with + * this characterization will be replayed into + * @param origin The origin of the SkSurface that the DDL created with this + * characterization will be replayed into + * @param surfaceProps The surface properties of the SkSurface that the DDL created + * with this characterization will be replayed into + * @param isMipMapped Will the surface the DDL will be replayed into have space + * allocated for mipmaps? + * @param willUseGLFBO0 Will the surface the DDL will be replayed into be backed by GL + * FBO 0. This flag is only valid if using an GL backend. + */ + SkSurfaceCharacterization createCharacterization( + size_t cacheMaxResourceBytes, + const SkImageInfo& ii, const GrBackendFormat& backendFormat, + int sampleCount, GrSurfaceOrigin origin, + const SkSurfaceProps& surfaceProps, + bool isMipMapped, bool willUseGLFBO0 = false); + + bool operator==(const GrContextThreadSafeProxy& that) const { + // Each GrContext should only ever have a single thread-safe proxy. + SkASSERT((this == &that) == (fContextUniqueID == that.fContextUniqueID)); + return this == &that; + } + + bool operator!=(const GrContextThreadSafeProxy& that) const { return !(*this == that); } + + // Provides access to functions that aren't part of the public API. + GrContextThreadSafeProxyPriv priv(); + const GrContextThreadSafeProxyPriv priv() const; + +private: + // DDL TODO: need to add unit tests for backend & maybe options + GrContextThreadSafeProxy(sk_sp caps, + uint32_t uniqueID, + GrBackendApi backend, + const GrContextOptions& options, + sk_sp cache); + + sk_sp fCaps; + const uint32_t fContextUniqueID; + const GrBackendApi fBackend; + const GrContextOptions fOptions; + sk_sp fFPFactoryCache; + + friend class GrDirectContext; // To construct this object + friend class GrContextThreadSafeProxyPriv; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/gpu/GrContextOptions.h b/skia/include/gpu/GrContextOptions.h new file mode 100644 index 00000000..e134bd7d --- /dev/null +++ b/skia/include/gpu/GrContextOptions.h @@ -0,0 +1,259 @@ +/* + * 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 GrContextOptions_DEFINED +#define GrContextOptions_DEFINED + +#include "SkData.h" +#include "SkTypes.h" +#include "GrTypes.h" +#include "../private/GrTypesPriv.h" +#include "GrDriverBugWorkarounds.h" + +#include + +class SkExecutor; + +#if SK_SUPPORT_GPU +struct GrContextOptions { + enum class Enable { + /** Forces an option to be disabled. */ + kNo, + /** Forces an option to be enabled. */ + kYes, + /** + * Uses Skia's default behavior, which may use runtime properties (e.g. driver version). + */ + kDefault + }; + + /** + * Abstract class which stores Skia data in a cache that persists between sessions. Currently, + * Skia stores compiled shader binaries (only when glProgramBinary / glGetProgramBinary are + * supported) when provided a persistent cache, but this may extend to other data in the future. + */ + class PersistentCache { + public: + virtual ~PersistentCache() {} + + /** + * Returns the data for the key if it exists in the cache, otherwise returns null. + */ + virtual sk_sp load(const SkData& key) = 0; + + virtual void store(const SkData& key, const SkData& data) = 0; + }; + + GrContextOptions() {} + + // Suppress prints for the GrContext. + bool fSuppressPrints = false; + + /** Overrides: These options override feature detection using backend API queries. These + overrides can only reduce the feature set or limits, never increase them beyond the + detected values. */ + + int fMaxTextureSizeOverride = SK_MaxS32; + + /** the threshold in bytes above which we will use a buffer mapping API to map vertex and index + buffers to CPU memory in order to update them. A value of -1 means the GrContext should + deduce the optimal value for this platform. */ + int fBufferMapThreshold = -1; + + /** + * Executor to handle threaded work within Ganesh. If this is nullptr, then all work will be + * done serially on the main thread. To have worker threads assist with various tasks, set this + * to a valid SkExecutor instance. Currently, used for software path rendering, but may be used + * for other tasks. + */ + SkExecutor* fExecutor = nullptr; + + /** Construct mipmaps manually, via repeated downsampling draw-calls. This is used when + the driver's implementation (glGenerateMipmap) contains bugs. This requires mipmap + level and LOD control (ie desktop or ES3). */ + bool fDoManualMipmapping = false; + + /** + * Disables the coverage counting path renderer. Coverage counting can sometimes cause new + * rendering artifacts along shared edges if care isn't taken to ensure both contours wind in + * the same direction. + */ + bool fDisableCoverageCountingPaths = false; + + /** + * Disables distance field rendering for paths. Distance field computation can be expensive, + * and yields no benefit if a path is not rendered multiple times with different transforms. + */ + bool fDisableDistanceFieldPaths = false; + + /** + * If true this allows path mask textures to be cached. This is only really useful if paths + * are commonly rendered at the same scale and fractional translation. + */ + bool fAllowPathMaskCaching = true; + + /** + * If true, the GPU will not be used to perform YUV -> RGB conversion when generating + * textures from codec-backed images. + */ + bool fDisableGpuYUVConversion = false; + + /** + * The maximum size of cache textures used for Skia's Glyph cache. + */ + size_t fGlyphCacheTextureMaximumBytes = 2048 * 1024 * 4; + + /** + * Below this threshold size in device space distance field fonts won't be used. Distance field + * fonts don't support hinting which is more important at smaller sizes. A negative value means + * use the default threshold. + */ + float fMinDistanceFieldFontSize = -1.f; + + /** + * Above this threshold size in device space glyphs are drawn as individual paths. A negative + * value means use the default threshold. + */ + float fGlyphsAsPathsFontSize = -1.f; + + /** + * Can the glyph atlas use multiple textures. If allowed, the each texture's size is bound by + * fGlypheCacheTextureMaximumBytes. + */ + Enable fAllowMultipleGlyphCacheTextures = Enable::kDefault; + + /** + * Bugs on certain drivers cause stencil buffers to leak. This flag causes Skia to avoid + * allocating stencil buffers and use alternate rasterization paths, avoiding the leak. + */ + bool fAvoidStencilBuffers = false; + + /** + * When specifing new data for a vertex/index buffer that replaces old data Ganesh can give + * a hint to the driver that the previous data will not be used in future draws like this: + * glBufferData(GL_..._BUFFER, size, NULL, usage); //<--hint, NULL means + * glBufferSubData(GL_..._BUFFER, 0, lessThanSize, data) // old data can't be + * // used again. + * However, this can be an unoptimization on some platforms, esp. Chrome. + * Chrome's cmd buffer will create a new allocation and memset the whole thing + * to zero (for security reasons). + * Defaults to the value of GR_GL_USE_BUFFER_DATA_NULL_HINT #define (which is, by default, 1). + */ + Enable fUseGLBufferDataNullHint = Enable::kDefault; + + /** + * If true, texture fetches from mip-mapped textures will be biased to read larger MIP levels. + * This has the effect of sharpening those textures, at the cost of some aliasing, and possible + * performance impact. + */ + bool fSharpenMipmappedTextures = false; + + /** + * Enables driver workaround to use draws instead of glClear. This only applies to + * GrBackendApi::kOpenGL. + */ + Enable fUseDrawInsteadOfGLClear = Enable::kDefault; + + /** + * Allow Ganesh to explicitly allocate resources at flush time rather than incrementally while + * drawing. This will eventually just be the way it is but, for now, it is optional. + */ + Enable fExplicitlyAllocateGPUResources = Enable::kDefault; + + /** + * Allow Ganesh to sort the opLists prior to allocating resources. This is an optional + * behavior that is only relevant when 'fExplicitlyAllocateGPUResources' is enabled. + * Eventually this will just be what is done and will not be optional. + */ + Enable fSortRenderTargets = Enable::kDefault; + + /** + * Allow Ganesh to more aggressively reorder operations. This is an optional + * behavior that is only relevant when 'fSortRenderTargets' is enabled. + * Eventually this will just be what is done and will not be optional. + */ + Enable fReduceOpListSplitting = Enable::kDefault; + + /** + * Some ES3 contexts report the ES2 external image extension, but not the ES3 version. + * If support for external images is critical, enabling this option will cause Ganesh to limit + * shaders to the ES2 shading language in that situation. + */ + bool fPreferExternalImagesOverES3 = false; + + /** + * Disables correctness workarounds that are enabled for particular GPUs, OSes, or drivers. + * This does not affect code path choices that are made for perfomance reasons nor does it + * override other GrContextOption settings. + */ + bool fDisableDriverCorrectnessWorkarounds = false; + + /** + * Cache in which to store compiled shader binaries between runs. + */ + PersistentCache* fPersistentCache = nullptr; + +#if GR_TEST_UTILS + /** + * Private options that are only meant for testing within Skia's tools. + */ + + /** + * If non-zero, overrides the maximum size of a tile for sw-backed images and bitmaps rendered + * by SkGpuDevice. + */ + int fMaxTileSizeOverride = 0; + + /** + * Prevents use of dual source blending, to test that all xfer modes work correctly without it. + */ + bool fSuppressDualSourceBlending = false; + + /** + * If true, the caps will never report driver support for path rendering. + */ + bool fSuppressPathRendering = false; + + /** + * If true, the caps will never support geometry shaders. + */ + bool fSuppressGeometryShaders = false; + + /** + * Render everything in wireframe + */ + bool fWireframeMode = false; + + /** + * Include or exclude specific GPU path renderers. + */ + GpuPathRenderers fGpuPathRenderers = GpuPathRenderers::kAll; + + /** + * Disables using multiple texture units to batch multiple images into a single draw on + * supported GPUs. + */ + bool fDisableImageMultitexturing = false; +#endif + +#if SK_SUPPORT_ATLAS_TEXT + /** + * Controls whether distance field glyph vertices always have 3 components even when the view + * matrix does not have perspective. + */ + Enable fDistanceFieldGlyphVerticesAlwaysHaveW = Enable::kDefault; +#endif + + GrDriverBugWorkarounds fDriverBugWorkarounds; +}; +#else +struct GrContextOptions { + struct PersistentCache {}; +}; +#endif + +#endif diff --git a/skia/include/gpu/GrDriverBugWorkarounds.h b/skia/include/gpu/GrDriverBugWorkarounds.h new file mode 100644 index 00000000..31f6df5a --- /dev/null +++ b/skia/include/gpu/GrDriverBugWorkarounds.h @@ -0,0 +1,51 @@ +/* + * 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 GrDriverBugWorkarounds_DEFINED +#define GrDriverBugWorkarounds_DEFINED + +// External embedders of Skia can override this to use their own list +// of workaround names. +#ifdef SK_GPU_WORKAROUNDS_HEADER +#include SK_GPU_WORKAROUNDS_HEADER +#else +// To regenerate this file, set gn arg "skia_generate_workarounds = true". +// This is not rebuilt by default to avoid embedders having to have extra +// build steps. +#include "GrDriverBugWorkaroundsAutogen.h" +#endif + +#include "SkTypes.h" + +#include +#include + +enum GrDriverBugWorkaroundType { +#define GPU_OP(type, name) type, + GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) +#undef GPU_OP + NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES +}; + +class SK_API GrDriverBugWorkarounds { + public: + GrDriverBugWorkarounds(); + explicit GrDriverBugWorkarounds(const std::vector& workarounds); + + GrDriverBugWorkarounds& operator=(const GrDriverBugWorkarounds&) = default; + + // Turn on any workarounds listed in |workarounds| (but don't turn any off). + void applyOverrides(const GrDriverBugWorkarounds& workarounds); + + ~GrDriverBugWorkarounds(); + +#define GPU_OP(type, name) bool name = false; + GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) +#undef GPU_OP +}; + +#endif diff --git a/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h b/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h new file mode 100644 index 00000000..a4db30e6 --- /dev/null +++ b/skia/include/gpu/GrDriverBugWorkaroundsAutogen.h @@ -0,0 +1,43 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is auto-generated from build_workaround_header.py +// DO NOT EDIT! + +#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) \ + GPU_OP(ADD_AND_TRUE_TO_LOOP_CONDITION, \ + add_and_true_to_loop_condition) \ + GPU_OP(DISABLE_BLEND_EQUATION_ADVANCED, \ + disable_blend_equation_advanced) \ + GPU_OP(DISABLE_DISCARD_FRAMEBUFFER, \ + disable_discard_framebuffer) \ + GPU_OP(DISABLE_TEXTURE_STORAGE, \ + disable_texture_storage) \ + GPU_OP(DISALLOW_LARGE_INSTANCED_DRAW, \ + disallow_large_instanced_draw) \ + GPU_OP(EMULATE_ABS_INT_FUNCTION, \ + emulate_abs_int_function) \ + GPU_OP(FLUSH_ON_FRAMEBUFFER_CHANGE, \ + flush_on_framebuffer_change) \ + GPU_OP(GL_CLEAR_BROKEN, \ + gl_clear_broken) \ + GPU_OP(MAX_FRAGMENT_UNIFORM_VECTORS_32, \ + max_fragment_uniform_vectors_32) \ + GPU_OP(MAX_MSAA_SAMPLE_COUNT_4, \ + max_msaa_sample_count_4) \ + GPU_OP(MAX_TEXTURE_SIZE_LIMIT_4096, \ + max_texture_size_limit_4096) \ + GPU_OP(PACK_PARAMETERS_WORKAROUND_WITH_PACK_BUFFER, \ + pack_parameters_workaround_with_pack_buffer) \ + GPU_OP(REMOVE_POW_WITH_CONSTANT_EXPONENT, \ + remove_pow_with_constant_exponent) \ + GPU_OP(RESTORE_SCISSOR_ON_FBO_CHANGE, \ + restore_scissor_on_fbo_change) \ + GPU_OP(REWRITE_DO_WHILE_LOOPS, \ + rewrite_do_while_loops) \ + GPU_OP(UNBIND_ATTACHMENTS_ON_BOUND_RENDER_FBO_DELETE, \ + unbind_attachments_on_bound_render_fbo_delete) \ + GPU_OP(UNFOLD_SHORT_CIRCUIT_AS_TERNARY_OPERATION, \ + unfold_short_circuit_as_ternary_operation) \ +// The End diff --git a/skia/include/gpu/GrGpuResource.h b/skia/include/gpu/GrGpuResource.h new file mode 100644 index 00000000..7f57cdd6 --- /dev/null +++ b/skia/include/gpu/GrGpuResource.h @@ -0,0 +1,358 @@ +/* + * 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 GrGpuResource_DEFINED +#define GrGpuResource_DEFINED + +#include "../private/GrTypesPriv.h" +#include "../private/SkNoncopyable.h" +#include "GrResourceKey.h" + +class GrContext; +class GrGpu; +class GrResourceCache; +class SkTraceMemoryDump; + +/** + * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base + * class to isolate the ref-cnting behavior and provide friendship without exposing all of + * GrGpuResource. + * + * Gpu resources can have three types of refs: + * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls + * that read and write the resource via GrOpList and by any object that must own a + * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code. + * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read + * of the resource by the GPU as a result of a skia API call but hasn't executed it yet. + * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a + * write to the resource by the GPU as a result of a skia API call but hasn't executed it yet. + * + * The latter two ref types are private and intended only for Gr core code. + * + * When all the ref/io counts reach zero DERIVED::notifyAllCntsAreZero() will be called (static poly + * morphism using CRTP). Similarly when the ref (but not necessarily pending read/write) count + * reaches 0 DERIVED::notifyRefCountIsZero() will be called. In the case when an unref() causes both + * the ref cnt to reach zero and the other counts are zero, notifyRefCountIsZero() will be called + * before notifyIsPurgeable(). Moreover, if notifyRefCountIsZero() returns false then + * notifyAllRefCntsAreZero() won't be called at all. notifyRefCountIsZero() must return false if the + * object may be deleted after notifyRefCntIsZero() returns. + * + * GrIORef and GrGpuResource are separate classes for organizational reasons and to be + * able to give access via friendship to only the functions related to pending IO operations. + */ +template class GrIORef : public SkNoncopyable { +public: + // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with + // templated helper classes (e.g. sk_sp). However, we have different categories of + // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are + // not intended to cross thread boundaries. + void ref() const { + this->validate(); + ++fRefCnt; + } + + void unref() const { + this->validate(); + + if (!(--fRefCnt)) { + if (!static_cast(this)->notifyRefCountIsZero()) { + return; + } + } + + this->didRemoveRefOrPendingIO(kRef_CntType); + } + + void validate() const { +#ifdef SK_DEBUG + SkASSERT(fRefCnt >= 0); + SkASSERT(fPendingReads >= 0); + SkASSERT(fPendingWrites >= 0); + SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0); +#endif + } + +protected: + GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } + + enum CntType { + kRef_CntType, + kPendingRead_CntType, + kPendingWrite_CntType, + }; + + bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); } + + bool internalHasPendingRead() const { return SkToBool(fPendingReads); } + bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } + bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } + + bool internalHasRef() const { return SkToBool(fRefCnt); } + bool internalHasUniqueRef() const { return fRefCnt == 1; } + +private: + friend class GrIORefProxy; // needs to forward on wrapped IO calls + // This is for a unit test. + template + friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt); + + void addPendingRead() const { + this->validate(); + ++fPendingReads; + } + + void completedRead() const { + this->validate(); + --fPendingReads; + this->didRemoveRefOrPendingIO(kPendingRead_CntType); + } + + void addPendingWrite() const { + this->validate(); + ++fPendingWrites; + } + + void completedWrite() const { + this->validate(); + --fPendingWrites; + this->didRemoveRefOrPendingIO(kPendingWrite_CntType); + } + +private: + void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const { + if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { + static_cast(this)->notifyAllCntsAreZero(cntTypeRemoved); + } + } + + mutable int32_t fRefCnt; + mutable int32_t fPendingReads; + mutable int32_t fPendingWrites; + + friend class GrResourceCache; // to check IO ref counts. + + template friend class GrPendingIOResource; +}; + +/** + * Base class for objects that can be kept in the GrResourceCache. + */ +class SK_API GrGpuResource : public GrIORef { +public: + + /** + * Tests whether a object has been abandoned or released. All objects will + * be in this state after their creating GrContext is destroyed or has + * contextLost called. It's up to the client to test wasDestroyed() before + * attempting to use an object if it holds refs on objects across + * ~GrContext, freeResources with the force flag, or contextLost. + * + * @return true if the object has been released or abandoned, + * false otherwise. + */ + bool wasDestroyed() const { return nullptr == fGpu; } + + /** + * Retrieves the context that owns the object. Note that it is possible for + * this to return NULL. When objects have been release()ed or abandon()ed + * they no longer have an owning context. Destroying a GrContext + * automatically releases all its resources. + */ + const GrContext* getContext() const; + GrContext* getContext(); + + /** + * Retrieves the amount of GPU memory used by this resource in bytes. It is + * approximate since we aren't aware of additional padding or copies made + * by the driver. + * + * @return the amount of GPU memory used in bytes + */ + size_t gpuMemorySize() const { + if (kInvalidGpuMemorySize == fGpuMemorySize) { + fGpuMemorySize = this->onGpuMemorySize(); + SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); + } + return fGpuMemorySize; + } + + class UniqueID { + public: + static UniqueID InvalidID() { + return UniqueID(uint32_t(SK_InvalidUniqueID)); + } + + UniqueID() {} + + explicit UniqueID(uint32_t id) : fID(id) {} + + uint32_t asUInt() const { return fID; } + + bool operator==(const UniqueID& other) const { + return fID == other.fID; + } + bool operator!=(const UniqueID& other) const { + return !(*this == other); + } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isInvalid() const { return SK_InvalidUniqueID == fID; } + + protected: + uint32_t fID; + }; + + /** + * Gets an id that is unique for this GrGpuResource object. It is static in that it does + * not change when the content of the GrGpuResource object changes. This will never return + * 0. + */ + UniqueID uniqueID() const { return fUniqueID; } + + /** Returns the current unique key for the resource. It will be invalid if the resource has no + associated unique key. */ + const GrUniqueKey& getUniqueKey() const { return fUniqueKey; } + + /** + * Internal-only helper class used for manipulations of the resource by the cache. + */ + class CacheAccess; + inline CacheAccess cacheAccess(); + inline const CacheAccess cacheAccess() const; + + /** + * Internal-only helper class used for manipulations of the resource by internal code. + */ + class ResourcePriv; + inline ResourcePriv resourcePriv(); + inline const ResourcePriv resourcePriv() const; + + /** + * Removes references to objects in the underlying 3D API without freeing them. + * Called by CacheAccess. + * In general this method should not be called outside of skia. It was + * made by public for a special case where it needs to be called in Blink + * when a texture becomes unsafe to use after having been shared through + * a texture mailbox. + */ + void abandon(); + + /** + * Dumps memory usage information for this GrGpuResource to traceMemoryDump. + * Typically, subclasses should not need to override this, and should only + * need to override setMemoryBacking. + **/ + virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; + + /** + * Describes the type of gpu resource that is represented by the implementing + * class (e.g. texture, buffer object, stencil). This data is used for diagnostic + * purposes by dumpMemoryStatistics(). + * + * The value returned is expected to be long lived and will not be copied by the caller. + */ + virtual const char* getResourceType() const = 0; + + static uint32_t CreateUniqueID(); + +protected: + // This must be called by every non-wrapped GrGpuObject. It should be called once the object is + // fully initialized (i.e. only from the constructors of the final class). + void registerWithCache(SkBudgeted); + + // This must be called by every GrGpuObject that references any wrapped backend objects. It + // should be called once the object is fully initialized (i.e. only from the constructors of the + // final class). + void registerWithCacheWrapped(bool purgeImmediately = false); + + GrGpuResource(GrGpu*); + virtual ~GrGpuResource(); + + GrGpu* getGpu() const { return fGpu; } + + /** Overridden to free GPU resources in the backend API. */ + virtual void onRelease() { } + /** Overridden to abandon any internal handles, ptrs, etc to backend API resources. + This may be called when the underlying 3D context is no longer valid and so no + backend API calls should be made. */ + virtual void onAbandon() { } + + /** + * Allows subclasses to add additional backing information to the SkTraceMemoryDump. + **/ + virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {} + + /** + * Returns a string that uniquely identifies this resource. + */ + SkString getResourceName() const; + + /** + * A helper for subclasses that override dumpMemoryStatistics(). This method using a format + * consistent with the default implementation of dumpMemoryStatistics() but allows the caller + * to customize various inputs. + */ + void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName, + const char* type, size_t size) const; + + +private: + /** + * Called by the registerWithCache if the resource is available to be used as scratch. + * Resource subclasses should override this if the instances should be recycled as scratch + * resources and populate the scratchKey with the key. + * By default resources are not recycled as scratch. + **/ + virtual void computeScratchKey(GrScratchKey*) const { } + + /** + * Frees the object in the underlying 3D API. Called by CacheAccess. + */ + void release(); + + virtual size_t onGpuMemorySize() const = 0; + + // See comments in CacheAccess and ResourcePriv. + void setUniqueKey(const GrUniqueKey&); + void removeUniqueKey(); + void notifyAllCntsAreZero(CntType) const; + bool notifyRefCountIsZero() const; + void removeScratchKey(); + void makeBudgeted(); + void makeUnbudgeted(); + +#ifdef SK_DEBUG + friend class GrGpu; // for assert in GrGpu to access getGpu +#endif + + // An index into a heap when this resource is purgeable or an array when not. This is maintained + // by the cache. + int fCacheArrayIndex; + // This value reflects how recently this resource was accessed in the cache. This is maintained + // by the cache. + uint32_t fTimestamp; + GrStdSteadyClock::time_point fTimeWhenBecamePurgeable; + + static const size_t kInvalidGpuMemorySize = ~static_cast(0); + GrScratchKey fScratchKey; + GrUniqueKey fUniqueKey; + + // This is not ref'ed but abandon() or release() will be called before the GrGpu object + // is destroyed. Those calls set will this to NULL. + GrGpu* fGpu; + mutable size_t fGpuMemorySize; + + SkBudgeted fBudgeted; + bool fShouldPurgeImmediately; + bool fRefsWrappedObjects; + const UniqueID fUniqueID; + + typedef GrIORef INHERITED; + friend class GrIORef; // to access notifyAllCntsAreZero and notifyRefCntIsZero. +}; + +#endif diff --git a/skia/include/gpu/GrRenderTarget.h b/skia/include/gpu/GrRenderTarget.h new file mode 100644 index 00000000..32c6225d --- /dev/null +++ b/skia/include/gpu/GrRenderTarget.h @@ -0,0 +1,136 @@ +/* + * 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 GrRenderTarget_DEFINED +#define GrRenderTarget_DEFINED + +#include "GrSurface.h" +#include "SkRect.h" + +class GrCaps; +class GrRenderTargetOpList; +class GrRenderTargetPriv; +class GrStencilAttachment; +class GrBackendRenderTarget; + +/** + * GrRenderTarget represents a 2D buffer of pixels that can be rendered to. + * A context's render target is set by setRenderTarget(). Render targets are + * created by a createTexture with the kRenderTarget_SurfaceFlag flag. + * Additionally, GrContext provides methods for creating GrRenderTargets + * that wrap externally created render targets. + */ +class GrRenderTarget : virtual public GrSurface { +public: + virtual bool alwaysClearStencil() const { return false; } + + // GrSurface overrides + GrRenderTarget* asRenderTarget() override { return this; } + const GrRenderTarget* asRenderTarget() const override { return this; } + + // GrRenderTarget + bool isStencilBufferMultisampled() const { return fSampleCnt > 1; } + + GrFSAAType fsaaType() const { + SkASSERT(fSampleCnt >= 1); + if (fSampleCnt <= 1) { + SkASSERT(!this->hasMixedSamples()); + return GrFSAAType::kNone; + } + return this->hasMixedSamples() ? GrFSAAType::kMixedSamples : GrFSAAType::kUnifiedMSAA; + } + + /** + * Returns the number of samples/pixel in the stencil buffer (One if non-MSAA). + */ + int numStencilSamples() const { return fSampleCnt; } + + /** + * Returns the number of samples/pixel in the color buffer (One if non-MSAA or mixed sampled). + */ + int numColorSamples() const { + return GrFSAAType::kMixedSamples == this->fsaaType() ? 1 : fSampleCnt; + } + + /** + * Call to indicate the multisample contents were modified such that the + * render target needs to be resolved before it can be used as texture. Gr + * tracks this for its own drawing and thus this only needs to be called + * when the render target has been modified outside of Gr. This has no + * effect on wrapped backend render targets. + * + * @param rect a rect bounding the area needing resolve. NULL indicates + * the whole RT needs resolving. + */ + void flagAsNeedingResolve(const SkIRect* rect = nullptr); + + /** + * Call to override the region that needs to be resolved. + */ + void overrideResolveRect(const SkIRect rect); + + /** + * Call to indicate that GrRenderTarget was externally resolved. This may + * allow Gr to skip a redundant resolve step. + */ + void flagAsResolved(); + + /** + * @return true if the GrRenderTarget requires MSAA resolving + */ + bool needsResolve() const { return !fResolveRect.isEmpty(); } + + /** + * Returns a rect bounding the region needing resolving. + */ + const SkIRect& getResolveRect() const { return fResolveRect; } + + // a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO + // 0 in GL), or be unresolvable because the client didn't give us the + // resolve destination. + enum ResolveType { + kCanResolve_ResolveType, + kAutoResolves_ResolveType, + kCantResolve_ResolveType, + }; + virtual ResolveType getResolveType() const = 0; + + virtual GrBackendRenderTarget getBackendRenderTarget() const = 0; + + // Checked when this object is asked to attach a stencil buffer. + virtual bool canAttemptStencilAttachment() const = 0; + + // Provides access to functions that aren't part of the public API. + GrRenderTargetPriv renderTargetPriv(); + const GrRenderTargetPriv renderTargetPriv() const; + +protected: + GrRenderTarget(GrGpu*, const GrSurfaceDesc&, GrStencilAttachment* = nullptr); + ~GrRenderTarget() override; + + // override of GrResource + void onAbandon() override; + void onRelease() override; + +private: + // Allows the backends to perform any additional work that is required for attaching a + // GrStencilAttachment. When this is called, the GrStencilAttachment has already been put onto + // the GrRenderTarget. This function must return false if any failures occur when completing the + // stencil attachment. + virtual bool completeStencilAttachment() = 0; + + friend class GrRenderTargetPriv; + + int fSampleCnt; + sk_sp fStencilAttachment; + + SkIRect fResolveRect; + + typedef GrSurface INHERITED; +}; + +#endif diff --git a/skia/include/gpu/GrResourceKey.h b/skia/include/gpu/GrResourceKey.h new file mode 100644 index 00000000..fb1b8920 --- /dev/null +++ b/skia/include/gpu/GrResourceKey.h @@ -0,0 +1,363 @@ +/* + * 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 GrResourceKey_DEFINED +#define GrResourceKey_DEFINED + +#include "../private/SkOnce.h" +#include "../private/SkTemplates.h" +#include "../private/SkTo.h" +#include "GrTypes.h" +#include "SkData.h" +#include "SkString.h" + +#include + +uint32_t GrResourceKeyHash(const uint32_t* data, size_t size); + +/** + * Base class for all GrGpuResource cache keys. There are two types of cache keys. Refer to the + * comments for each key type below. + */ +class GrResourceKey { +public: + uint32_t hash() const { + this->validate(); + return fKey[kHash_MetaDataIdx]; + } + + size_t size() const { + this->validate(); + SkASSERT(this->isValid()); + return this->internalSize(); + } + +protected: + static const uint32_t kInvalidDomain = 0; + + GrResourceKey() { this->reset(); } + + /** Reset to an invalid key. */ + void reset() { + GR_STATIC_ASSERT((uint16_t)kInvalidDomain == kInvalidDomain); + fKey.reset(kMetaDataCnt); + fKey[kHash_MetaDataIdx] = 0; + fKey[kDomainAndSize_MetaDataIdx] = kInvalidDomain; + } + + bool operator==(const GrResourceKey& that) const { + return this->hash() == that.hash() && + 0 == memcmp(&fKey[kHash_MetaDataIdx + 1], + &that.fKey[kHash_MetaDataIdx + 1], + this->internalSize() - sizeof(uint32_t)); + } + + GrResourceKey& operator=(const GrResourceKey& that) { + SkASSERT(that.isValid()); + if (this != &that) { + size_t bytes = that.size(); + SkASSERT(SkIsAlign4(bytes)); + fKey.reset(SkToInt(bytes / sizeof(uint32_t))); + memcpy(fKey.get(), that.fKey.get(), bytes); + this->validate(); + } + return *this; + } + + bool isValid() const { return kInvalidDomain != this->domain(); } + + uint32_t domain() const { return fKey[kDomainAndSize_MetaDataIdx] & 0xffff; } + + /** size of the key data, excluding meta-data (hash, domain, etc). */ + size_t dataSize() const { return this->size() - 4 * kMetaDataCnt; } + + /** ptr to the key data, excluding meta-data (hash, domain, etc). */ + const uint32_t* data() const { + this->validate(); + return &fKey[kMetaDataCnt]; + } + +#ifdef SK_DEBUG + void dump() const { + if (!this->isValid()) { + SkDebugf("Invalid Key\n"); + } else { + SkDebugf("hash: %d ", this->hash()); + SkDebugf("domain: %d ", this->domain()); + SkDebugf("size: %dB ", this->internalSize()); + for (size_t i = 0; i < this->internalSize(); ++i) { + SkDebugf("%d ", fKey[i]); + } + SkDebugf("\n"); + } + } +#endif + + /** Used to initialize a key. */ + class Builder { + public: + Builder(GrResourceKey* key, uint32_t domain, int data32Count) : fKey(key) { + SkASSERT(data32Count >= 0); + SkASSERT(domain != kInvalidDomain); + key->fKey.reset(kMetaDataCnt + data32Count); + int size = (data32Count + kMetaDataCnt) * sizeof(uint32_t); + SkASSERT(SkToU16(size) == size); + SkASSERT(SkToU16(domain) == domain); + key->fKey[kDomainAndSize_MetaDataIdx] = domain | (size << 16); + } + + ~Builder() { this->finish(); } + + void finish() { + if (nullptr == fKey) { + return; + } + GR_STATIC_ASSERT(0 == kHash_MetaDataIdx); + uint32_t* hash = &fKey->fKey[kHash_MetaDataIdx]; + *hash = GrResourceKeyHash(hash + 1, fKey->internalSize() - sizeof(uint32_t)); + fKey->validate(); + fKey = nullptr; + } + + uint32_t& operator[](int dataIdx) { + SkASSERT(fKey); + SkDEBUGCODE(size_t dataCount = fKey->internalSize() / sizeof(uint32_t) - kMetaDataCnt;) + SkASSERT(SkToU32(dataIdx) < dataCount); + return fKey->fKey[kMetaDataCnt + dataIdx]; + } + + private: + GrResourceKey* fKey; + }; + +private: + enum MetaDataIdx { + kHash_MetaDataIdx, + // The key domain and size are packed into a single uint32_t. + kDomainAndSize_MetaDataIdx, + + kLastMetaDataIdx = kDomainAndSize_MetaDataIdx + }; + static const uint32_t kMetaDataCnt = kLastMetaDataIdx + 1; + + size_t internalSize() const { + return fKey[kDomainAndSize_MetaDataIdx] >> 16; + } + + void validate() const { + SkASSERT(fKey[kHash_MetaDataIdx] == + GrResourceKeyHash(&fKey[kHash_MetaDataIdx] + 1, + this->internalSize() - sizeof(uint32_t))); + SkASSERT(SkIsAlign4(this->internalSize())); + } + + friend class TestResource; // For unit test to access kMetaDataCnt. + + // bmp textures require 5 uint32_t values. + SkAutoSTMalloc fKey; +}; + +/** + * A key used for scratch resources. There are three important rules about scratch keys: + * * Multiple resources can share the same scratch key. Therefore resources assigned the same + * scratch key should be interchangeable with respect to the code that uses them. + * * A resource can have at most one scratch key and it is set at resource creation by the + * resource itself. + * * When a scratch resource is ref'ed it will not be returned from the + * cache for a subsequent cache request until all refs are released. This facilitates using + * a scratch key for multiple render-to-texture scenarios. An example is a separable blur: + * + * GrTexture* texture[2]; + * texture[0] = get_scratch_texture(scratchKey); + * texture[1] = get_scratch_texture(scratchKey); // texture[0] is already owned so we will get a + * // different one for texture[1] + * draw_mask(texture[0], path); // draws path mask to texture[0] + * blur_x(texture[0], texture[1]); // blurs texture[0] in y and stores result in texture[1] + * blur_y(texture[1], texture[0]); // blurs texture[1] in y and stores result in texture[0] + * texture[1]->unref(); // texture 1 can now be recycled for the next request with scratchKey + * consume_blur(texture[0]); + * texture[0]->unref(); // texture 0 can now be recycled for the next request with scratchKey + */ +class GrScratchKey : public GrResourceKey { +private: + typedef GrResourceKey INHERITED; + +public: + /** Uniquely identifies the type of resource that is cached as scratch. */ + typedef uint32_t ResourceType; + + /** Generate a unique ResourceType. */ + static ResourceType GenerateResourceType(); + + /** Creates an invalid scratch key. It must be initialized using a Builder object before use. */ + GrScratchKey() {} + + GrScratchKey(const GrScratchKey& that) { *this = that; } + + /** reset() returns the key to the invalid state. */ + using INHERITED::reset; + + using INHERITED::isValid; + + ResourceType resourceType() const { return this->domain(); } + + GrScratchKey& operator=(const GrScratchKey& that) { + this->INHERITED::operator=(that); + return *this; + } + + bool operator==(const GrScratchKey& that) const { + return this->INHERITED::operator==(that); + } + bool operator!=(const GrScratchKey& that) const { return !(*this == that); } + + class Builder : public INHERITED::Builder { + public: + Builder(GrScratchKey* key, ResourceType type, int data32Count) + : INHERITED::Builder(key, type, data32Count) {} + }; +}; + +/** + * A key that allows for exclusive use of a resource for a use case (AKA "domain"). There are three + * rules governing the use of unique keys: + * * Only one resource can have a given unique key at a time. Hence, "unique". + * * A resource can have at most one unique key at a time. + * * Unlike scratch keys, multiple requests for a unique key will return the same + * resource even if the resource already has refs. + * This key type allows a code path to create cached resources for which it is the exclusive user. + * The code path creates a domain which it sets on its keys. This guarantees that there are no + * cross-domain collisions. + * + * Unique keys preempt scratch keys. While a resource has a unique key it is inaccessible via its + * scratch key. It can become scratch again if the unique key is removed. + */ +class GrUniqueKey : public GrResourceKey { +private: + typedef GrResourceKey INHERITED; + +public: + typedef uint32_t Domain; + /** Generate a Domain for unique keys. */ + static Domain GenerateDomain(); + + /** Creates an invalid unique key. It must be initialized using a Builder object before use. */ + GrUniqueKey() : fTag(nullptr) {} + + GrUniqueKey(const GrUniqueKey& that) { *this = that; } + + /** reset() returns the key to the invalid state. */ + using INHERITED::reset; + + using INHERITED::isValid; + + GrUniqueKey& operator=(const GrUniqueKey& that) { + this->INHERITED::operator=(that); + this->setCustomData(sk_ref_sp(that.getCustomData())); + fTag = that.fTag; + return *this; + } + + bool operator==(const GrUniqueKey& that) const { + return this->INHERITED::operator==(that); + } + bool operator!=(const GrUniqueKey& that) const { return !(*this == that); } + + void setCustomData(sk_sp data) { + fData = std::move(data); + } + SkData* getCustomData() const { + return fData.get(); + } + + const char* tag() const { return fTag; } + +#ifdef SK_DEBUG + void dump(const char* label) const { + SkDebugf("%s tag: %s\n", label, fTag ? fTag : "None"); + this->INHERITED::dump(); + } +#endif + + class Builder : public INHERITED::Builder { + public: + Builder(GrUniqueKey* key, Domain type, int data32Count, const char* tag = nullptr) + : INHERITED::Builder(key, type, data32Count) { + key->fTag = tag; + } + + /** Used to build a key that wraps another key and adds additional data. */ + Builder(GrUniqueKey* key, const GrUniqueKey& innerKey, Domain domain, int extraData32Cnt, + const char* tag = nullptr) + : INHERITED::Builder(key, domain, Data32CntForInnerKey(innerKey) + extraData32Cnt) { + SkASSERT(&innerKey != key); + // add the inner key to the end of the key so that op[] can be indexed normally. + uint32_t* innerKeyData = &this->operator[](extraData32Cnt); + const uint32_t* srcData = innerKey.data(); + (*innerKeyData++) = innerKey.domain(); + memcpy(innerKeyData, srcData, innerKey.dataSize()); + key->fTag = tag; + } + + private: + static int Data32CntForInnerKey(const GrUniqueKey& innerKey) { + // key data + domain + return SkToInt((innerKey.dataSize() >> 2) + 1); + } + }; + +private: + sk_sp fData; + const char* fTag; +}; + +/** + * It is common to need a frequently reused GrUniqueKey where the only requirement is that the key + * is unique. These macros create such a key in a thread safe manner so the key can be truly global + * and only constructed once. + */ + +/** Place outside of function/class definitions. */ +#define GR_DECLARE_STATIC_UNIQUE_KEY(name) static SkOnce name##_once + +/** Place inside function where the key is used. */ +#define GR_DEFINE_STATIC_UNIQUE_KEY(name) \ + static SkAlignedSTStorage<1, GrUniqueKey> name##_storage; \ + name##_once(gr_init_static_unique_key_once, &name##_storage); \ + static const GrUniqueKey& name = *reinterpret_cast(name##_storage.get()); + +static inline void gr_init_static_unique_key_once(SkAlignedSTStorage<1,GrUniqueKey>* keyStorage) { + GrUniqueKey* key = new (keyStorage->get()) GrUniqueKey; + GrUniqueKey::Builder builder(key, GrUniqueKey::GenerateDomain(), 0); +} + +// The cache listens for these messages to purge junk resources proactively. +class GrUniqueKeyInvalidatedMessage { +public: + GrUniqueKeyInvalidatedMessage(const GrUniqueKey& key, uint32_t contextUniqueID) + : fKey(key), fContextID(contextUniqueID) { + SkASSERT(SK_InvalidUniqueID != contextUniqueID); + } + + GrUniqueKeyInvalidatedMessage(const GrUniqueKeyInvalidatedMessage&) = default; + + GrUniqueKeyInvalidatedMessage& operator=(const GrUniqueKeyInvalidatedMessage&) = default; + + const GrUniqueKey& key() const { return fKey; } + uint32_t contextID() const { return fContextID; } + +private: + GrUniqueKey fKey; + uint32_t fContextID; +}; + +static inline bool SkShouldPostMessageToBus( + const GrUniqueKeyInvalidatedMessage& msg, uint32_t msgBusUniqueID) { + return msg.contextID() == msgBusUniqueID; +} + +#endif diff --git a/skia/include/gpu/GrSamplerState.h b/skia/include/gpu/GrSamplerState.h new file mode 100644 index 00000000..75f68912 --- /dev/null +++ b/skia/include/gpu/GrSamplerState.h @@ -0,0 +1,69 @@ +/* + * 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 GrSamplerState_DEFINED +#define GrSamplerState_DEFINED + +#include "GrTypes.h" + +/** + * Represents the filtering and tile modes used to access a texture. + */ +class GrSamplerState { +public: + enum class Filter : uint8_t { kNearest, kBilerp, kMipMap }; + enum class WrapMode : uint8_t { kClamp, kRepeat, kMirrorRepeat }; + + static constexpr GrSamplerState ClampNearest() { return GrSamplerState(); } + static constexpr GrSamplerState ClampBilerp() { + return GrSamplerState(WrapMode::kClamp, Filter::kBilerp); + } + + constexpr GrSamplerState() : GrSamplerState(WrapMode::kClamp, Filter::kNearest) {} + + constexpr GrSamplerState(WrapMode wrapXAndY, Filter filter) + : fWrapModes{wrapXAndY, wrapXAndY}, fFilter(filter) {} + + constexpr GrSamplerState(const WrapMode wrapModes[2], Filter filter) + : fWrapModes{wrapModes[0], wrapModes[1]}, fFilter(filter) {} + + constexpr GrSamplerState(const GrSamplerState&) = default; + + GrSamplerState& operator=(const GrSamplerState& that) { + fWrapModes[0] = that.fWrapModes[0]; + fWrapModes[1] = that.fWrapModes[1]; + fFilter = that.fFilter; + return *this; + } + + Filter filter() const { return fFilter; } + + void setFilterMode(Filter filterMode) { fFilter = filterMode; } + + void setWrapModeX(const WrapMode wrap) { fWrapModes[0] = wrap; } + void setWrapModeY(const WrapMode wrap) { fWrapModes[1] = wrap; } + + WrapMode wrapModeX() const { return fWrapModes[0]; } + WrapMode wrapModeY() const { return fWrapModes[1]; } + + bool isRepeated() const { + return WrapMode::kClamp != fWrapModes[0] || WrapMode::kClamp != fWrapModes[1]; + } + + bool operator==(const GrSamplerState& that) const { + return fWrapModes[0] == that.fWrapModes[0] && fWrapModes[1] == that.fWrapModes[1] && + fFilter == that.fFilter; + } + + bool operator!=(const GrSamplerState& that) const { return !(*this == that); } + +private: + WrapMode fWrapModes[2]; + Filter fFilter; +}; + +#endif diff --git a/skia/include/gpu/GrSurface.h b/skia/include/gpu/GrSurface.h new file mode 100644 index 00000000..bcd854f1 --- /dev/null +++ b/skia/include/gpu/GrSurface.h @@ -0,0 +1,123 @@ +/* + * 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 GrSurface_DEFINED +#define GrSurface_DEFINED + +#include "GrTypes.h" +#include "GrBackendSurface.h" +#include "GrGpuResource.h" +#include "SkImageInfo.h" +#include "SkRect.h" + +class GrRenderTarget; +class GrSurfacePriv; +class GrTexture; + +class SK_API GrSurface : public GrGpuResource { +public: + /** + * Retrieves the width of the surface. + */ + int width() const { return fWidth; } + + /** + * Retrieves the height of the surface. + */ + int height() const { return fHeight; } + + /** + * Helper that gets the width and height of the surface as a bounding rectangle. + */ + SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); } + + /** + * Retrieves the pixel config specified when the surface was created. + * For render targets this can be kUnknown_GrPixelConfig + * if client asked us to render to a target that has a pixel + * config that isn't equivalent with one of our configs. + */ + GrPixelConfig config() const { return fConfig; } + + virtual GrBackendFormat backendFormat() const = 0; + + /** + * @return the texture associated with the surface, may be null. + */ + virtual GrTexture* asTexture() { return nullptr; } + virtual const GrTexture* asTexture() const { return nullptr; } + + /** + * @return the render target underlying this surface, may be null. + */ + virtual GrRenderTarget* asRenderTarget() { return nullptr; } + virtual const GrRenderTarget* asRenderTarget() const { return nullptr; } + + /** Access methods that are only to be used within Skia code. */ + inline GrSurfacePriv surfacePriv(); + inline const GrSurfacePriv surfacePriv() const; + + static size_t WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2 = false); + static size_t ComputeSize(GrPixelConfig config, int width, int height, int colorSamplesPerPixel, + GrMipMapped, bool useNextPow2 = false); + +protected: + void setHasMixedSamples() { + SkASSERT(this->asRenderTarget()); + fSurfaceFlags |= GrInternalSurfaceFlags::kMixedSampled; + } + bool hasMixedSamples() const { return fSurfaceFlags & GrInternalSurfaceFlags::kMixedSampled; } + + void setSupportsWindowRects() { + SkASSERT(this->asRenderTarget()); + fSurfaceFlags |= GrInternalSurfaceFlags::kWindowRectsSupport; + } + bool supportsWindowRects() const { + return fSurfaceFlags & GrInternalSurfaceFlags::kWindowRectsSupport; + } + + void setGLRTFBOIDIs0() { + SkASSERT(this->asRenderTarget()); + fSurfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; + } + bool glRTFBOIDis0() const { + return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0; + } + + // Methods made available via GrSurfacePriv + bool hasPendingRead() const; + bool hasPendingWrite() const; + bool hasPendingIO() const; + + // Provides access to methods that should be public within Skia code. + friend class GrSurfacePriv; + + GrSurface(GrGpu* gpu, const GrSurfaceDesc& desc) + : INHERITED(gpu) + , fConfig(desc.fConfig) + , fWidth(desc.fWidth) + , fHeight(desc.fHeight) + , fSurfaceFlags(GrInternalSurfaceFlags::kNone) { + } + + ~GrSurface() override {} + + void onRelease() override; + void onAbandon() override; + +private: + const char* getResourceType() const override { return "Surface"; } + + GrPixelConfig fConfig; + int fWidth; + int fHeight; + GrInternalSurfaceFlags fSurfaceFlags; + + typedef GrGpuResource INHERITED; +}; + +#endif diff --git a/skia/include/gpu/GrTexture.h b/skia/include/gpu/GrTexture.h new file mode 100644 index 00000000..c1ed58b8 --- /dev/null +++ b/skia/include/gpu/GrTexture.h @@ -0,0 +1,86 @@ + +/* + * 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 GrTexture_DEFINED +#define GrTexture_DEFINED + +#include "GrBackendSurface.h" +#include "GrSamplerState.h" +#include "GrSurface.h" +#include "SkImage.h" +#include "SkPoint.h" +#include "SkRefCnt.h" +#include "../private/GrTypesPriv.h" + +class GrTexturePriv; + +class GrTexture : virtual public GrSurface { +public: + GrTexture* asTexture() override { return this; } + const GrTexture* asTexture() const override { return this; } + + virtual GrBackendTexture getBackendTexture() const = 0; + + /** + * This function indicates that the texture parameters (wrap mode, filtering, ...) have been + * changed externally to Skia. + */ + virtual void textureParamsModified() = 0; + + /** + * This function steals the backend texture from a uniquely owned GrTexture with no pending + * IO, passing it out to the caller. The GrTexture is deleted in the process. + * + * Note that if the GrTexture is not uniquely owned (no other refs), or has pending IO, this + * function will fail. + */ + static bool StealBackendTexture(sk_sp&&, + GrBackendTexture*, + SkImage::BackendTextureReleaseProc*); + +#ifdef SK_DEBUG + void validate() const { + this->INHERITED::validate(); + } +#endif + + virtual void setRelease(sk_sp releaseHelper) = 0; + + // These match the definitions in SkImage, from whence they came. + // TODO: Either move Chrome over to new api or remove their need to call this on GrTexture + typedef void* ReleaseCtx; + typedef void (*ReleaseProc)(ReleaseCtx); + void setRelease(ReleaseProc proc, ReleaseCtx ctx) { + sk_sp helper(new GrReleaseProcHelper(proc, ctx)); + this->setRelease(std::move(helper)); + } + + /** Access methods that are only to be used within Skia code. */ + inline GrTexturePriv texturePriv(); + inline const GrTexturePriv texturePriv() const; + +protected: + GrTexture(GrGpu*, const GrSurfaceDesc&, GrTextureType, GrMipMapsStatus); + + virtual bool onStealBackendTexture(GrBackendTexture*, SkImage::BackendTextureReleaseProc*) = 0; + +private: + void computeScratchKey(GrScratchKey*) const override; + size_t onGpuMemorySize() const override; + void markMipMapsDirty(); + void markMipMapsClean(); + + GrTextureType fTextureType; + GrMipMapsStatus fMipMapsStatus; + int fMaxMipMapLevel; + friend class GrTexturePriv; + + typedef GrSurface INHERITED; +}; + +#endif diff --git a/skia/include/gpu/GrTypes.h b/skia/include/gpu/GrTypes.h new file mode 100644 index 00000000..6082d971 --- /dev/null +++ b/skia/include/gpu/GrTypes.h @@ -0,0 +1,271 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrTypes_DEFINED +#define GrTypes_DEFINED + +#include "SkMath.h" +#include "SkTypes.h" +#include "GrConfig.h" + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Defines overloaded bitwise operators to make it easier to use an enum as a + * bitfield. + */ +#define GR_MAKE_BITFIELD_OPS(X) \ + inline X operator |(X a, X b) { \ + return (X) (+a | +b); \ + } \ + inline X& operator |=(X& a, X b) { \ + return (a = a | b); \ + } \ + inline X operator &(X a, X b) { \ + return (X) (+a & +b); \ + } \ + inline X& operator &=(X& a, X b) { \ + return (a = a & b); \ + } \ + template \ + inline X operator &(T a, X b) { \ + return (X) (+a & +b); \ + } \ + template \ + inline X operator &(X a, T b) { \ + return (X) (+a & +b); \ + } \ + +#define GR_DECL_BITFIELD_OPS_FRIENDS(X) \ + friend X operator |(X a, X b); \ + friend X& operator |=(X& a, X b); \ + \ + friend X operator &(X a, X b); \ + friend X& operator &=(X& a, X b); \ + \ + template \ + friend X operator &(T a, X b); \ + \ + template \ + friend X operator &(X a, T b); \ + +/** + * Wraps a C++11 enum that we use as a bitfield, and enables a limited amount of + * masking with type safety. Instantiated with the ~ operator. + */ +template class GrTFlagsMask { +public: + constexpr explicit GrTFlagsMask(TFlags value) : GrTFlagsMask(static_cast(value)) {} + constexpr explicit GrTFlagsMask(int value) : fValue(value) {} + constexpr int value() const { return fValue; } +private: + const int fValue; +}; + +// Or-ing a mask always returns another mask. +template constexpr GrTFlagsMask operator|(GrTFlagsMask a, + GrTFlagsMask b) { + return GrTFlagsMask(a.value() | b.value()); +} +template constexpr GrTFlagsMask operator|(GrTFlagsMask a, + TFlags b) { + return GrTFlagsMask(a.value() | static_cast(b)); +} +template constexpr GrTFlagsMask operator|(TFlags a, + GrTFlagsMask b) { + return GrTFlagsMask(static_cast(a) | b.value()); +} +template inline GrTFlagsMask& operator|=(GrTFlagsMask& a, + GrTFlagsMask b) { + return (a = a | b); +} + +// And-ing two masks returns another mask; and-ing one with regular flags returns flags. +template constexpr GrTFlagsMask operator&(GrTFlagsMask a, + GrTFlagsMask b) { + return GrTFlagsMask(a.value() & b.value()); +} +template constexpr TFlags operator&(GrTFlagsMask a, TFlags b) { + return static_cast(a.value() & static_cast(b)); +} +template constexpr TFlags operator&(TFlags a, GrTFlagsMask b) { + return static_cast(static_cast(a) & b.value()); +} +template inline TFlags& operator&=(TFlags& a, GrTFlagsMask b) { + return (a = a & b); +} + +/** + * Defines bitwise operators that make it possible to use an enum class as a + * basic bitfield. + */ +#define GR_MAKE_BITFIELD_CLASS_OPS(X) \ + constexpr GrTFlagsMask operator~(X a) { \ + return GrTFlagsMask(~static_cast(a)); \ + } \ + constexpr X operator|(X a, X b) { \ + return static_cast(static_cast(a) | static_cast(b)); \ + } \ + inline X& operator|=(X& a, X b) { \ + return (a = a | b); \ + } \ + constexpr bool operator&(X a, X b) { \ + return SkToBool(static_cast(a) & static_cast(b)); \ + } \ + +#define GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \ + friend constexpr GrTFlagsMask operator ~(X); \ + friend constexpr X operator |(X, X); \ + friend X& operator |=(X&, X); \ + friend constexpr bool operator &(X, X); + +//////////////////////////////////////////////////////////////////////////////// + +// compile time versions of min/max +#define GR_CT_MAX(a, b) (((b) < (a)) ? (a) : (b)) +#define GR_CT_MIN(a, b) (((b) < (a)) ? (b) : (a)) + +/** + * divide, rounding up + */ +static inline int32_t GrIDivRoundUp(int x, int y) { + SkASSERT(y > 0); + return (x + (y-1)) / y; +} +static inline uint32_t GrUIDivRoundUp(uint32_t x, uint32_t y) { + return (x + (y-1)) / y; +} +static inline size_t GrSizeDivRoundUp(size_t x, size_t y) { + return (x + (y-1)) / y; +} + +// compile time, evaluates Y multiple times +#define GR_CT_DIV_ROUND_UP(X, Y) (((X) + ((Y)-1)) / (Y)) + +/** + * align up + */ +static inline uint32_t GrUIAlignUp(uint32_t x, uint32_t alignment) { + return GrUIDivRoundUp(x, alignment) * alignment; +} +static inline size_t GrSizeAlignUp(size_t x, size_t alignment) { + return GrSizeDivRoundUp(x, alignment) * alignment; +} + +// compile time, evaluates A multiple times +#define GR_CT_ALIGN_UP(X, A) (GR_CT_DIV_ROUND_UP((X),(A)) * (A)) + +/** + * amount of pad needed to align up + */ +static inline uint32_t GrUIAlignUpPad(uint32_t x, uint32_t alignment) { + return (alignment - x % alignment) % alignment; +} +static inline size_t GrSizeAlignUpPad(size_t x, size_t alignment) { + return (alignment - x % alignment) % alignment; +} + +/** + * align down + */ +static inline uint32_t GrUIAlignDown(uint32_t x, uint32_t alignment) { + return (x / alignment) * alignment; +} +static inline size_t GrSizeAlignDown(size_t x, uint32_t alignment) { + return (x / alignment) * alignment; +} + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Possible 3D APIs that may be used by Ganesh. + */ +enum class GrBackendApi : unsigned { + kMetal, + kOpenGL, + kVulkan, + /** + * Mock is a backend that does not draw anything. It is used for unit tests + * and to measure CPU overhead. + */ + kMock, + + /** + * Added here to support the legacy GrBackend enum value and clients who referenced it using + * GrBackend::kOpenGL_GrBackend. + */ + kOpenGL_GrBackend = kOpenGL, +}; + +/** + * Previously the above enum was not an enum class but a normal enum. To support the legacy use of + * the enum values we define them below so that no clients break. + */ +typedef GrBackendApi GrBackend; + +static constexpr GrBackendApi kMetal_GrBackend = GrBackendApi::kMetal; +static constexpr GrBackendApi kVulkan_GrBackend = GrBackendApi::kVulkan; +static constexpr GrBackendApi kMock_GrBackend = GrBackendApi::kMock; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Used to say whether a texture has mip levels allocated or not. + */ +enum class GrMipMapped : bool { + kNo = false, + kYes = true +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * GPU SkImage and SkSurfaces can be stored such that (0, 0) in texture space may correspond to + * either the top-left or bottom-left content pixel. + */ +enum GrSurfaceOrigin : int { + kTopLeft_GrSurfaceOrigin, + kBottomLeft_GrSurfaceOrigin, +}; + +/** + * A GrContext's cache of backend context state can be partially invalidated. + * These enums are specific to the GL backend and we'd add a new set for an alternative backend. + */ +enum GrGLBackendState { + kRenderTarget_GrGLBackendState = 1 << 0, + // Also includes samplers bound to texture units. + kTextureBinding_GrGLBackendState = 1 << 1, + // View state stands for scissor and viewport + kView_GrGLBackendState = 1 << 2, + kBlend_GrGLBackendState = 1 << 3, + kMSAAEnable_GrGLBackendState = 1 << 4, + kVertex_GrGLBackendState = 1 << 5, + kStencil_GrGLBackendState = 1 << 6, + kPixelStore_GrGLBackendState = 1 << 7, + kProgram_GrGLBackendState = 1 << 8, + kFixedFunction_GrGLBackendState = 1 << 9, + kMisc_GrGLBackendState = 1 << 10, + kPathRendering_GrGLBackendState = 1 << 11, + kALL_GrGLBackendState = 0xffff +}; + +/** + * This value translates to reseting all the context state for any backend. + */ +static const uint32_t kAll_GrBackendState = 0xffffffff; + +/** + * Enum used as return value when flush with semaphores so the client knows whether the semaphores + * were submitted to GPU or not. + */ +enum class GrSemaphoresSubmitted : bool { + kNo = false, + kYes = true +}; + +#endif diff --git a/skia/include/gpu/gl/GrGLAssembleInterface.h b/skia/include/gpu/gl/GrGLAssembleInterface.h new file mode 100644 index 00000000..42f842e2 --- /dev/null +++ b/skia/include/gpu/gl/GrGLAssembleInterface.h @@ -0,0 +1,32 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gl/GrGLInterface.h" + +typedef GrGLFuncPtr (*GrGLGetProc)(void* ctx, const char name[]); + +/** + * Generic function for creating a GrGLInterface for an either OpenGL or GLES. It calls + * get() to get each function address. ctx is a generic ptr passed to and interpreted by get(). + */ +SK_API sk_sp GrGLMakeAssembledInterface(void *ctx, GrGLGetProc get); + +/** + * Generic function for creating a GrGLInterface for an OpenGL (but not GLES) context. It calls + * get() to get each function address. ctx is a generic ptr passed to and interpreted by get(). + */ +SK_API sk_sp GrGLMakeAssembledGLInterface(void *ctx, GrGLGetProc get); + +/** + * Generic function for creating a GrGLInterface for an OpenGL ES (but not Open GL) context. It + * calls get() to get each function address. ctx is a generic ptr passed to and interpreted by + * get(). + */ +SK_API sk_sp GrGLMakeAssembledGLESInterface(void *ctx, GrGLGetProc get); + +/** Deprecated version of GrGLMakeAssembledInterface() that returns a bare pointer. */ +SK_API const GrGLInterface* GrGLAssembleInterface(void *ctx, GrGLGetProc get); diff --git a/skia/include/gpu/gl/GrGLConfig.h b/skia/include/gpu/gl/GrGLConfig.h new file mode 100644 index 00000000..1526f06e --- /dev/null +++ b/skia/include/gpu/gl/GrGLConfig.h @@ -0,0 +1,129 @@ + +/* + * 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 GrGLConfig_DEFINED +#define GrGLConfig_DEFINED + +#include "GrTypes.h" + +/** + * Optional GL config file. + */ +#ifdef GR_GL_CUSTOM_SETUP_HEADER + #include GR_GL_CUSTOM_SETUP_HEADER +#endif + +#if !defined(GR_GL_FUNCTION_TYPE) + #if defined(SK_BUILD_FOR_WIN) + #define GR_GL_FUNCTION_TYPE __stdcall + #else + #define GR_GL_FUNCTION_TYPE + #endif +#endif + +/** + * The following are optional defines that can be enabled at the compiler + * command line, in a IDE project, in a GrUserConfig.h file, or in a GL custom + * file (if one is in use). If a GR_GL_CUSTOM_SETUP_HEADER is used they can + * also be placed there. + * + * GR_GL_LOG_CALLS: if 1 Gr can print every GL call using SkDebugf. Defaults to + * 0. Logging can be enabled and disabled at runtime using a debugger via to + * global gLogCallsGL. The initial value of gLogCallsGL is controlled by + * GR_GL_LOG_CALLS_START. + * + * GR_GL_LOG_CALLS_START: controls the initial value of gLogCallsGL when + * GR_GL_LOG_CALLS is 1. Defaults to 0. + * + * GR_GL_CHECK_ERROR: if enabled Gr can do a glGetError() after every GL call. + * Defaults to 1 if SK_DEBUG is set, otherwise 0. When GR_GL_CHECK_ERROR is 1 + * this can be toggled in a debugger using the gCheckErrorGL global. The initial + * value of gCheckErrorGL is controlled by by GR_GL_CHECK_ERROR_START. + * + * GR_GL_CHECK_ERROR_START: controls the initial value of gCheckErrorGL + * when GR_GL_CHECK_ERROR is 1. Defaults to 1. + * + * GR_GL_USE_BUFFER_DATA_NULL_HINT: When specifing new data for a vertex/index + * buffer that replaces old data Ganesh can give a hint to the driver that the + * previous data will not be used in future draws like this: + * glBufferData(GL_..._BUFFER, size, NULL, usage); //<--hint, NULL means + * glBufferSubData(GL_..._BUFFER, 0, lessThanSize, data) // old data can't be + * // used again. + * However, this can be an unoptimization on some platforms, esp. Chrome. + * Chrome's cmd buffer will create a new allocation and memset the whole thing + * to zero (for security reasons). Defaults to 1 (enabled). + * + * GR_GL_CHECK_ALLOC_WITH_GET_ERROR: If set to 1 this will then glTexImage, + * glBufferData, glRenderbufferStorage, etc will be checked for errors. This + * amounts to ensuring the error is GL_NO_ERROR, calling the allocating + * function, and then checking that the error is still GL_NO_ERROR. When the + * value is 0 we will assume no error was generated without checking. + * + * GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT: We will normally check the FBO status + * every time we bind a texture or renderbuffer to an FBO. However, in some + * environments CheckFrameBufferStatus is very expensive. If this is set we will + * check the first time we use a color format or a combination of color / + * stencil formats as attachments. If the FBO is complete we will assume + * subsequent attachments with the same formats are complete as well. + * + * GR_GL_MUST_USE_VBO: Indicates that all vertices and indices must be rendered + * from VBOs. Chromium's command buffer doesn't allow glVertexAttribArray with + * ARARY_BUFFER 0 bound or glDrawElements with ELEMENT_ARRAY_BUFFER 0 bound. + * + * GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE is for compatibility with the new version + * of the OpenGLES2.0 headers from Khronos. glShaderSource now takes a const char * const *, + * instead of a const char + */ + +#if !defined(GR_GL_LOG_CALLS) + #ifdef SK_DEBUG + #define GR_GL_LOG_CALLS 1 + #else + #define GR_GL_LOG_CALLS 0 + #endif +#endif + +#if !defined(GR_GL_LOG_CALLS_START) + #define GR_GL_LOG_CALLS_START 0 +#endif + +#if !defined(GR_GL_CHECK_ERROR) + #ifdef SK_DEBUG + #define GR_GL_CHECK_ERROR 1 + #else + #define GR_GL_CHECK_ERROR 0 + #endif +#endif + +#if !defined(GR_GL_CHECK_ERROR_START) + #define GR_GL_CHECK_ERROR_START 1 +#endif + +#if !defined(GR_GL_USE_BUFFER_DATA_NULL_HINT) + #define GR_GL_USE_BUFFER_DATA_NULL_HINT 1 +#endif + +#if !defined(GR_GL_CHECK_ALLOC_WITH_GET_ERROR) + #define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 1 +#endif + +#if !defined(GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT) + #define GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT 0 +#endif + +#if !defined(GR_GL_MUST_USE_VBO) + #define GR_GL_MUST_USE_VBO 0 +#endif + +#if !defined(GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE) + #define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE 0 +#endif + +#endif diff --git a/skia/include/gpu/gl/GrGLConfig_chrome.h b/skia/include/gpu/gl/GrGLConfig_chrome.h new file mode 100644 index 00000000..838e0543 --- /dev/null +++ b/skia/include/gpu/gl/GrGLConfig_chrome.h @@ -0,0 +1,36 @@ + +/* + * 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 GrGLConfig_chrome_DEFINED +#define GrGLConfig_chrome_DEFINED + +// glGetError() forces a sync with gpu process on chrome +#define GR_GL_CHECK_ERROR_START 0 + +// cmd buffer allocates memory and memsets it to zero when it sees glBufferData +// with NULL. +#define GR_GL_USE_BUFFER_DATA_NULL_HINT 0 + +// Check error is even more expensive in chrome (cmd buffer flush). The +// compositor also doesn't check its allocations. +#define GR_GL_CHECK_ALLOC_WITH_GET_ERROR 0 + +// CheckFramebufferStatus in chrome synchronizes the gpu and renderer processes. +#define GR_GL_CHECK_FBO_STATUS_ONCE_PER_FORMAT 1 + +// Non-VBO vertices and indices are not allowed in Chromium. +#define GR_GL_MUST_USE_VBO 1 + +// Use updated Khronos signature for glShaderSource +// (const char* const instead of char**). +#define GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE 1 + +#if !defined(GR_GL_IGNORE_ES3_MSAA) + #define GR_GL_IGNORE_ES3_MSAA 1 +#endif + +#endif diff --git a/skia/include/gpu/gl/GrGLExtensions.h b/skia/include/gpu/gl/GrGLExtensions.h new file mode 100644 index 00000000..6a41ed91 --- /dev/null +++ b/skia/include/gpu/gl/GrGLExtensions.h @@ -0,0 +1,78 @@ +/* + * 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 GrGLExtensions_DEFINED +#define GrGLExtensions_DEFINED + +#include "../../private/SkTArray.h" +#include "GrGLFunctions.h" +#include "SkString.h" + +#include + +struct GrGLInterface; +class SkJSONWriter; + +/** + * This helper queries the current GL context for its extensions, remembers them, and can be + * queried. It supports both glGetString- and glGetStringi-style extension string APIs and will + * use the latter if it is available. It also will query for EGL extensions if a eglQueryString + * implementation is provided. + */ +class SK_API GrGLExtensions { +public: + GrGLExtensions() {} + + GrGLExtensions(const GrGLExtensions&); + + GrGLExtensions& operator=(const GrGLExtensions&); + + void swap(GrGLExtensions* that) { + using std::swap; + swap(fStrings, that->fStrings); + swap(fInitialized, that->fInitialized); + } + + /** + * We sometimes need to use this class without having yet created a GrGLInterface. This version + * of init expects that getString is always non-NULL while getIntegerv and getStringi are non- + * NULL if on desktop GL with version 3.0 or higher. Otherwise it will fail. + */ + bool init(GrGLStandard standard, + GrGLFunction getString, + GrGLFunction getStringi, + GrGLFunction getIntegerv, + GrGLFunction queryString = nullptr, + GrEGLDisplay eglDisplay = nullptr); + + bool isInitialized() const { return fInitialized; } + + /** + * Queries whether an extension is present. This will fail if init() has not been called. + */ + bool has(const char[]) const; + + /** + * Removes an extension if present. Returns true if the extension was present before the call. + */ + bool remove(const char[]); + + /** + * Adds an extension to list + */ + void add(const char[]); + + void reset() { fStrings.reset(); } + + void dumpJSON(SkJSONWriter*) const; + +private: + bool fInitialized = false; + SkTArray fStrings; +}; + +#endif diff --git a/skia/include/gpu/gl/GrGLFunctions.h b/skia/include/gpu/gl/GrGLFunctions.h new file mode 100644 index 00000000..a677efbb --- /dev/null +++ b/skia/include/gpu/gl/GrGLFunctions.h @@ -0,0 +1,323 @@ + +/* + * 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 GrGLFunctions_DEFINED +#define GrGLFunctions_DEFINED + +#include +#include "../private/SkTLogic.h" +#include "GrGLTypes.h" + + +extern "C" { + +/////////////////////////////////////////////////////////////////////////////// + +using GrGLActiveTextureFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum texture); +using GrGLAttachShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint shader); +using GrGLBeginQueryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint id); +using GrGLBindAttribLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint index, const char* name); +using GrGLBindBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint buffer); +using GrGLBindFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint framebuffer); +using GrGLBindRenderbufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint renderbuffer); +using GrGLBindTextureFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLuint texture); +using GrGLBindFragDataLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint colorNumber, const GrGLchar* name); +using GrGLBindFragDataLocationIndexedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLuint colorNumber, GrGLuint index, const GrGLchar* name); +using GrGLBindSamplerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint unit, GrGLuint sampler); +using GrGLBindVertexArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint array); +using GrGLBlendBarrierFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLBlendColorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); +using GrGLBlendEquationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLBlendFuncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum sfactor, GrGLenum dfactor); +using GrGLBlitFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint srcX0, GrGLint srcY0, GrGLint srcX1, GrGLint srcY1, GrGLint dstX0, GrGLint dstY0, GrGLint dstX1, GrGLint dstY1, GrGLbitfield mask, GrGLenum filter); +using GrGLBufferDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data, GrGLenum usage); +using GrGLBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr size, const GrGLvoid* data); +using GrGLCheckFramebufferStatusFn = GrGLenum GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLClearFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLbitfield mask); +using GrGLClearColorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha); +using GrGLClearStencilFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint s); +using GrGLClearTexImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLenum format, GrGLenum type, const GrGLvoid* data); +using GrGLClearTexSubImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint zoffset, GrGLsizei width, GrGLsizei height, GrGLsizei depth, GrGLenum format, GrGLenum type, const GrGLvoid* data); +using GrGLColorMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha); +using GrGLCompileShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader); +using GrGLCompressedTexImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLenum internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLsizei imageSize, const GrGLvoid* data); +using GrGLCompressedTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLsizei imageSize, const GrGLvoid* data); +using GrGLCopyTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +using GrGLCreateProgramFn = GrGLuint GR_GL_FUNCTION_TYPE(); +using GrGLCreateShaderFn = GrGLuint GR_GL_FUNCTION_TYPE(GrGLenum type); +using GrGLCullFaceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLDeleteBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* buffers); +using GrGLDeleteFramebuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* framebuffers); +using GrGLDeleteProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLDeleteQueriesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* ids); +using GrGLDeleteRenderbuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* renderbuffers); +using GrGLDeleteSamplersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei count, const GrGLuint* samplers); +using GrGLDeleteShaderFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader); +using GrGLDeleteTexturesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* textures); +using GrGLDeleteVertexArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLuint* arrays); +using GrGLDepthMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLboolean flag); +using GrGLDisableFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum cap); +using GrGLDisableVertexAttribArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index); +using GrGLDrawArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLint first, GrGLsizei count); +using GrGLDrawArraysInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLint first, GrGLsizei count, GrGLsizei primcount); +using GrGLDrawArraysIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLvoid* indirect); +using GrGLDrawBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLDrawBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, const GrGLenum* bufs); +using GrGLDrawElementsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); +using GrGLDrawElementsInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices, GrGLsizei primcount); +using GrGLDrawElementsIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLenum type, const GrGLvoid* indirect); +using GrGLDrawRangeElementsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLuint start, GrGLuint end, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); +using GrGLEnableFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum cap); +using GrGLEnableVertexAttribArrayFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index); +using GrGLEndQueryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLFinishFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLFlushFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLFlushMappedBufferRangeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length); +using GrGLFramebufferRenderbufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer); +using GrGLFramebufferTexture2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level); +using GrGLFramebufferTexture2DMultisampleFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level, GrGLsizei samples); +using GrGLFrontFaceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode); +using GrGLGenBuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* buffers); +using GrGLGenFramebuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* framebuffers); +using GrGLGenerateMipmapFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLGenQueriesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* ids); +using GrGLGenRenderbuffersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* renderbuffers); +using GrGLGenSamplersFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei count, GrGLuint* samplers); +using GrGLGenTexturesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* textures); +using GrGLGenVertexArraysFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei n, GrGLuint* arrays); +using GrGLGetBufferParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint* params); +using GrGLGetErrorFn = GrGLenum GR_GL_FUNCTION_TYPE(); +using GrGLGetFramebufferAttachmentParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum attachment, GrGLenum pname, GrGLint* params); +using GrGLGetIntegervFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint* params); +using GrGLGetMultisamplefvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLuint index, GrGLfloat* val); +using GrGLGetProgramBinaryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, GrGLenum* binaryFormat, void* binary); +using GrGLGetProgramInfoLogFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length, char* infolog); +using GrGLGetProgramivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum pname, GrGLint* params); +using GrGLGetQueryivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum GLtarget, GrGLenum pname, GrGLint* params); +using GrGLGetQueryObjecti64vFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLint64* params); +using GrGLGetQueryObjectivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLint* params); +using GrGLGetQueryObjectui64vFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLuint64* params); +using GrGLGetQueryObjectuivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum pname, GrGLuint* params); +using GrGLGetRenderbufferParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint* params); +using GrGLGetShaderInfoLogFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length, char* infolog); +using GrGLGetShaderivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLenum pname, GrGLint* params); +using GrGLGetShaderPrecisionFormatFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum shadertype, GrGLenum precisiontype, GrGLint* range, GrGLint* precision); +using GrGLGetStringFn = const GrGLubyte* GR_GL_FUNCTION_TYPE(GrGLenum name); +using GrGLGetStringiFn = const GrGLubyte* GR_GL_FUNCTION_TYPE(GrGLenum name, GrGLuint index); +using GrGLGetTexLevelParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLenum pname, GrGLint* params); +using GrGLGetUniformLocationFn = GrGLint GR_GL_FUNCTION_TYPE(GrGLuint program, const char* name); +using GrGLInsertEventMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei length, const char* marker); +using GrGLInvalidateBufferDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint buffer); +using GrGLInvalidateBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length); +using GrGLInvalidateFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); +using GrGLInvalidateSubFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments, GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +using GrGLInvalidateTexImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level); +using GrGLInvalidateTexSubImageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint texture, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint zoffset, GrGLsizei width, GrGLsizei height, GrGLsizei depth); +using GrGLIsTextureFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLuint texture); +using GrGLLineWidthFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLfloat width); +using GrGLLinkProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLMapBufferFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum access); +using GrGLMapBufferRangeFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access); +using GrGLMapBufferSubDataFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLuint target, GrGLintptr offset, GrGLsizeiptr size, GrGLenum access); +using GrGLMapTexSubImage2DFn = GrGLvoid* GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLenum access); +using GrGLPixelStoreiFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum pname, GrGLint param); +using GrGLPolygonModeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum mode); +using GrGLPopGroupMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLProgramBinaryFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum binaryFormat, void* binary, GrGLsizei length); +using GrGLProgramParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum pname, GrGLint value); +using GrGLPushGroupMarkerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei length, const char* marker); +using GrGLQueryCounterFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint id, GrGLenum target); +using GrGLRasterSamplesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint samples, GrGLboolean fixedsamplelocations); +using GrGLReadBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum src); +using GrGLReadPixelsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels); +using GrGLRenderbufferStorageFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLRenderbufferStorageMultisampleFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei samples, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLResolveMultisampleFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLSamplerParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint sampler, GrGLenum pname, GrGLint params); +using GrGLSamplerParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint sampler, GrGLenum pname, const GrGLint* params); +using GrGLScissorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); +// GL_CHROMIUM_bind_uniform_location +using GrGLBindUniformLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLint location, const char* name); + +#if GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE +using GrGLShaderSourceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLsizei count, const char* const* str, const GrGLint* length); +#else +using GrGLShaderSourceFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint shader, GrGLsizei count, const char** str, const GrGLint* length); +#endif +using GrGLStencilFuncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum func, GrGLint ref, GrGLuint mask); +using GrGLStencilFuncSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum func, GrGLint ref, GrGLuint mask); +using GrGLStencilMaskFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint mask); +using GrGLStencilMaskSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLuint mask); +using GrGLStencilOpFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum fail, GrGLenum zfail, GrGLenum zpass); +using GrGLStencilOpSeparateFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass); +using GrGLTexBufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLuint buffer); +using GrGLTexBufferRangeFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr size); +using GrGLTexImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); +using GrGLTexParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, GrGLint param); +using GrGLTexParameterivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum pname, const GrGLint* params); +using GrGLTexStorage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei levels, GrGLenum internalformat, GrGLsizei width, GrGLsizei height); +using GrGLDiscardFramebufferFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); +using GrGLTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); +using GrGLTextureBarrierFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLUniform1fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0); +using GrGLUniform1iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0); +using GrGLUniform1fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform1ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform2fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1); +using GrGLUniform2iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1); +using GrGLUniform2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform2ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform3fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2); +using GrGLUniform3iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2); +using GrGLUniform3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform3ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniform4fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2, GrGLfloat v3); +using GrGLUniform4iFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLint v0, GrGLint v1, GrGLint v2, GrGLint v3); +using GrGLUniform4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLfloat* v); +using GrGLUniform4ivFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, const GrGLint* v); +using GrGLUniformMatrix2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUniformMatrix3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUniformMatrix4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint location, GrGLsizei count, GrGLboolean transpose, const GrGLfloat* value); +using GrGLUnmapBufferFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLenum target); +using GrGLUnmapBufferSubDataFn = GrGLvoid GR_GL_FUNCTION_TYPE(const GrGLvoid* mem); +using GrGLUnmapTexSubImage2DFn = GrGLvoid GR_GL_FUNCTION_TYPE(const GrGLvoid* mem); +using GrGLUseProgramFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program); +using GrGLVertexAttrib1fFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat value); +using GrGLVertexAttrib2fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttrib3fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttrib4fvFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, const GrGLfloat* values); +using GrGLVertexAttribDivisorFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint index, GrGLuint divisor); +using GrGLVertexAttribIPointerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* ptr); +using GrGLVertexAttribPointerFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint indx, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const GrGLvoid* ptr); +using GrGLViewportFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height); + +/* GL_NV_path_rendering */ +using GrGLMatrixLoadfFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum matrixMode, const GrGLfloat* m); +using GrGLMatrixLoadIdentityFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum); +using GrGLPathCommandsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLsizei numCommands, const GrGLubyte* commands, GrGLsizei numCoords, GrGLenum coordType, const GrGLvoid* coords); +using GrGLPathParameteriFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLenum pname, GrGLint value); +using GrGLPathParameterfFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLenum pname, GrGLfloat value); +using GrGLGenPathsFn = GrGLuint GR_GL_FUNCTION_TYPE(GrGLsizei range); +using GrGLDeletePathsFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLsizei range); +using GrGLIsPathFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLuint path); +using GrGLPathStencilFuncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum func, GrGLint ref, GrGLuint mask); +using GrGLStencilFillPathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLenum fillMode, GrGLuint mask); +using GrGLStencilStrokePathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLint reference, GrGLuint mask); +using GrGLStencilFillPathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum transformType, const GrGLfloat* transformValues); +using GrGLStencilStrokePathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum transformType, const GrGLfloat* transformValues); +using GrGLCoverFillPathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLenum coverMode); +using GrGLCoverStrokePathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint name, GrGLenum coverMode); +using GrGLCoverFillPathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues); +using GrGLCoverStrokePathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues); +// NV_path_rendering v1.2 +using GrGLStencilThenCoverFillPathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode); +using GrGLStencilThenCoverStrokePathFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint path, GrGLint reference, GrGLuint mask, GrGLenum coverMode); +using GrGLStencilThenCoverFillPathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues); +using GrGLStencilThenCoverStrokePathInstancedFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid* paths, GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues); +// NV_path_rendering v1.3 +using GrGLProgramPathFragmentInputGenFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLint location, GrGLenum genMode, GrGLint components, const GrGLfloat* coeffs); +// CHROMIUM_path_rendering +using GrGLBindFragmentInputLocationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLint location, const GrGLchar* name); + +/* ARB_program_interface_query */ +using GrGLGetProgramResourceLocationFn = GrGLint GR_GL_FUNCTION_TYPE(GrGLuint program, GrGLenum programInterface, const GrGLchar* name); + +/* GL_NV_framebuffer_mixed_samples */ +using GrGLCoverageModulationFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum components); + +/* EXT_multi_draw_indirect */ +using GrGLMultiDrawArraysIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, const GrGLvoid* indirect, GrGLsizei drawcount, GrGLsizei stride); +using GrGLMultiDrawElementsIndirectFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLenum type, const GrGLvoid* indirect, GrGLsizei drawcount, GrGLsizei stride); + +/* ARB_sample_shading */ +using GrGLMinSampleShadingFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLfloat value); + +/* ARB_sync */ +using GrGLFenceSyncFn = GrGLsync GR_GL_FUNCTION_TYPE(GrGLenum condition, GrGLbitfield flags); +using GrGLIsSyncFn = GrGLboolean GR_GL_FUNCTION_TYPE(GrGLsync sync); +using GrGLClientWaitSyncFn = GrGLenum GR_GL_FUNCTION_TYPE(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +using GrGLWaitSyncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +using GrGLDeleteSyncFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLsync sync); + +/* ARB_internalformat_query */ +using GrGLGetInternalformativFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum target, GrGLenum internalformat, GrGLenum pname, GrGLsizei bufSize, GrGLint* params); + +/* KHR_debug */ +using GrGLDebugMessageControlFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled); +using GrGLDebugMessageInsertFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf); +using GrGLDebugMessageCallbackFn = GrGLvoid GR_GL_FUNCTION_TYPE(GRGLDEBUGPROC callback, const GrGLvoid* userParam); +using GrGLGetDebugMessageLogFn = GrGLuint GR_GL_FUNCTION_TYPE(GrGLuint count, GrGLsizei bufSize, GrGLenum* sources, GrGLenum* types, GrGLuint* ids, GrGLenum* severities, GrGLsizei* lengths, GrGLchar* messageLog); +using GrGLPushDebugGroupFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum source, GrGLuint id, GrGLsizei length, const GrGLchar* message); +using GrGLPopDebugGroupFn = GrGLvoid GR_GL_FUNCTION_TYPE(); +using GrGLObjectLabelFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum identifier, GrGLuint name, GrGLsizei length, const GrGLchar* label); + +/** EXT_window_rectangles */ +using GrGLWindowRectanglesFn = GrGLvoid GR_GL_FUNCTION_TYPE(GrGLenum mode, GrGLsizei count, const GrGLint box[]); + +/** EGL functions */ +using GrEGLQueryStringFn = const char* GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLint name); +using GrEGLGetCurrentDisplayFn = GrEGLDisplay GR_GL_FUNCTION_TYPE(); +using GrEGLCreateImageFn = GrEGLImage GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLContext ctx, GrEGLenum target, GrEGLClientBuffer buffer, const GrEGLint* attrib_list); +using GrEGLDestroyImageFn = GrEGLBoolean GR_GL_FUNCTION_TYPE(GrEGLDisplay dpy, GrEGLImage image); +} // extern "C" + +// This is a lighter-weight std::function, trying to reduce code size and compile time +// by only supporting the exact use cases we require. +template class GrGLFunction; + +template +class GrGLFunction { +public: + using Fn = R GR_GL_FUNCTION_TYPE(Args...); + // Construct empty. + GrGLFunction() = default; + GrGLFunction(std::nullptr_t) {} + + // Construct from a simple function pointer. + GrGLFunction(Fn* fn_ptr) { + static_assert(sizeof(fn_ptr) <= sizeof(fBuf), "fBuf is too small"); + if (fn_ptr) { + memcpy(fBuf, &fn_ptr, sizeof(fn_ptr)); + fCall = [](const void* buf, Args... args) { + return (*(Fn**)buf)(std::forward(args)...); + }; + } + } + + // Construct from a small closure. + template + GrGLFunction(Closure closure) : GrGLFunction() { + static_assert(sizeof(Closure) <= sizeof(fBuf), "fBuf is too small"); +#if defined(__APPLE__) // I am having serious trouble getting these to work with all STLs... + static_assert(std::is_trivially_copyable::value, ""); + static_assert(std::is_trivially_destructible::value, ""); +#endif + + memcpy(fBuf, &closure, sizeof(closure)); + fCall = [](const void* buf, Args... args) { + auto closure = (const Closure*)buf; + return (*closure)(args...); + }; + } + + R operator()(Args... args) const { + SkASSERT(fCall); + return fCall(fBuf, std::forward(args)...); + } + + explicit operator bool() const { return fCall != nullptr; } + + void reset() { fCall = nullptr; } + +private: + using Call = R(const void* buf, Args...); + Call* fCall = nullptr; + size_t fBuf[4]; +}; + +#endif diff --git a/skia/include/gpu/gl/GrGLInterface.h b/skia/include/gpu/gl/GrGLInterface.h new file mode 100644 index 00000000..b0a8d937 --- /dev/null +++ b/skia/include/gpu/gl/GrGLInterface.h @@ -0,0 +1,349 @@ +/* + * 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 GrGLInterface_DEFINED +#define GrGLInterface_DEFINED + +#include "GrGLFunctions.h" +#include "GrGLExtensions.h" +#include "SkRefCnt.h" + +//////////////////////////////////////////////////////////////////////////////// + +typedef void(*GrGLFuncPtr)(); +struct GrGLInterface; + + +/** + * Rather than depend on platform-specific GL headers and libraries, we require + * the client to provide a struct of GL function pointers. This struct can be + * specified per-GrContext as a parameter to GrContext::MakeGL. If no interface is + * passed to MakeGL then a default GL interface is created using GrGLMakeNativeInterface(). + * If this returns nullptr then GrContext::MakeGL() will fail. + * + * The implementation of GrGLMakeNativeInterface is platform-specific. Several + * implementations have been provided (for GLX, WGL, EGL, etc), along with an + * implementation that simply returns nullptr. Clients should select the most + * appropriate one to build. + */ +SK_API sk_sp GrGLMakeNativeInterface(); +// Deprecated alternative to GrGLMakeNativeInterface(). +SK_API const GrGLInterface* GrGLCreateNativeInterface(); + +/** + * Creates a null GrGLInterface that doesn't draw anything. Used for measuring + * CPU overhead. TODO: We would like to move this to tools/gpu/gl/null but currently + * Chromium is using it in its unit tests. + */ +const SK_API GrGLInterface* GrGLCreateNullInterface(bool enableNVPR = false); + +/** + * GrContext uses the following interface to make all calls into OpenGL. When a + * GrContext is created it is given a GrGLInterface. The interface's function + * pointers must be valid for the OpenGL context associated with the GrContext. + * On some platforms, such as Windows, function pointers for OpenGL extensions + * may vary between OpenGL contexts. So the caller must be careful to use a + * GrGLInterface initialized for the correct context. All functions that should + * be available based on the OpenGL's version and extension string must be + * non-NULL or GrContext creation will fail. This can be tested with the + * validate() method when the OpenGL context has been made current. + */ +struct SK_API GrGLInterface : public SkRefCnt { +private: + typedef SkRefCnt INHERITED; + +public: + GrGLInterface(); + + // Validates that the GrGLInterface supports its advertised standard. This means the necessary + // function pointers have been initialized for both the GL version and any advertised + // extensions. + bool validate() const; + + // Indicates the type of GL implementation + union { + GrGLStandard fStandard; + GrGLStandard fBindingsExported; // Legacy name, will be remove when Chromium is updated. + }; + + GrGLExtensions fExtensions; + + bool hasExtension(const char ext[]) const { return fExtensions.has(ext); } + + /** + * The function pointers are in a struct so that we can have a compiler generated assignment + * operator. + */ + struct Functions { + GrGLFunction fActiveTexture; + GrGLFunction fAttachShader; + GrGLFunction fBeginQuery; + GrGLFunction fBindAttribLocation; + GrGLFunction fBindBuffer; + GrGLFunction fBindFragDataLocation; + GrGLFunction fBindFragDataLocationIndexed; + GrGLFunction fBindFramebuffer; + GrGLFunction fBindRenderbuffer; + GrGLFunction fBindSampler; + GrGLFunction fBindTexture; + GrGLFunction fBindVertexArray; + GrGLFunction fBlendBarrier; + GrGLFunction fBlendColor; + GrGLFunction fBlendEquation; + GrGLFunction fBlendFunc; + GrGLFunction fBlitFramebuffer; + GrGLFunction fBufferData; + GrGLFunction fBufferSubData; + GrGLFunction fCheckFramebufferStatus; + GrGLFunction fClear; + GrGLFunction fClearColor; + GrGLFunction fClearStencil; + GrGLFunction fClearTexImage; + GrGLFunction fClearTexSubImage; + GrGLFunction fColorMask; + GrGLFunction fCompileShader; + GrGLFunction fCompressedTexImage2D; + GrGLFunction fCompressedTexSubImage2D; + GrGLFunction fCopyTexSubImage2D; + GrGLFunction fCreateProgram; + GrGLFunction fCreateShader; + GrGLFunction fCullFace; + GrGLFunction fDeleteBuffers; + GrGLFunction fDeleteFramebuffers; + GrGLFunction fDeleteProgram; + GrGLFunction fDeleteQueries; + GrGLFunction fDeleteRenderbuffers; + GrGLFunction fDeleteSamplers; + GrGLFunction fDeleteShader; + GrGLFunction fDeleteTextures; + GrGLFunction fDeleteVertexArrays; + GrGLFunction fDepthMask; + GrGLFunction fDisable; + GrGLFunction fDisableVertexAttribArray; + GrGLFunction fDrawArrays; + GrGLFunction fDrawArraysIndirect; + GrGLFunction fDrawArraysInstanced; + GrGLFunction fDrawBuffer; + GrGLFunction fDrawBuffers; + GrGLFunction fDrawElements; + GrGLFunction fDrawElementsIndirect; + GrGLFunction fDrawElementsInstanced; + GrGLFunction fDrawRangeElements; + GrGLFunction fEnable; + GrGLFunction fEnableVertexAttribArray; + GrGLFunction fEndQuery; + GrGLFunction fFinish; + GrGLFunction fFlush; + GrGLFunction fFlushMappedBufferRange; + GrGLFunction fFramebufferRenderbuffer; + GrGLFunction fFramebufferTexture2D; + GrGLFunction fFramebufferTexture2DMultisample; + GrGLFunction fFrontFace; + GrGLFunction fGenBuffers; + GrGLFunction fGenFramebuffers; + GrGLFunction fGenerateMipmap; + GrGLFunction fGenQueries; + GrGLFunction fGenRenderbuffers; + GrGLFunction fGenSamplers; + GrGLFunction fGenTextures; + GrGLFunction fGenVertexArrays; + GrGLFunction fGetBufferParameteriv; + GrGLFunction fGetError; + GrGLFunction fGetFramebufferAttachmentParameteriv; + GrGLFunction fGetIntegerv; + GrGLFunction fGetMultisamplefv; + GrGLFunction fGetProgramBinary; + GrGLFunction fGetProgramInfoLog; + GrGLFunction fGetProgramiv; + GrGLFunction fGetQueryObjecti64v; + GrGLFunction fGetQueryObjectiv; + GrGLFunction fGetQueryObjectui64v; + GrGLFunction fGetQueryObjectuiv; + GrGLFunction fGetQueryiv; + GrGLFunction fGetRenderbufferParameteriv; + GrGLFunction fGetShaderInfoLog; + GrGLFunction fGetShaderiv; + GrGLFunction fGetShaderPrecisionFormat; + GrGLFunction fGetString; + GrGLFunction fGetStringi; + GrGLFunction fGetTexLevelParameteriv; + GrGLFunction fGetUniformLocation; + GrGLFunction fInsertEventMarker; + GrGLFunction fInvalidateBufferData; + GrGLFunction fInvalidateBufferSubData; + GrGLFunction fInvalidateFramebuffer; + GrGLFunction fInvalidateSubFramebuffer; + GrGLFunction fInvalidateTexImage; + GrGLFunction fInvalidateTexSubImage; + GrGLFunction fIsTexture; + GrGLFunction fLineWidth; + GrGLFunction fLinkProgram; + GrGLFunction fProgramBinary; + GrGLFunction fProgramParameteri; + GrGLFunction fMapBuffer; + GrGLFunction fMapBufferRange; + GrGLFunction fMapBufferSubData; + GrGLFunction fMapTexSubImage2D; + GrGLFunction fMultiDrawArraysIndirect; + GrGLFunction fMultiDrawElementsIndirect; + GrGLFunction fPixelStorei; + GrGLFunction fPolygonMode; + GrGLFunction fPopGroupMarker; + GrGLFunction fPushGroupMarker; + GrGLFunction fQueryCounter; + GrGLFunction fRasterSamples; + GrGLFunction fReadBuffer; + GrGLFunction fReadPixels; + GrGLFunction fRenderbufferStorage; + + // On OpenGL ES there are multiple incompatible extensions that add support for MSAA + // and ES3 adds MSAA support to the standard. On an ES3 driver we may still use the + // older extensions for performance reasons or due to ES3 driver bugs. We want the function + // that creates the GrGLInterface to provide all available functions and internally + // we will select among them. They all have a method called glRenderbufferStorageMultisample*. + // So we have separate function pointers for GL_IMG/EXT_multisampled_to_texture, + // GL_CHROMIUM/ANGLE_framebuffer_multisample/ES3, and GL_APPLE_framebuffer_multisample + // variations. + // + // If a driver supports multiple GL_ARB_framebuffer_multisample-style extensions then we will + // assume the function pointers for the standard (or equivalent GL_ARB) version have + // been preferred over GL_EXT, GL_CHROMIUM, or GL_ANGLE variations that have reduced + // functionality. + + // GL_EXT_multisampled_render_to_texture (preferred) or GL_IMG_multisampled_render_to_texture + GrGLFunction fRenderbufferStorageMultisampleES2EXT; + // GL_APPLE_framebuffer_multisample + GrGLFunction fRenderbufferStorageMultisampleES2APPLE; + + // This is used to store the pointer for GL_ARB/EXT/ANGLE/CHROMIUM_framebuffer_multisample or + // the standard function in ES3+ or GL 3.0+. + GrGLFunction fRenderbufferStorageMultisample; + + // Pointer to BindUniformLocationCHROMIUM from the GL_CHROMIUM_bind_uniform_location extension. + GrGLFunction fBindUniformLocation; + + GrGLFunction fResolveMultisampleFramebuffer; + GrGLFunction fSamplerParameteri; + GrGLFunction fSamplerParameteriv; + GrGLFunction fScissor; + GrGLFunction fShaderSource; + GrGLFunction fStencilFunc; + GrGLFunction fStencilFuncSeparate; + GrGLFunction fStencilMask; + GrGLFunction fStencilMaskSeparate; + GrGLFunction fStencilOp; + GrGLFunction fStencilOpSeparate; + GrGLFunction fTexBuffer; + GrGLFunction fTexBufferRange; + GrGLFunction fTexImage2D; + GrGLFunction fTexParameteri; + GrGLFunction fTexParameteriv; + GrGLFunction fTexSubImage2D; + GrGLFunction fTexStorage2D; + GrGLFunction fTextureBarrier; + GrGLFunction fDiscardFramebuffer; + GrGLFunction fUniform1f; + GrGLFunction fUniform1i; + GrGLFunction fUniform1fv; + GrGLFunction fUniform1iv; + GrGLFunction fUniform2f; + GrGLFunction fUniform2i; + GrGLFunction fUniform2fv; + GrGLFunction fUniform2iv; + GrGLFunction fUniform3f; + GrGLFunction fUniform3i; + GrGLFunction fUniform3fv; + GrGLFunction fUniform3iv; + GrGLFunction fUniform4f; + GrGLFunction fUniform4i; + GrGLFunction fUniform4fv; + GrGLFunction fUniform4iv; + GrGLFunction fUniformMatrix2fv; + GrGLFunction fUniformMatrix3fv; + GrGLFunction fUniformMatrix4fv; + GrGLFunction fUnmapBuffer; + GrGLFunction fUnmapBufferSubData; + GrGLFunction fUnmapTexSubImage2D; + GrGLFunction fUseProgram; + GrGLFunction fVertexAttrib1f; + GrGLFunction fVertexAttrib2fv; + GrGLFunction fVertexAttrib3fv; + GrGLFunction fVertexAttrib4fv; + GrGLFunction fVertexAttribDivisor; + GrGLFunction fVertexAttribIPointer; + GrGLFunction fVertexAttribPointer; + GrGLFunction fViewport; + + /* GL_NV_path_rendering */ + GrGLFunction fMatrixLoadf; + GrGLFunction fMatrixLoadIdentity; + GrGLFunction fGetProgramResourceLocation; + GrGLFunction fPathCommands; + GrGLFunction fPathParameteri; + GrGLFunction fPathParameterf; + GrGLFunction fGenPaths; + GrGLFunction fDeletePaths; + GrGLFunction fIsPath; + GrGLFunction fPathStencilFunc; + GrGLFunction fStencilFillPath; + GrGLFunction fStencilStrokePath; + GrGLFunction fStencilFillPathInstanced; + GrGLFunction fStencilStrokePathInstanced; + GrGLFunction fCoverFillPath; + GrGLFunction fCoverStrokePath; + GrGLFunction fCoverFillPathInstanced; + GrGLFunction fCoverStrokePathInstanced; + // NV_path_rendering v1.2 + GrGLFunction fStencilThenCoverFillPath; + GrGLFunction fStencilThenCoverStrokePath; + GrGLFunction fStencilThenCoverFillPathInstanced; + GrGLFunction fStencilThenCoverStrokePathInstanced; + // NV_path_rendering v1.3 + GrGLFunction fProgramPathFragmentInputGen; + // CHROMIUM_path_rendering + GrGLFunction fBindFragmentInputLocation; + + /* NV_framebuffer_mixed_samples */ + GrGLFunction fCoverageModulation; + + /* ARB_sample_shading */ + GrGLFunction fMinSampleShading; + + /* ARB_sync */ + GrGLFunction fFenceSync; + GrGLFunction fIsSync; + GrGLFunction fClientWaitSync; + GrGLFunction fWaitSync; + GrGLFunction fDeleteSync; + + /* ARB_internalforamt_query */ + GrGLFunction fGetInternalformativ; + + /* KHR_debug */ + GrGLFunction fDebugMessageControl; + GrGLFunction fDebugMessageInsert; + GrGLFunction fDebugMessageCallback; + GrGLFunction fGetDebugMessageLog; + GrGLFunction fPushDebugGroup; + GrGLFunction fPopDebugGroup; + GrGLFunction fObjectLabel; + + /* EXT_window_rectangles */ + GrGLFunction fWindowRectangles; + + /* EGL functions */ + GrGLFunction fEGLCreateImage; + GrGLFunction fEGLDestroyImage; + } fFunctions; + +#if GR_TEST_UTILS + // This exists for internal testing. + virtual void abandon() const; +#endif +}; + +#endif diff --git a/skia/include/gpu/gl/GrGLTypes.h b/skia/include/gpu/gl/GrGLTypes.h new file mode 100644 index 00000000..cb8d7972 --- /dev/null +++ b/skia/include/gpu/gl/GrGLTypes.h @@ -0,0 +1,126 @@ + +/* + * 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 GrGLTypes_DEFINED +#define GrGLTypes_DEFINED + +#include "GrGLConfig.h" +#include "SkRefCnt.h" + +/** + * Classifies GL contexts by which standard they implement (currently as OpenGL vs. OpenGL ES). + */ +enum GrGLStandard { + kNone_GrGLStandard, + kGL_GrGLStandard, + kGLES_GrGLStandard, +}; +static const int kGrGLStandardCnt = 3; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Declares typedefs for all the GL functions used in GrGLInterface + */ + +typedef unsigned int GrGLenum; +typedef unsigned char GrGLboolean; +typedef unsigned int GrGLbitfield; +typedef signed char GrGLbyte; +typedef char GrGLchar; +typedef short GrGLshort; +typedef int GrGLint; +typedef int GrGLsizei; +typedef int64_t GrGLint64; +typedef unsigned char GrGLubyte; +typedef unsigned short GrGLushort; +typedef unsigned int GrGLuint; +typedef uint64_t GrGLuint64; +typedef float GrGLfloat; +typedef float GrGLclampf; +typedef double GrGLdouble; +typedef double GrGLclampd; +typedef void GrGLvoid; +#ifdef _WIN64 +typedef signed long long int GrGLintptr; +typedef signed long long int GrGLsizeiptr; +#else +typedef signed long int GrGLintptr; +typedef signed long int GrGLsizeiptr; +#endif +typedef void* GrGLeglImage; +typedef struct __GLsync* GrGLsync; + +struct GrGLDrawArraysIndirectCommand { + GrGLuint fCount; + GrGLuint fInstanceCount; + GrGLuint fFirst; + GrGLuint fBaseInstance; // Requires EXT_base_instance on ES. +}; + +GR_STATIC_ASSERT(16 == sizeof(GrGLDrawArraysIndirectCommand)); + +struct GrGLDrawElementsIndirectCommand { + GrGLuint fCount; + GrGLuint fInstanceCount; + GrGLuint fFirstIndex; + GrGLuint fBaseVertex; + GrGLuint fBaseInstance; // Requires EXT_base_instance on ES. +}; + +GR_STATIC_ASSERT(20 == sizeof(GrGLDrawElementsIndirectCommand)); + +/** + * KHR_debug + */ +typedef void (GR_GL_FUNCTION_TYPE* GRGLDEBUGPROC)(GrGLenum source, + GrGLenum type, + GrGLuint id, + GrGLenum severity, + GrGLsizei length, + const GrGLchar* message, + const void* userParam); + +/** + * EGL types. + */ +typedef void* GrEGLImage; +typedef void* GrEGLDisplay; +typedef void* GrEGLContext; +typedef void* GrEGLClientBuffer; +typedef unsigned int GrEGLenum; +typedef int32_t GrEGLint; +typedef unsigned int GrEGLBoolean; + +/////////////////////////////////////////////////////////////////////////////// +/** + * Types for interacting with GL resources created externally to Skia. GrBackendObjects for GL + * textures are really const GrGLTexture*. The fFormat here should be a sized, internal format + * for the texture. We will try to use the sized format if the GL Context supports it, otherwise + * we will internally fall back to using the base internal formats. + */ +struct GrGLTextureInfo { + GrGLenum fTarget; + GrGLuint fID; + GrGLenum fFormat = 0; + + bool operator==(const GrGLTextureInfo& that) const { + return fTarget == that.fTarget && fID == that.fID && fFormat == that.fFormat; + } +}; + +struct GrGLFramebufferInfo { + GrGLuint fFBOID; + GrGLenum fFormat = 0; + + bool operator==(const GrGLFramebufferInfo& that) const { + return fFBOID == that.fFBOID && fFormat == that.fFormat; + } +}; + +#endif diff --git a/skia/include/gpu/mock/GrMockTypes.h b/skia/include/gpu/mock/GrMockTypes.h new file mode 100644 index 00000000..21037b17 --- /dev/null +++ b/skia/include/gpu/mock/GrMockTypes.h @@ -0,0 +1,75 @@ +/* + * 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 GrMockOptions_DEFINED +#define GrMockOptions_DEFINED + +#include "GrTypes.h" +#include "../private/GrTypesPriv.h" + +struct GrMockTextureInfo { + GrPixelConfig fConfig; + int fID; + + bool operator==(const GrMockTextureInfo& that) const { + return fConfig == that.fConfig && fID == that.fID; + } +}; + +struct GrMockRenderTargetInfo { + GrPixelConfig fConfig; + int fID; + + bool operator==(const GrMockRenderTargetInfo& that) const { + return fConfig == that.fConfig && fID == that.fID; + } +}; + +/** + * A pointer to this type is used as the GrBackendContext when creating a Mock GrContext. It can be + * used to specify capability options for the mock context. If nullptr is used a default constructed + * GrMockOptions is used. + */ +struct GrMockOptions { + GrMockOptions() { + using Renderability = ConfigOptions::Renderability; + // By default RGBA_8888 is textureable and renderable and A8 and RGB565 are texturable. + fConfigOptions[kRGBA_8888_GrPixelConfig].fRenderability = Renderability::kNonMSAA; + fConfigOptions[kRGBA_8888_GrPixelConfig].fTexturable = true; + fConfigOptions[kAlpha_8_GrPixelConfig].fTexturable = true; + fConfigOptions[kAlpha_8_as_Alpha_GrPixelConfig].fTexturable = true; + fConfigOptions[kAlpha_8_as_Red_GrPixelConfig].fTexturable = true; + fConfigOptions[kRGB_565_GrPixelConfig].fTexturable = true; + } + + struct ConfigOptions { + enum Renderability { kNo, kNonMSAA, kMSAA }; + Renderability fRenderability; + bool fTexturable = false; + }; + + // GrCaps options. + bool fInstanceAttribSupport = false; + uint32_t fMapBufferFlags = 0; + int fMaxTextureSize = 2048; + int fMaxRenderTargetSize = 2048; + int fMaxVertexAttributes = 16; + ConfigOptions fConfigOptions[kGrPixelConfigCnt]; + + // GrShaderCaps options. + bool fGeometryShaderSupport = false; + bool fIntegerSupport = false; + bool fFlatInterpolationSupport = false; + int fMaxVertexSamplers = 0; + int fMaxFragmentSamplers = 8; + bool fShaderDerivativeSupport = true; + + // GrMockGpu options. + bool fFailTextureAllocations = false; +}; + +#endif diff --git a/skia/include/gpu/mtl/GrMtlTypes.h b/skia/include/gpu/mtl/GrMtlTypes.h new file mode 100644 index 00000000..8b973f71 --- /dev/null +++ b/skia/include/gpu/mtl/GrMtlTypes.h @@ -0,0 +1,32 @@ +/* + * 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 GrMtlTypes_DEFINED +#define GrMtlTypes_DEFINED + +#include "GrTypes.h" + +/** + * Declares typedefs for Metal types used in Ganesh cpp code + */ +typedef unsigned int GrMTLPixelFormat; + +/////////////////////////////////////////////////////////////////////////////// +/** + * Types for interacting with Metal resources created externally to Skia. Holds the MTLTexture as a + * const void*. This is used by GrBackendObjects. + */ +struct GrMtlTextureInfo { +public: + const void* fTexture; // Pointer to MTLTexture + + bool operator==(const GrMtlTextureInfo& that) const { + return fTexture == that.fTexture; + } +}; + +#endif diff --git a/skia/include/gpu/vk/GrVkBackendContext.h b/skia/include/gpu/vk/GrVkBackendContext.h new file mode 100644 index 00000000..f49c36f7 --- /dev/null +++ b/skia/include/gpu/vk/GrVkBackendContext.h @@ -0,0 +1,70 @@ +/* + * 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 GrVkBackendContext_DEFINED +#define GrVkBackendContext_DEFINED + +#include "GrVkTypes.h" +#include "SkRefCnt.h" +#include "vk/GrVkMemoryAllocator.h" + +class GrVkExtensions; + +enum GrVkExtensionFlags { + kEXT_debug_report_GrVkExtensionFlag = 0x0001, + kNV_glsl_shader_GrVkExtensionFlag = 0x0002, + kKHR_surface_GrVkExtensionFlag = 0x0004, + kKHR_swapchain_GrVkExtensionFlag = 0x0008, + kKHR_win32_surface_GrVkExtensionFlag = 0x0010, + kKHR_android_surface_GrVkExtensionFlag = 0x0020, + kKHR_xcb_surface_GrVkExtensionFlag = 0x0040, +}; + +enum GrVkFeatureFlags { + kGeometryShader_GrVkFeatureFlag = 0x0001, + kDualSrcBlend_GrVkFeatureFlag = 0x0002, + kSampleRateShading_GrVkFeatureFlag = 0x0004, +}; + +// It is not guarenteed VkPhysicalDeviceProperties2 will be in the client's header so we forward +// declare it here to be safe. +struct VkPhysicalDeviceFeatures2; + +// The BackendContext contains all of the base Vulkan objects needed by the GrVkGpu. The assumption +// is that the client will set these up and pass them to the GrVkGpu constructor. The VkDevice +// created must support at least one graphics queue, which is passed in as well. +// The QueueFamilyIndex must match the family of the given queue. It is needed for CommandPool +// creation, and any GrBackendObjects handed to us (e.g., for wrapped textures) needs to be created +// in or transitioned to that family. The refs held by members of this struct must be released +// (either by deleting the struct or manually releasing the refs) before the underlying vulkan +// device and instance are destroyed. +struct SK_API GrVkBackendContext { + VkInstance fInstance; + VkPhysicalDevice fPhysicalDevice; + VkDevice fDevice; + VkQueue fQueue; + uint32_t fGraphicsQueueIndex; + uint32_t fMinAPIVersion; // Deprecated. Set fInstanceVersion instead. + uint32_t fInstanceVersion = 0; + uint32_t fExtensions = 0; // Deprecated. Use fVkExtensions instead. + const GrVkExtensions* fVkExtensions = nullptr; + uint32_t fFeatures; // Deprecated. Use either fDeviceFeatures[2] instead. + // The client can create their VkDevice with either a VkPhysicalDeviceFeatures or + // VkPhysicalDeviceFeatures2 struct, thus we have to support taking both. The + // VkPhysicalDeviceFeatures2 struct is needed so we know if the client enabled any extension + // specific features. If fDeviceFeatures2 is not null then we ignore fDeviceFeatures. If both + // fDeviceFeatures and fDeviceFeatures2 are null we will assume no features are enabled. + VkPhysicalDeviceFeatures* fDeviceFeatures = nullptr; + VkPhysicalDeviceFeatures2* fDeviceFeatures2 = nullptr; + sk_sp fMemoryAllocator; + GrVkGetProc fGetProc = nullptr; + // This is deprecated and should be set to false. The client is responsible for managing the + // lifetime of the VkInstance and VkDevice objects. + bool fOwnsInstanceAndDevice = false; +}; + +#endif diff --git a/skia/include/gpu/vk/GrVkExtensions.h b/skia/include/gpu/vk/GrVkExtensions.h new file mode 100644 index 00000000..fc77ba1d --- /dev/null +++ b/skia/include/gpu/vk/GrVkExtensions.h @@ -0,0 +1,63 @@ +/* + * 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 GrVkExtensions_DEFINED +#define GrVkExtensions_DEFINED + +#include "../../private/SkTArray.h" +#include "SkString.h" +#include "vk/GrVkTypes.h" + +/** + * Helper class that eats in an array of extensions strings for instance and device and allows for + * quicker querying if an extension is present. + */ +class SK_API GrVkExtensions { +public: + GrVkExtensions() {} + + void init(GrVkGetProc, VkInstance, VkPhysicalDevice, + uint32_t instanceExtensionCount, const char* const* instanceExtensions, + uint32_t deviceExtensionCount, const char* const* deviceExtensions); + + bool hasExtension(const char[], uint32_t minVersion) const; + + struct Info { + Info() {} + Info(const char* name) : fName(name), fSpecVersion(0) {} + + SkString fName; + uint32_t fSpecVersion; + + struct Less { + bool operator() (const Info& a, const SkString& b) { + return strcmp(a.fName.c_str(), b.c_str()) < 0; + } + bool operator() (const SkString& a, const GrVkExtensions::Info& b) { + return strcmp(a.c_str(), b.fName.c_str()) < 0; + } + }; + }; + +#ifdef SK_DEBUG + void dump() const { + SkDebugf("**Vulkan Extensions**\n"); + for (int i = 0; i < fExtensions.count(); ++i) { + SkDebugf("%s. Version: %d\n", + fExtensions[i].fName.c_str(), fExtensions[i].fSpecVersion); + } + SkDebugf("**End Vulkan Extensions**\n"); + } +#endif + +private: + void getSpecVersions(GrVkGetProc getProc, VkInstance, VkPhysicalDevice); + + SkTArray fExtensions; +}; + +#endif diff --git a/skia/include/gpu/vk/GrVkMemoryAllocator.h b/skia/include/gpu/vk/GrVkMemoryAllocator.h new file mode 100644 index 00000000..62ac4aca --- /dev/null +++ b/skia/include/gpu/vk/GrVkMemoryAllocator.h @@ -0,0 +1,88 @@ +/* + * 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 GrVkMemoryAllocator_DEFINED +#define GrVkMemoryAllocator_DEFINED + +#include "SkRefCnt.h" +#include "GrTypes.h" +#include "GrVkTypes.h" + +class GrVkMemoryAllocator : public SkRefCnt { +public: + enum class AllocationPropertyFlags { + kNone = 0, + // Allocation will be placed in its own VkDeviceMemory and not suballocated from some larger + // block. + kDedicatedAllocation = 0x1, + // Says that the backing memory can only be accessed by the device. Additionally the device + // may lazily allocate the memory. This cannot be used with buffers that will be host + // visible. Setting this flag does not guarantee that we will allocate memory that respects + // it, but we will try to prefer memory that can respect it. + kLazyAllocation = 0x2, + // The allocation will be mapped immediately and stay mapped until it is destroyed. This + // flag is only valid for buffers which are host visible (i.e. must have a usage other than + // BufferUsage::kGpuOnly). + kPersistentlyMapped = 0x4, + }; + + GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AllocationPropertyFlags); + + enum class BufferUsage { + // Buffers that will only be accessed from the device (large const buffers). Will always be + // in device local memory. + kGpuOnly, + // Buffers that will be accessed on the host and copied to and from a GPU resource (transfer + // buffers). Will always be mappable and coherent memory. + kCpuOnly, + // Buffers that typically will be updated multiple times by the host and read on the gpu + // (e.g. uniform or vertex buffers). Will always be mappable memory, and will prefer to be + // in device local memory. + kCpuWritesGpuReads, + // Buffers which are typically writted to by the GPU and then read on the host. Will always + // be mappable memory, and will prefer coherent and cached memory. + kGpuWritesCpuReads, + }; + + virtual bool allocateMemoryForImage(VkImage image, AllocationPropertyFlags flags, + GrVkBackendMemory*) = 0; + + virtual bool allocateMemoryForBuffer(VkBuffer buffer, BufferUsage usage, + AllocationPropertyFlags flags, GrVkBackendMemory*) = 0; + + // Fills out the passed in GrVkAlloc struct for the passed in GrVkBackendMemory. + virtual void getAllocInfo(const GrVkBackendMemory&, GrVkAlloc*) const = 0; + + // Maps the entire allocation and returns a pointer to the start of the allocation. The + // implementation may map more memory than just the allocation, but the returned pointer must + // point at the start of the memory for the requested allocation. + virtual void* mapMemory(const GrVkBackendMemory&) = 0; + virtual void unmapMemory(const GrVkBackendMemory&) = 0; + + // The following two calls are used for managing non-coherent memory. The offset is relative to + // the start of the allocation and not the underlying VkDeviceMemory. Additionaly the client + // must make sure that the offset + size passed in is less that or equal to the allocation size. + // It is the responsibility of the implementation to make sure all alignment requirements are + // followed. The client should not have to deal with any sort of alignment issues. + virtual void flushMappedMemory(const GrVkBackendMemory&, VkDeviceSize offset, + VkDeviceSize size) = 0; + virtual void invalidateMappedMemory(const GrVkBackendMemory&, VkDeviceSize offset, + VkDeviceSize size)= 0; + + virtual void freeMemory(const GrVkBackendMemory&) = 0; + + // Returns the total amount of memory that is allocated and in use by an allocation for this + // allocator. + virtual uint64_t totalUsedMemory() const = 0; + + // Returns the total amount of memory that is allocated by this allocator. + virtual uint64_t totalAllocatedMemory() const = 0; +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrVkMemoryAllocator::AllocationPropertyFlags); + +#endif diff --git a/skia/include/gpu/vk/GrVkTypes.h b/skia/include/gpu/vk/GrVkTypes.h new file mode 100644 index 00000000..796a867f --- /dev/null +++ b/skia/include/gpu/vk/GrVkTypes.h @@ -0,0 +1,153 @@ + +/* + * 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 GrVkTypes_DEFINED +#define GrVkTypes_DEFINED + +#ifdef SK_VULKAN +#include +#else +#include "../../../third_party/vulkan/vulkan/vulkan_core.h" +#endif +#ifndef VK_VERSION_1_1 +#error Skia requires the use of Vulkan 1.1 headers +#endif + +#include +#include "GrTypes.h" + +typedef intptr_t GrVkBackendMemory; + +/** + * Types for interacting with Vulkan resources created externally to Skia. GrBackendObjects for + * Vulkan textures are really const GrVkImageInfo* + */ +struct GrVkAlloc { + GrVkAlloc() + : fMemory(VK_NULL_HANDLE) + , fOffset(0) + , fSize(0) + , fFlags(0) + , fBackendMemory(0) + , fUsesSystemHeap(false) {} + + GrVkAlloc(VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, uint32_t flags) + : fMemory(memory) + , fOffset(offset) + , fSize(size) + , fFlags(flags) + , fBackendMemory(0) + , fUsesSystemHeap(false) {} + + VkDeviceMemory fMemory; // can be VK_NULL_HANDLE iff is an RT and is borrowed + VkDeviceSize fOffset; + VkDeviceSize fSize; // this can be indeterminate iff Tex uses borrow semantics + uint32_t fFlags; + GrVkBackendMemory fBackendMemory; // handle to memory allocated via GrVkMemoryAllocator. + + enum Flag { + kNoncoherent_Flag = 0x1, // memory must be flushed to device after mapping + kMappable_Flag = 0x2, // memory is able to be mapped. + }; + + bool operator==(const GrVkAlloc& that) const { + return fMemory == that.fMemory && fOffset == that.fOffset && fSize == that.fSize && + fFlags == that.fFlags && fUsesSystemHeap == that.fUsesSystemHeap; + } + +private: + friend class GrVkHeap; // For access to usesSystemHeap + bool fUsesSystemHeap; +}; +struct GrVkImageInfo { + VkImage fImage; + GrVkAlloc fAlloc; + VkImageTiling fImageTiling; + VkImageLayout fImageLayout; + VkFormat fFormat; + uint32_t fLevelCount; + uint32_t fCurrentQueueFamily; + + GrVkImageInfo() + : fImage(VK_NULL_HANDLE) + , fAlloc() + , fImageTiling(VK_IMAGE_TILING_OPTIMAL) + , fImageLayout(VK_IMAGE_LAYOUT_UNDEFINED) + , fFormat(VK_FORMAT_UNDEFINED) + , fLevelCount(0) + , fCurrentQueueFamily(VK_QUEUE_FAMILY_IGNORED) {} + + GrVkImageInfo(VkImage image, GrVkAlloc alloc, VkImageTiling imageTiling, VkImageLayout layout, + VkFormat format, uint32_t levelCount, + uint32_t currentQueueFamily = VK_QUEUE_FAMILY_IGNORED) + : fImage(image) + , fAlloc(alloc) + , fImageTiling(imageTiling) + , fImageLayout(layout) + , fFormat(format) + , fLevelCount(levelCount) + , fCurrentQueueFamily(currentQueueFamily) {} + + GrVkImageInfo(const GrVkImageInfo& info, VkImageLayout layout) + : fImage(info.fImage) + , fAlloc(info.fAlloc) + , fImageTiling(info.fImageTiling) + , fImageLayout(layout) + , fFormat(info.fFormat) + , fLevelCount(info.fLevelCount) + , fCurrentQueueFamily(info.fCurrentQueueFamily) {} + + // This gives a way for a client to update the layout of the Image if they change the layout + // while we're still holding onto the wrapped texture. They will first need to get a handle + // to our internal GrVkImageInfo by calling getTextureHandle on a GrVkTexture. + void updateImageLayout(VkImageLayout layout) { fImageLayout = layout; } + + bool operator==(const GrVkImageInfo& that) const { + return fImage == that.fImage && fAlloc == that.fAlloc && + fImageTiling == that.fImageTiling && fImageLayout == that.fImageLayout && + fFormat == that.fFormat && fLevelCount == that.fLevelCount; + } +}; + +using GrVkGetProc = std::function; + +/** + * This object is wrapped in a GrBackendDrawableInfo and passed in as an argument to + * drawBackendGpu() calls on an SkDrawable. The drawable will use this info to inject direct + * Vulkan calls into our stream of GPU draws. + * + * The SkDrawable is given a secondary VkCommandBuffer in which to record draws. The GPU backend + * will then execute that command buffer within a render pass it is using for its own draws. The + * drawable is also given the attachment of the color index, a compatible VkRenderPass, and the + * VkFormat of the color attachment so that it can make VkPipeline objects for the draws. The + * SkDrawable must not alter the state of the VkRenderpass or sub pass. + * + * Additionally, the SkDrawable may fill in the passed in fDrawBounds with the bounds of the draws + * that it submits to the command buffer. This will be used by the GPU backend for setting the + * bounds in vkCmdBeginRenderPass. If fDrawBounds is not updated, we will assume that the entire + * attachment may have been written to. + * + * The SkDrawable is always allowed to create its own command buffers and submit them to the queue + * to render offscreen textures which will be sampled in draws added to the passed in + * VkCommandBuffer. If this is done the SkDrawable is in charge of adding the required memory + * barriers to the queue for the sampled images since the Skia backend will not do this. + */ +struct GrVkDrawableInfo { + VkCommandBuffer fSecondaryCommandBuffer; + uint32_t fColorAttachmentIndex; + VkRenderPass fCompatibleRenderPass; + uint32_t fImageAttachmentIndex; + VkFormat fFormat; + VkRect2D* fDrawBounds; +}; + +#endif diff --git a/skia/include/pathops/SkPathOps.h b/skia/include/pathops/SkPathOps.h new file mode 100644 index 00000000..50e50d61 --- /dev/null +++ b/skia/include/pathops/SkPathOps.h @@ -0,0 +1,113 @@ +/* + * 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 SkPathOps_DEFINED +#define SkPathOps_DEFINED + +#include "../private/SkTArray.h" +#include "../private/SkTDArray.h" +#include "SkPreConfig.h" + +class SkPath; +struct SkRect; + + +// FIXME: move everything below into the SkPath class +/** + * The logical operations that can be performed when combining two paths. + */ +enum SkPathOp { + kDifference_SkPathOp, //!< subtract the op path from the first path + kIntersect_SkPathOp, //!< intersect the two paths + kUnion_SkPathOp, //!< union (inclusive-or) the two paths + kXOR_SkPathOp, //!< exclusive-or the two paths + kReverseDifference_SkPathOp, //!< subtract the first path from the op path +}; + +/** Set this path to the result of applying the Op to this path and the + specified path: this = (this op operand). + The resulting path will be constructed from non-overlapping contours. + The curve order is reduced where possible so that cubics may be turned + into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param one The first operand (for difference, the minuend) + @param two The second operand (for difference, the subtrahend) + @param op The operator to apply. + @param result The product of the operands. The result may be one of the + inputs. + @return True if the operation succeeded. + */ +bool SK_API Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result); + +/** Set this path to a set of non-overlapping contours that describe the + same area as the original path. + The curve order is reduced where possible so that cubics may + be turned into quadratics, and quadratics maybe turned into lines. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. + + @param path The path to simplify. + @param result The simplified path. The result may be the input. + @return True if simplification succeeded. + */ +bool SK_API Simplify(const SkPath& path, SkPath* result); + +/** Set the resulting rectangle to the tight bounds of the path. + + @param path The path measured. + @param result The tight bounds of the path. + @return True if the bounds could be computed. + */ +bool SK_API TightBounds(const SkPath& path, SkRect* result); + +/** Set the result with fill type winding to area equivalent to path. + Returns true if successful. Does not detect if path contains contours which + contain self-crossings or cross other contours; in these cases, may return + true even though result does not fill same area as path. + + Returns true if operation was able to produce a result; + otherwise, result is unmodified. The result may be the input. + + @param path The path typically with fill type set to even odd. + @param result The equivalent path with fill type set to winding. + @return True if winding path was set. + */ +bool SK_API AsWinding(const SkPath& path, SkPath* result); + +/** Perform a series of path operations, optimized for unioning many paths together. + */ +class SK_API SkOpBuilder { +public: + /** Add one or more paths and their operand. The builder is empty before the first + path is added, so the result of a single add is (emptyPath OP path). + + @param path The second operand. + @param _operator The operator to apply to the existing and supplied paths. + */ + void add(const SkPath& path, SkPathOp _operator); + + /** Computes the sum of all paths and operands, and resets the builder to its + initial state. + + @param result The product of the operands. + @return True if the operation succeeded. + */ + bool resolve(SkPath* result); + +private: + SkTArray fPathRefs; + SkTDArray fOps; + + static bool FixWinding(SkPath* path); + static void ReversePath(SkPath* path); + void reset(); +}; + +#endif diff --git a/skia/include/ports/SkFontConfigInterface.h b/skia/include/ports/SkFontConfigInterface.h new file mode 100644 index 00000000..01346f25 --- /dev/null +++ b/skia/include/ports/SkFontConfigInterface.h @@ -0,0 +1,115 @@ +/* + * 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 SkFontConfigInterface_DEFINED +#define SkFontConfigInterface_DEFINED + +#include "SkFontStyle.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkTypeface.h" + +class SkFontMgr; + +/** + * \class SkFontConfigInterface + * + * A simple interface for remotable font management. + * The global instance can be found with RefGlobal(). + */ +class SK_API SkFontConfigInterface : public SkRefCnt { +public: + + /** + * Returns the global SkFontConfigInterface instance. If it is not + * nullptr, calls ref() on it. The caller must balance this with a call to + * unref(). The default SkFontConfigInterface is the result of calling + * GetSingletonDirectInterface. + */ + static sk_sp RefGlobal(); + + /** + * Replace the current global instance with the specified one. + */ + static void SetGlobal(sk_sp fc); + + /** + * This should be treated as private to the impl of SkFontConfigInterface. + * Callers should not change or expect any particular values. It is meant + * to be a union of possible storage types to aid the impl. + */ + struct FontIdentity { + FontIdentity() : fID(0), fTTCIndex(0) {} + + bool operator==(const FontIdentity& other) const { + return fID == other.fID && + fTTCIndex == other.fTTCIndex && + fString == other.fString; + } + bool operator!=(const FontIdentity& other) const { + return !(*this == other); + } + + uint32_t fID; + int32_t fTTCIndex; + SkString fString; + SkFontStyle fStyle; + + // If buffer is NULL, just return the number of bytes that would have + // been written. Will pad contents to a multiple of 4. + size_t writeToMemory(void* buffer = nullptr) const; + + // Recreate from a flattened buffer, returning the number of bytes read. + size_t readFromMemory(const void* buffer, size_t length); + }; + + /** + * Given a familyName and style, find the best match. + * + * If a match is found, return true and set its outFontIdentifier. + * If outFamilyName is not null, assign the found familyName to it + * (which may differ from the requested familyName). + * If outStyle is not null, assign the found style to it + * (which may differ from the requested style). + * + * If a match is not found, return false, and ignore all out parameters. + */ + virtual bool matchFamilyName(const char familyName[], + SkFontStyle requested, + FontIdentity* outFontIdentifier, + SkString* outFamilyName, + SkFontStyle* outStyle) = 0; + + /** + * Given a FontRef, open a stream to access its data, or return null + * if the FontRef's data is not available. The caller is responsible for + * deleting the stream when it is done accessing the data. + */ + virtual SkStreamAsset* openStream(const FontIdentity&) = 0; + + /** + * Return an SkTypeface for the given FontIdentity. + * + * The default implementation simply returns a new typeface built using data obtained from + * openStream(), but derived classes may implement more complex caching schemes. + */ + virtual sk_sp makeTypeface(const FontIdentity& identity) { + return SkTypeface::MakeFromStream(std::unique_ptr(this->openStream(identity)), + identity.fTTCIndex); + + } + + /** + * Return a singleton instance of a direct subclass that calls into + * libfontconfig. This does not affect the refcnt of the returned instance. + */ + static SkFontConfigInterface* GetSingletonDirectInterface(); + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/ports/SkFontMgr_FontConfigInterface.h b/skia/include/ports/SkFontMgr_FontConfigInterface.h new file mode 100644 index 00000000..9dccb7be --- /dev/null +++ b/skia/include/ports/SkFontMgr_FontConfigInterface.h @@ -0,0 +1,20 @@ +/* + * 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 SkFontMgr_FontConfigInterface_DEFINED +#define SkFontMgr_FontConfigInterface_DEFINED + +#include "SkTypes.h" +#include "SkRefCnt.h" + +class SkFontMgr; +class SkFontConfigInterface; + +/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */ +SK_API sk_sp SkFontMgr_New_FCI(sk_sp fci); + +#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED diff --git a/skia/include/ports/SkFontMgr_android.h b/skia/include/ports/SkFontMgr_android.h new file mode 100644 index 00000000..050faddb --- /dev/null +++ b/skia/include/ports/SkFontMgr_android.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 SkFontMgr_android_DEFINED +#define SkFontMgr_android_DEFINED + +#include "SkRefCnt.h" + +class SkFontMgr; + +struct SkFontMgr_Android_CustomFonts { + /** When specifying custom fonts, indicates how to use system fonts. */ + enum SystemFontUse { + kOnlyCustom, /** Use only custom fonts. NDK compliant. */ + kPreferCustom, /** Use custom fonts before system fonts. */ + kPreferSystem /** Use system fonts before custom fonts. */ + }; + /** Whether or not to use system fonts. */ + SystemFontUse fSystemFontUse; + + /** Base path to resolve relative font file names. If a directory, should end with '/'. */ + const char* fBasePath; + + /** Optional custom configuration file to use. */ + const char* fFontsXml; + + /** Optional custom configuration file for fonts which provide fallback. + * In the new style (version > 21) fontsXml format is used, this should be NULL. + */ + const char* fFallbackFontsXml; + + /** Optional custom flag. If set to true the SkFontMgr will acquire all requisite + * system IO resources on initialization. + */ + bool fIsolated; +}; + +/** Create a font manager for Android. If 'custom' is NULL, use only system fonts. */ +SK_API sk_sp SkFontMgr_New_Android(const SkFontMgr_Android_CustomFonts* custom); + +#endif // SkFontMgr_android_DEFINED diff --git a/skia/include/ports/SkFontMgr_directory.h b/skia/include/ports/SkFontMgr_directory.h new file mode 100644 index 00000000..8f79a7f5 --- /dev/null +++ b/skia/include/ports/SkFontMgr_directory.h @@ -0,0 +1,21 @@ +/* + * 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 SkFontMgr_directory_DEFINED +#define SkFontMgr_directory_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager which scans a given directory for font files. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Directory(const char* dir); + +#endif // SkFontMgr_directory_DEFINED diff --git a/skia/include/ports/SkFontMgr_empty.h b/skia/include/ports/SkFontMgr_empty.h new file mode 100644 index 00000000..dbeef586 --- /dev/null +++ b/skia/include/ports/SkFontMgr_empty.h @@ -0,0 +1,21 @@ +/* + * 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 SkFontMgr_empty_DEFINED +#define SkFontMgr_empty_DEFINED + +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkFontMgr; + +/** Create a custom font manager that contains no built-in fonts. + * This font manager uses FreeType for rendering. + */ +SK_API sk_sp SkFontMgr_New_Custom_Empty(); + +#endif // SkFontMgr_empty_DEFINED diff --git a/skia/include/ports/SkFontMgr_fontconfig.h b/skia/include/ports/SkFontMgr_fontconfig.h new file mode 100644 index 00000000..e0f41089 --- /dev/null +++ b/skia/include/ports/SkFontMgr_fontconfig.h @@ -0,0 +1,22 @@ +/* + * 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 SkFontMgr_fontconfig_DEFINED +#define SkFontMgr_fontconfig_DEFINED + +#include "SkRefCnt.h" +#include + +class SkFontMgr; + +/** Create a font manager around a FontConfig instance. + * If 'fc' is NULL, will use a new default config. + * Takes ownership of 'fc' and will call FcConfigDestroy on it. + */ +SK_API sk_sp SkFontMgr_New_FontConfig(FcConfig* fc); + +#endif // #ifndef SkFontMgr_fontconfig_DEFINED diff --git a/skia/include/ports/SkFontMgr_indirect.h b/skia/include/ports/SkFontMgr_indirect.h new file mode 100644 index 00000000..04e903ed --- /dev/null +++ b/skia/include/ports/SkFontMgr_indirect.h @@ -0,0 +1,99 @@ +/* + * 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 SkFontMgr_indirect_DEFINED +#define SkFontMgr_indirect_DEFINED + +#include "../private/SkMutex.h" +#include "../private/SkOnce.h" +#include "../private/SkTArray.h" +#include "SkFontMgr.h" +#include "SkRefCnt.h" +#include "SkRemotableFontMgr.h" +#include "SkTypeface.h" +#include "SkTypes.h" + +class SkData; +class SkFontStyle; +class SkStreamAsset; +class SkString; + +class SK_API SkFontMgr_Indirect : public SkFontMgr { +public: + // TODO: The SkFontMgr is only used for createFromStream/File/Data. + // In the future these calls should be broken out into their own interface + // with a name like SkFontRenderer. + SkFontMgr_Indirect(sk_sp impl, sk_sp proxy) + : fImpl(std::move(impl)), fProxy(std::move(proxy)) + { } + +protected: + int onCountFamilies() const override; + void onGetFamilyName(int index, SkString* familyName) const override; + SkFontStyleSet* onCreateStyleSet(int index) const override; + + SkFontStyleSet* onMatchFamily(const char familyName[]) const override; + + SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const override; + + SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], + int bcp47Count, + SkUnichar character) const override; + + SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle& fontStyle) const override; + + sk_sp onMakeFromStreamIndex(std::unique_ptr, int ttcIndex) const override; + sk_sp onMakeFromFile(const char path[], int ttcIndex) const override; + sk_sp onMakeFromData(sk_sp, int ttcIndex) const override; + sk_sp onLegacyMakeTypeface(const char familyName[], SkFontStyle) const override; + +private: + SkTypeface* createTypefaceFromFontId(const SkFontIdentity& fontId) const; + + sk_sp fImpl; + sk_sp fProxy; + + struct DataEntry { + uint32_t fDataId; // key1 + uint32_t fTtcIndex; // key2 + SkTypeface* fTypeface; // value: weak ref to typeface + + DataEntry() { } + + DataEntry(DataEntry&& that) + : fDataId(that.fDataId) + , fTtcIndex(that.fTtcIndex) + , fTypeface(that.fTypeface) + { + SkDEBUGCODE(that.fDataId = SkFontIdentity::kInvalidDataId;) + SkDEBUGCODE(that.fTtcIndex = 0xbbadbeef;) + that.fTypeface = nullptr; + } + + ~DataEntry() { + if (fTypeface) { + fTypeface->weak_unref(); + } + } + }; + /** + * This cache is essentially { dataId: { ttcIndex: typeface } } + * For data caching we want a mapping from data id to weak references to + * typefaces with that data id. By storing the index next to the typeface, + * this data cache also acts as a typeface cache. + */ + mutable SkTArray fDataCache; + mutable SkMutex fDataCacheMutex; + + friend class SkStyleSet_Indirect; +}; + +#endif diff --git a/skia/include/ports/SkImageGeneratorCG.h b/skia/include/ports/SkImageGeneratorCG.h new file mode 100644 index 00000000..3206fc48 --- /dev/null +++ b/skia/include/ports/SkImageGeneratorCG.h @@ -0,0 +1,20 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "SkData.h" +#include "SkImageGenerator.h" + +#include + +namespace SkImageGeneratorCG { +SK_API std::unique_ptr MakeFromEncodedCG(sk_sp); +} + +#endif //defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/skia/include/ports/SkImageGeneratorWIC.h b/skia/include/ports/SkImageGeneratorWIC.h new file mode 100644 index 00000000..75104557 --- /dev/null +++ b/skia/include/ports/SkImageGeneratorWIC.h @@ -0,0 +1,35 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" + +#if defined(SK_BUILD_FOR_WIN) + +#include "SkData.h" +#include "SkImageGenerator.h" + +#include + +/* + * Any Windows program that uses COM must initialize the COM library by calling + * the CoInitializeEx function. In addition, each thread that uses a COM + * interface must make a separate call to this function. + * + * For every successful call to CoInitializeEx, the thread must call + * CoUninitialize before it exits. + * + * SkImageGeneratorWIC requires the COM library and leaves it to the client to + * initialize COM for their application. + * + * For more information on initializing COM, please see: + * https://msdn.microsoft.com/en-us/library/windows/desktop/ff485844.aspx + */ +namespace SkImageGeneratorWIC { +SK_API std::unique_ptr MakeFromEncodedWIC(sk_sp); +} + +#endif // SK_BUILD_FOR_WIN diff --git a/skia/include/ports/SkRemotableFontMgr.h b/skia/include/ports/SkRemotableFontMgr.h new file mode 100644 index 00000000..12050c7e --- /dev/null +++ b/skia/include/ports/SkRemotableFontMgr.h @@ -0,0 +1,139 @@ +/* + * 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 SkRemotableFontMgr_DEFINED +#define SkRemotableFontMgr_DEFINED + +#include "../private/SkTemplates.h" +#include "SkFontStyle.h" +#include "SkRefCnt.h" +#include "SkTypes.h" + +class SkDataTable; +class SkStreamAsset; + +struct SK_API SkFontIdentity { + static const uint32_t kInvalidDataId = 0xFFFFFFFF; + + // Note that fDataId is a data identifier, not a font identifier. + // (fDataID, fTtcIndex) can be seen as a font identifier. + uint32_t fDataId; + uint32_t fTtcIndex; + + // On Linux/FontConfig there is also the ability to specify preferences for rendering + // antialias, embedded bitmaps, autohint, hinting, hintstyle, lcd rendering + // may all be set or set to no-preference + // (No-preference is resolved against globals set by the platform) + // Since they may be selected against, these are really 'extensions' to SkFontStyle. + // SkFontStyle should pick these up. + SkFontStyle fFontStyle; +}; + +class SK_API SkRemotableFontIdentitySet : public SkRefCnt { +public: + SkRemotableFontIdentitySet(int count, SkFontIdentity** data); + + int count() const { return fCount; } + const SkFontIdentity& at(int index) const { return fData[index]; } + + static SkRemotableFontIdentitySet* NewEmpty(); + +private: + SkRemotableFontIdentitySet() : fCount(0), fData() { } + + friend SkRemotableFontIdentitySet* sk_remotable_font_identity_set_new(); + + int fCount; + SkAutoTMalloc fData; + + typedef SkRefCnt INHERITED; +}; + +class SK_API SkRemotableFontMgr : public SkRefCnt { +public: + /** + * Returns all of the fonts with the given familyIndex. + * Returns NULL if the index is out of bounds. + * Returns empty if there are no fonts at the given index. + * + * The caller must unref() the returned object. + */ + virtual SkRemotableFontIdentitySet* getIndex(int familyIndex) const = 0; + + /** + * Returns the closest match to the given style in the given index. + * If there are no available fonts at the given index, the return value's + * data id will be kInvalidDataId. + */ + virtual SkFontIdentity matchIndexStyle(int familyIndex, const SkFontStyle&) const = 0; + + /** + * Returns all the fonts on the system with the given name. + * If the given name is NULL, will return the default font family. + * Never returns NULL; will return an empty set if the name is not found. + * + * It is possible that this will return fonts not accessible from + * getIndex(int) or matchIndexStyle(int, SkFontStyle) due to + * hidden or auto-activated fonts. + * + * The matching may be done in a system dependent way. The name may be + * matched case-insensitive, there may be system aliases which resolve, + * and names outside the current locale may be considered. However, this + * should only return fonts which are somehow associated with the requested + * name. + * + * The caller must unref() the returned object. + */ + virtual SkRemotableFontIdentitySet* matchName(const char familyName[]) const = 0; + + /** + * Returns the closest matching font to the specified name and style. + * If there are no available fonts which match the name, the return value's + * data id will be kInvalidDataId. + * If the given name is NULL, the match will be against any default fonts. + * + * It is possible that this will return a font identity not accessible from + * methods returning sets due to hidden or auto-activated fonts. + * + * The matching may be done in a system dependent way. The name may be + * matched case-insensitive, there may be system aliases which resolve, + * and names outside the current locale may be considered. However, this + * should only return a font which is somehow associated with the requested + * name. + * + * The caller must unref() the returned object. + */ + virtual SkFontIdentity matchNameStyle(const char familyName[], const SkFontStyle&) const = 0; + + /** + * Use the system fall-back to find a font for the given character. + * If no font can be found for the character, the return value's data id + * will be kInvalidDataId. + * If the name is NULL, the match will start against any default fonts. + * If the bpc47 is NULL, a default locale will be assumed. + * + * Note that bpc47 is a combination of ISO 639, 15924, and 3166-1 codes, + * so it is fine to just pass a ISO 639 here. + */ + virtual SkFontIdentity matchNameStyleCharacter(const char familyName[], const SkFontStyle&, + const char* bcp47[], int bcp47Count, + SkUnichar character) const=0; + + /** + * Returns the data for the given data id. + * Will return NULL if the data id is invalid. + * Note that this is a data id, not a font id. + * + * The caller must unref() the returned object. + */ + virtual SkStreamAsset* getData(int dataId) const = 0; + +private: + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/ports/SkTypeface_mac.h b/skia/include/ports/SkTypeface_mac.h new file mode 100644 index 00000000..14440b53 --- /dev/null +++ b/skia/include/ports/SkTypeface_mac.h @@ -0,0 +1,49 @@ +/* + * 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 SkTypeface_mac_DEFINED +#define SkTypeface_mac_DEFINED + +#include "SkTypeface.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include + +#ifdef SK_BUILD_FOR_MAC +#import +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified CTFontRef. The caller must call + * unref() when it is finished. + * + * The CFTypeRef parameter, if provided, will be kept referenced for the + * lifetime of the SkTypeface. This was introduced as a means to work around + * https://crbug.com/413332 . + */ +SK_API extern SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef, CFTypeRef = NULL); + +/** + * Returns the platform-specific CTFontRef handle for a + * given SkTypeface. Note that the returned CTFontRef gets + * released when the source SkTypeface is destroyed. + * + * This method is deprecated. It may only be used by Blink Mac + * legacy code in special cases related to text-shaping + * with AAT fonts, clipboard handling and font fallback. + * See https://code.google.com/p/skia/issues/detail?id=3408 + */ +SK_API extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkTypeface_mac_DEFINED diff --git a/skia/include/ports/SkTypeface_win.h b/skia/include/ports/SkTypeface_win.h new file mode 100644 index 00000000..06e7d33b --- /dev/null +++ b/skia/include/ports/SkTypeface_win.h @@ -0,0 +1,71 @@ +/* + * 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 SkTypeface_win_DEFINED +#define SkTypeface_win_DEFINED + +#include "../private/SkLeanWindows.h" +#include "SkTypeface.h" + +#ifdef SK_BUILD_FOR_WIN + +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified logfont. The caller is responsible + * for calling unref() when it is finished. + */ +SK_API SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT&); + +/** + * Copy the LOGFONT associated with this typeface into the lf parameter. Note + * that the lfHeight will need to be set afterwards, since the typeface does + * not track this (the paint does). + * typeface may be NULL, in which case we return the logfont for the default font. + */ +SK_API void SkLOGFONTFromTypeface(const SkTypeface* typeface, LOGFONT* lf); + +/** + * Set an optional callback to ensure that the data behind a LOGFONT is loaded. + * This will get called if Skia tries to access the data but hits a failure. + * Normally this is null, and is only required if the font data needs to be + * remotely (re)loaded. + */ +SK_API void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*)(const LOGFONT&)); + +// Experimental! +// +class SkFontMgr; +class SkRemotableFontMgr; +struct IDWriteFactory; +struct IDWriteFontCollection; +struct IDWriteFontFallback; + +SK_API sk_sp SkFontMgr_New_GDI(); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL, + IDWriteFontCollection* collection = NULL); +SK_API sk_sp SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback); + +/** + * Creates an SkFontMgr which renders using DirectWrite and obtains its data + * from the SkRemotableFontMgr. + * + * If DirectWrite could not be initialized, will return NULL. + */ +SK_API sk_sp SkFontMgr_New_DirectWriteRenderer(sk_sp); + +/** + * Creates an SkRemotableFontMgr backed by DirectWrite using the default + * system font collection in the current locale. + * + * If DirectWrite could not be initialized, will return NULL. + */ +SK_API sk_sp SkRemotableFontMgr_New_DirectWrite(); + +#endif // SK_BUILD_FOR_WIN +#endif // SkTypeface_win_DEFINED diff --git a/skia/include/private/GrAuditTrail.h b/skia/include/private/GrAuditTrail.h new file mode 100644 index 00000000..aacc4db5 --- /dev/null +++ b/skia/include/private/GrAuditTrail.h @@ -0,0 +1,183 @@ +/* + * 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 GrAuditTrail_DEFINED +#define GrAuditTrail_DEFINED + +#include "GrConfig.h" +#include "GrGpuResource.h" +#include "GrRenderTargetProxy.h" +#include "SkRect.h" +#include "SkString.h" +#include "SkTArray.h" +#include "SkTHash.h" + +class GrOp; + +/* + * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them + * to json. + * + * Capturing this information is expensive and consumes a lot of memory, therefore it is important + * to enable auditing only when required and disable it promptly. The AutoEnable class helps to + * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt + * with, be sure to call reset(), or the log will simply keep growing. + */ +class GrAuditTrail { +public: + GrAuditTrail() + : fClientID(kGrAuditTrailInvalidID) + , fEnabled(false) {} + + class AutoEnable { + public: + AutoEnable(GrAuditTrail* auditTrail) + : fAuditTrail(auditTrail) { + SkASSERT(!fAuditTrail->isEnabled()); + fAuditTrail->setEnabled(true); + } + + ~AutoEnable() { + SkASSERT(fAuditTrail->isEnabled()); + fAuditTrail->setEnabled(false); + } + + private: + GrAuditTrail* fAuditTrail; + }; + + class AutoManageOpList { + public: + AutoManageOpList(GrAuditTrail* auditTrail) + : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {} + + ~AutoManageOpList() { fAuditTrail->fullReset(); } + + private: + AutoEnable fAutoEnable; + GrAuditTrail* fAuditTrail; + }; + + class AutoCollectOps { + public: + AutoCollectOps(GrAuditTrail* auditTrail, int clientID) + : fAutoEnable(auditTrail), fAuditTrail(auditTrail) { + fAuditTrail->setClientID(clientID); + } + + ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); } + + private: + AutoEnable fAutoEnable; + GrAuditTrail* fAuditTrail; + }; + + void pushFrame(const char* framename) { + SkASSERT(fEnabled); + fCurrentStackTrace.push_back(SkString(framename)); + } + + void addOp(const GrOp*, GrRenderTargetProxy::UniqueID proxyID); + + void opsCombined(const GrOp* consumer, const GrOp* consumed); + + // Because op combining is heavily dependent on sequence of draw calls, these calls will only + // produce valid information for the given draw sequence which preceeded them. Specifically, ops + // of future draw calls may combine with previous ops and thus would invalidate the json. What + // this means is that for some sequence of draw calls N, the below toJson calls will only + // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or + // N - 1 draws depending on the actual combining algorithm used. + SkString toJson(bool prettyPrint = false) const; + + // returns a json string of all of the ops associated with a given client id + SkString toJson(int clientID, bool prettyPrint = false) const; + + bool isEnabled() { return fEnabled; } + void setEnabled(bool enabled) { fEnabled = enabled; } + + void setClientID(int clientID) { fClientID = clientID; } + + // We could just return our internal bookkeeping struct if copying the data out becomes + // a performance issue, but until then its nice to decouple + struct OpInfo { + struct Op { + int fClientID; + SkRect fBounds; + }; + + SkRect fBounds; + GrSurfaceProxy::UniqueID fProxyUniqueID; + SkTArray fOps; + }; + + void getBoundsByClientID(SkTArray* outInfo, int clientID); + void getBoundsByOpListID(OpInfo* outInfo, int opListID); + + void fullReset(); + + static const int kGrAuditTrailInvalidID; + +private: + // TODO if performance becomes an issue, we can move to using SkVarAlloc + struct Op { + SkString toJson() const; + SkString fName; + SkTArray fStackTrace; + SkRect fBounds; + int fClientID; + int fOpListID; + int fChildID; + }; + typedef SkTArray, true> OpPool; + + typedef SkTArray Ops; + + struct OpNode { + OpNode(const GrSurfaceProxy::UniqueID& proxyID) : fProxyUniqueID(proxyID) { } + SkString toJson() const; + + SkRect fBounds; + Ops fChildren; + const GrSurfaceProxy::UniqueID fProxyUniqueID; + }; + typedef SkTArray, true> OpList; + + void copyOutFromOpList(OpInfo* outOpInfo, int opListID); + + template + static void JsonifyTArray(SkString* json, const char* name, const T& array, + bool addComma); + + OpPool fOpPool; + SkTHashMap fIDLookup; + SkTHashMap fClientIDLookup; + OpList fOpList; + SkTArray fCurrentStackTrace; + + // The client can pass in an optional client ID which we will use to mark the ops + int fClientID; + bool fEnabled; +}; + +#define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \ + if (audit_trail->isEnabled()) { \ + audit_trail->invoke(__VA_ARGS__); \ + } + +#define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \ + GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename); + +#define GR_AUDIT_TRAIL_RESET(audit_trail) \ + //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset); + +#define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, proxy_id); + +#define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op); + +#endif diff --git a/skia/include/private/GrCCClipPath.h b/skia/include/private/GrCCClipPath.h new file mode 100644 index 00000000..8c1e7d4c --- /dev/null +++ b/skia/include/private/GrCCClipPath.h @@ -0,0 +1,81 @@ +/* + * 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 GrCCClipPath_DEFINED +#define GrCCClipPath_DEFINED + +#include "GrTextureProxy.h" +#include "SkPath.h" + +struct GrCCPerFlushResourceSpecs; +class GrCCAtlas; +class GrCCPerFlushResources; +class GrOnFlushResourceProvider; +class GrProxyProvider; + +/** + * These are keyed by SkPath generation ID, and store which device-space paths are accessed and + * where by clip FPs in a given opList. A single GrCCClipPath can be referenced by multiple FPs. At + * flush time their coverage count masks are packed into atlas(es) alongside normal DrawPathOps. + */ +class GrCCClipPath { +public: + GrCCClipPath() = default; + GrCCClipPath(const GrCCClipPath&) = delete; + + ~GrCCClipPath() { + // Ensure no clip FP exists with a dangling pointer back into this class. This works because + // a clip FP will have a ref on the proxy if it exists. + // + // This assert also guarantees there won't be a lazy proxy callback with a dangling pointer + // back into this class, since no proxy will exist after we destruct, if the assert passes. + SkASSERT(!fAtlasLazyProxy || fAtlasLazyProxy->isUnique_debugOnly()); + } + + bool isInitialized() const { return fAtlasLazyProxy != nullptr; } + void init(const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth, int rtHeight, + const GrCaps&); + + void addAccess(const SkIRect& accessRect) { + SkASSERT(this->isInitialized()); + fAccessRect.join(accessRect); + } + GrTextureProxy* atlasLazyProxy() const { + SkASSERT(this->isInitialized()); + return fAtlasLazyProxy.get(); + } + const SkPath& deviceSpacePath() const { + SkASSERT(this->isInitialized()); + return fDeviceSpacePath; + } + const SkIRect& pathDevIBounds() const { + SkASSERT(this->isInitialized()); + return fPathDevIBounds; + } + + void accountForOwnPath(GrCCPerFlushResourceSpecs*) const; + void renderPathInAtlas(GrCCPerFlushResources*, GrOnFlushResourceProvider*); + + const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); return fAtlasScale; } + const SkVector& atlasTranslate() const { SkASSERT(fHasAtlasTransform); return fAtlasTranslate; } + +private: + sk_sp fAtlasLazyProxy; + SkPath fDeviceSpacePath; + SkIRect fPathDevIBounds; + SkIRect fAccessRect; + + const GrCCAtlas* fAtlas = nullptr; + SkIVector fDevToAtlasOffset; // Translation from device space to location in atlas. + SkDEBUGCODE(bool fHasAtlas = false); + + SkVector fAtlasScale; + SkVector fAtlasTranslate; + SkDEBUGCODE(bool fHasAtlasTransform = false); +}; + +#endif diff --git a/skia/include/private/GrCCPerOpListPaths.h b/skia/include/private/GrCCPerOpListPaths.h new file mode 100644 index 00000000..61c3c59a --- /dev/null +++ b/skia/include/private/GrCCPerOpListPaths.h @@ -0,0 +1,32 @@ +/* + * 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 GrCCPerOpListPaths_DEFINED +#define GrCCPerOpListPaths_DEFINED + +#include "SkArenaAlloc.h" +#include "SkRefCnt.h" +#include "SkTInternalLList.h" +#include "GrCCClipPath.h" + +#include + +class GrCCDrawPathsOp; +class GrCCPerFlushResources; + +/** + * Tracks all the CCPR paths in a given opList that will be drawn when it flushes. + */ +// DDL TODO: given the usage pattern in DDL mode, this could probably be non-atomic refcounting. +struct GrCCPerOpListPaths : public SkRefCnt { + SkTInternalLList fDrawOps; // This class does not own these ops. + std::map fClipPaths; + SkSTArenaAlloc<10 * 1024> fAllocator{10 * 1024 * 2}; + sk_sp fFlushResources; +}; + +#endif diff --git a/skia/include/private/GrColor.h b/skia/include/private/GrColor.h new file mode 100644 index 00000000..1d1f54b0 --- /dev/null +++ b/skia/include/private/GrColor.h @@ -0,0 +1,108 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + + +#ifndef GrColor_DEFINED +#define GrColor_DEFINED + +#include "SkColor.h" +#include "SkColorData.h" +#include "SkColorPriv.h" +#include "SkHalf.h" + +/** + * GrColor is 4 bytes for R, G, B, A, in a specific order defined below. Whether the color is + * premultiplied or not depends on the context in which it is being used. + */ +typedef uint32_t GrColor; + +// shift amount to assign a component to a GrColor int +// These shift values are chosen for compatibility with GL attrib arrays +// ES doesn't allow BGRA vertex attrib order so if they were not in this order +// we'd have to swizzle in shaders. +#ifdef SK_CPU_BENDIAN + #define GrColor_SHIFT_R 24 + #define GrColor_SHIFT_G 16 + #define GrColor_SHIFT_B 8 + #define GrColor_SHIFT_A 0 +#else + #define GrColor_SHIFT_R 0 + #define GrColor_SHIFT_G 8 + #define GrColor_SHIFT_B 16 + #define GrColor_SHIFT_A 24 +#endif + +/** + * Pack 4 components (RGBA) into a GrColor int + */ +static inline GrColor GrColorPackRGBA(unsigned r, unsigned g, unsigned b, unsigned a) { + SkASSERT((uint8_t)r == r); + SkASSERT((uint8_t)g == g); + SkASSERT((uint8_t)b == b); + SkASSERT((uint8_t)a == a); + return (r << GrColor_SHIFT_R) | + (g << GrColor_SHIFT_G) | + (b << GrColor_SHIFT_B) | + (a << GrColor_SHIFT_A); +} + +// extract a component (byte) from a GrColor int + +#define GrColorUnpackR(color) (((color) >> GrColor_SHIFT_R) & 0xFF) +#define GrColorUnpackG(color) (((color) >> GrColor_SHIFT_G) & 0xFF) +#define GrColorUnpackB(color) (((color) >> GrColor_SHIFT_B) & 0xFF) +#define GrColorUnpackA(color) (((color) >> GrColor_SHIFT_A) & 0xFF) + +/** + * Since premultiplied means that alpha >= color, we construct a color with + * each component==255 and alpha == 0 to be "illegal" + */ +#define GrColor_ILLEGAL (~(0xFF << GrColor_SHIFT_A)) + +#define GrColor_WHITE 0xFFFFFFFF + +/** Normalizes and coverts an uint8_t to a float. [0, 255] -> [0.0, 1.0] */ +static inline float GrNormalizeByteToFloat(uint8_t value) { + static const float ONE_OVER_255 = 1.f / 255.f; + return value * ONE_OVER_255; +} + +/** Returns true if all channels are in [0, 1]. Used to pick vertex attribute types. */ +static inline bool SkPMColor4fFitsInBytes(const SkPMColor4f& color) { + SkASSERT(color.fA >= 0.0f && color.fA <= 1.0f); + return color.fR >= 0.0f && color.fR <= 1.0f && + color.fG >= 0.0f && color.fG <= 1.0f && + color.fB >= 0.0f && color.fB <= 1.0f; +} + +/** + * GrVertexColor is a helper for writing colors to a vertex attribute. It stores either GrColor + * or four half-float channels, depending on the wideColor parameter. GrVertexWriter will write + * the correct amount of data. Note that the GP needs to have been constructed with the correct + * attribute type for colors, to match the usage here. + */ +class GrVertexColor { +public: + explicit GrVertexColor(const SkPMColor4f& color, bool wideColor) + : fWideColor(wideColor) { + if (wideColor) { + SkFloatToHalf_finite_ftz(Sk4f::Load(color.vec())).store(&fColor); + } else { + fColor[0] = color.toBytes_RGBA(); + } + } + +private: + friend struct GrVertexWriter; + + uint32_t fColor[2]; + bool fWideColor; +}; + +#endif diff --git a/skia/include/private/GrOpList.h b/skia/include/private/GrOpList.h new file mode 100644 index 00000000..e596ca97 --- /dev/null +++ b/skia/include/private/GrOpList.h @@ -0,0 +1,189 @@ +/* + * 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 GrOpList_DEFINED +#define GrOpList_DEFINED + +#include "GrProxyRef.h" +#include "GrTextureProxy.h" +#include "SkColorData.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" + +class GrAuditTrail; +class GrCaps; +class GrOpFlushState; +class GrOpMemoryPool; +class GrRenderTargetOpList; +class GrResourceAllocator; +class GrResourceProvider; +class GrSurfaceProxy; +class GrTextureOpList; + +struct SkIPoint; +struct SkIRect; + +class GrOpList : public SkRefCnt { +public: + GrOpList(GrResourceProvider*, sk_sp, GrSurfaceProxy*, GrAuditTrail*); + ~GrOpList() override; + + // These four methods are invoked at flush time + bool instantiate(GrResourceProvider* resourceProvider); + // Instantiates any "threaded" texture proxies that are being prepared elsewhere + void instantiateDeferredProxies(GrResourceProvider* resourceProvider); + void prepare(GrOpFlushState* flushState); + bool execute(GrOpFlushState* flushState) { return this->onExecute(flushState); } + + virtual bool copySurface(GrContext*, + GrSurfaceProxy* dst, + GrSurfaceProxy* src, + const SkIRect& srcRect, + const SkIPoint& dstPoint) = 0; + + virtual void makeClosed(const GrCaps&) { + if (!this->isClosed()) { + this->setFlag(kClosed_Flag); + fTarget.removeRef(); + } + } + + // Called when this class will survive a flush and needs to truncate its ops and start over. + // TODO: ultimately it should be invalid for an op list to survive a flush. + // https://bugs.chromium.org/p/skia/issues/detail?id=7111 + virtual void endFlush(); + + bool isClosed() const { return this->isSetFlag(kClosed_Flag); } + + /* + * Notify this GrOpList that it relies on the contents of 'dependedOn' + */ + void addDependency(GrSurfaceProxy* dependedOn, const GrCaps& caps); + + /* + * Does this opList depend on 'dependedOn'? + */ + bool dependsOn(const GrOpList* dependedOn) const; + + /* + * Safely cast this GrOpList to a GrTextureOpList (if possible). + */ + virtual GrTextureOpList* asTextureOpList() { return nullptr; } + + /* + * Safely case this GrOpList to a GrRenderTargetOpList (if possible). + */ + virtual GrRenderTargetOpList* asRenderTargetOpList() { return nullptr; } + + uint32_t uniqueID() const { return fUniqueID; } + + /* + * Dump out the GrOpList dependency DAG + */ + SkDEBUGCODE(virtual void dump(bool printDependencies) const;) + + SkDEBUGCODE(virtual int numClips() const { return 0; }) + + // TODO: it would be nice for this to be hidden + void setStencilLoadOp(GrLoadOp loadOp) { fStencilLoadOp = loadOp; } + +protected: + bool isInstantiated() const; + + // In addition to just the GrSurface being allocated, has the stencil buffer been allocated (if + // it is required)? + bool isFullyInstantiated() const; + + // This is a backpointer to the GrOpMemoryPool that holds the memory for this opLists' ops. + // In the DDL case, these back pointers keep the DDL's GrOpMemoryPool alive as long as its + // constituent opLists survive. + sk_sp fOpMemoryPool; + GrSurfaceProxyRef fTarget; + GrAuditTrail* fAuditTrail; + + GrLoadOp fColorLoadOp = GrLoadOp::kLoad; + SkPMColor4f fLoadClearColor = SK_PMColor4fTRANSPARENT; + GrLoadOp fStencilLoadOp = GrLoadOp::kLoad; + + // List of texture proxies whose contents are being prepared on a worker thread + SkTArray fDeferredProxies; + +private: + friend class GrDrawingManager; // for resetFlag, TopoSortTraits & gatherProxyIntervals + + void addDependency(GrOpList* dependedOn); + void addDependent(GrOpList* dependent); + SkDEBUGCODE(bool isDependedent(const GrOpList* dependent) const); + SkDEBUGCODE(void validate() const); + void closeThoseWhoDependOnMe(const GrCaps&); + + // Remove all Ops which reference proxies that have not been instantiated. + virtual void purgeOpsWithUninstantiatedProxies() = 0; + + // Feed proxy usage intervals to the GrResourceAllocator class + virtual void gatherProxyIntervals(GrResourceAllocator*) const = 0; + + static uint32_t CreateUniqueID(); + + enum Flags { + kClosed_Flag = 0x01, //!< This GrOpList can't accept any more ops + + kWasOutput_Flag = 0x02, //!< Flag for topological sorting + kTempMark_Flag = 0x04, //!< Flag for topological sorting + }; + + void setFlag(uint32_t flag) { + fFlags |= flag; + } + + void resetFlag(uint32_t flag) { + fFlags &= ~flag; + } + + bool isSetFlag(uint32_t flag) const { + return SkToBool(fFlags & flag); + } + + struct TopoSortTraits { + static void Output(GrOpList* opList, int /* index */) { + opList->setFlag(GrOpList::kWasOutput_Flag); + } + static bool WasOutput(const GrOpList* opList) { + return opList->isSetFlag(GrOpList::kWasOutput_Flag); + } + static void SetTempMark(GrOpList* opList) { + opList->setFlag(GrOpList::kTempMark_Flag); + } + static void ResetTempMark(GrOpList* opList) { + opList->resetFlag(GrOpList::kTempMark_Flag); + } + static bool IsTempMarked(const GrOpList* opList) { + return opList->isSetFlag(GrOpList::kTempMark_Flag); + } + static int NumDependencies(const GrOpList* opList) { + return opList->fDependencies.count(); + } + static GrOpList* Dependency(GrOpList* opList, int index) { + return opList->fDependencies[index]; + } + }; + + virtual void onPrepare(GrOpFlushState* flushState) = 0; + virtual bool onExecute(GrOpFlushState* flushState) = 0; + + uint32_t fUniqueID; + uint32_t fFlags; + + // 'this' GrOpList relies on the output of the GrOpLists in 'fDependencies' + SkSTArray<1, GrOpList*, true> fDependencies; + // 'this' GrOpList's output is relied on by the GrOpLists in 'fDependents' + SkSTArray<1, GrOpList*, true> fDependents; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/private/GrProxyRef.h b/skia/include/private/GrProxyRef.h new file mode 100644 index 00000000..9d4419fb --- /dev/null +++ b/skia/include/private/GrProxyRef.h @@ -0,0 +1,151 @@ +/* + * 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 GrProxyRef_DEFINED +#define GrProxyRef_DEFINED + +#include "GrSurfaceProxy.h" +#include "GrTextureProxy.h" +#include "GrTypesPriv.h" + +/** + * Helper for owning a ref and/or pending IO on a GrSurfaceProxy. This is useful when ownership + * must transform from ref'ed to pending IO when the owner is recorded into a GrOpList. + */ +template class GrProxyRef { +public: + GrProxyRef() = default; + GrProxyRef(const GrProxyRef&) = delete; + GrProxyRef& operator=(const GrProxyRef&) = delete; + + /** ioType expresses what type of IO operations will be marked as pending on the proxy when + markPendingIO is called. */ + GrProxyRef(sk_sp proxy, GrIOType ioType) { this->setProxy(std::move(proxy), ioType); } + + ~GrProxyRef() { this->reset(); } + + /** ioType expresses what type of IO operations will be marked as + pending on the proxy when markPendingIO is called. */ + void setProxy(sk_sp proxy, GrIOType ioType) { + SkASSERT(!fPendingIO); + SkASSERT(SkToBool(fProxy) == fOwnRef); + SkSafeUnref(fProxy); + if (!proxy) { + fProxy = nullptr; + fOwnRef = false; + } else { + fProxy = proxy.release(); // due to the semantics of this class we unpack from sk_sp + fOwnRef = true; + fIOType = ioType; + } + } + + T* get() const { return fProxy; } + + /** Does this object own a pending read or write on the resource it is wrapping. */ + bool ownsPendingIO() const { return fPendingIO; } + + /** What type of IO does this represent? This is independent of whether a normal ref or a + pending IO is currently held. */ + GrIOType ioType() const { return fIOType; } + + /** Shortcut for calling setProxy() with NULL. It cannot be called after markingPendingIO + is called. */ + void reset() { + if (fPendingIO) { + SkASSERT(fProxy); + switch (fIOType) { + case kRead_GrIOType: + fProxy->completedRead(); + break; + case kWrite_GrIOType: + fProxy->completedWrite(); + break; + case kRW_GrIOType: + fProxy->completedRead(); + fProxy->completedWrite(); + break; + } + fPendingIO = false; + } + if (fOwnRef) { + SkASSERT(fProxy); + fProxy->unref(); + fOwnRef = false; + } + fProxy = nullptr; + } + + /** + * Called when transferring into an op list and therefore scheduled for an IO operation. It can + * only be called once. + */ + void markPendingIO() const { + // This should only be called when the owning GrProgramElement gets its first + // pendingExecution ref. + SkASSERT(!fPendingIO); + SkASSERT(fProxy); + fPendingIO = true; + switch (fIOType) { + case kRead_GrIOType: + fProxy->addPendingRead(); + break; + case kWrite_GrIOType: + fProxy->addPendingWrite(); + break; + case kRW_GrIOType: + fProxy->addPendingRead(); + fProxy->addPendingWrite(); + break; + } + } + + /** Called when the program element/draw state is no longer owned by GrOpList-client code. + This lets the cache know that the drawing code will no longer schedule additional reads or + writes to the resource using the program element or draw state. It can only be called once. + */ + void removeRef() const { + SkASSERT(fOwnRef); + SkASSERT(fPendingIO); + SkASSERT(fProxy); + fProxy->unref(); + fOwnRef = false; + } + + /** Called to indicate that the previous pending IO is complete. Useful when the owning object + still has refs, so it is not about to destroy this GrGpuResourceRef, but its previously + pending executions have been complete. Can only be called if removeRef() was not previously + called. */ + void pendingIOComplete() const { + SkASSERT(fOwnRef); + SkASSERT(fPendingIO); + switch (fIOType) { + case kRead_GrIOType: + fProxy->completedRead(); + break; + case kWrite_GrIOType: + fProxy->completedWrite(); + break; + case kRW_GrIOType: + fProxy->completedRead(); + fProxy->completedWrite(); + break; + } + fPendingIO = false; + } + +private: + T* fProxy = nullptr; + mutable bool fOwnRef = false; + mutable bool fPendingIO = false; + GrIOType fIOType = kRead_GrIOType; +}; + +using GrSurfaceProxyRef = GrProxyRef; +using GrTextureProxyRef = GrProxyRef; + +#endif diff --git a/skia/include/private/GrRenderTargetProxy.h b/skia/include/private/GrRenderTargetProxy.h new file mode 100644 index 00000000..1f5b79fd --- /dev/null +++ b/skia/include/private/GrRenderTargetProxy.h @@ -0,0 +1,133 @@ +/* + * 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 GrRenderTargetProxy_DEFINED +#define GrRenderTargetProxy_DEFINED + +#include "GrSurfaceProxy.h" +#include "GrTypesPriv.h" + +class GrResourceProvider; +class GrRenderTargetProxyPriv; + +// This class delays the acquisition of RenderTargets until they are actually +// required +// Beware: the uniqueID of the RenderTargetProxy will usually be different than +// the uniqueID of the RenderTarget it represents! +class GrRenderTargetProxy : virtual public GrSurfaceProxy { +public: + GrRenderTargetProxy* asRenderTargetProxy() override { return this; } + const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; } + + // Actually instantiate the backing rendertarget, if necessary. + bool instantiate(GrResourceProvider*) override; + + GrFSAAType fsaaType() const { + if (fSampleCnt <= 1) { + SkASSERT(!this->hasMixedSamples()); + return GrFSAAType::kNone; + } + return this->hasMixedSamples() ? GrFSAAType::kMixedSamples : GrFSAAType::kUnifiedMSAA; + } + + /* + * When instantiated does this proxy require a stencil buffer? + */ + void setNeedsStencil() { fNeedsStencil = true; } + bool needsStencil() const { return fNeedsStencil; } + + /** + * Returns the number of samples/pixel in the stencil buffer (One if non-MSAA). + */ + int numStencilSamples() const { return fSampleCnt; } + + /** + * Returns the number of samples/pixel in the color buffer (One if non-MSAA or mixed sampled). + */ + int numColorSamples() const { + return GrFSAAType::kMixedSamples == this->fsaaType() ? 1 : fSampleCnt; + } + + int maxWindowRectangles(const GrCaps& caps) const; + + // TODO: move this to a priv class! + bool refsWrappedObjects() const; + + // Provides access to special purpose functions. + GrRenderTargetProxyPriv rtPriv(); + const GrRenderTargetProxyPriv rtPriv() const; + +protected: + friend class GrProxyProvider; // for ctors + friend class GrRenderTargetProxyPriv; + + // Deferred version + GrRenderTargetProxy(const GrCaps&, const GrBackendFormat&, const GrSurfaceDesc&, + GrSurfaceOrigin, SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + + // Lazy-callback version + // There are two main use cases for lazily-instantiated proxies: + // basic knowledge - width, height, config, samples, origin are known + // minimal knowledge - only config is known. + // + // The basic knowledge version is used for DDL where we know the type of proxy we are going to + // use, but we don't have access to the GPU yet to instantiate it. + // + // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not + // know the final size until flush time. + GrRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType lazyType, + const GrBackendFormat&, const GrSurfaceDesc&, GrSurfaceOrigin, + SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + + // Wrapped version + GrRenderTargetProxy(sk_sp, GrSurfaceOrigin); + + sk_sp createSurface(GrResourceProvider*) const override; + +private: + void setHasMixedSamples() { + fSurfaceFlags |= GrInternalSurfaceFlags::kMixedSampled; + } + bool hasMixedSamples() const { return fSurfaceFlags & GrInternalSurfaceFlags::kMixedSampled; } + + void setSupportsWindowRects() { + fSurfaceFlags |= GrInternalSurfaceFlags::kWindowRectsSupport; + } + bool supportsWindowRects() const { + return fSurfaceFlags & GrInternalSurfaceFlags::kWindowRectsSupport; + } + + void setGLRTFBOIDIs0() { + fSurfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; + } + bool glRTFBOIDIs0() const { + return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0; + } + + + size_t onUninstantiatedGpuMemorySize() const override; + SkDEBUGCODE(void onValidateSurface(const GrSurface*) override;) + + // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings + // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes + // each class in the diamond require 16 byte alignment. Clang appears to layout the fields for + // each class to achieve the necessary alignment. However, ASAN checks the alignment of 'this' + // in the constructors, and always looks for the full 16 byte alignment, even if the fields in + // that particular class don't require it. Changing the size of this object can move the start + // address of other types, leading to this problem. + + int fSampleCnt; + bool fNeedsStencil; + + // For wrapped render targets the actual GrRenderTarget is stored in the GrIORefProxy class. + // For deferred proxies that pointer is filled in when we need to instantiate the + // deferred resource. + + typedef GrSurfaceProxy INHERITED; +}; + +#endif diff --git a/skia/include/private/GrSharedEnums.h b/skia/include/private/GrSharedEnums.h new file mode 100644 index 00000000..d745b70b --- /dev/null +++ b/skia/include/private/GrSharedEnums.h @@ -0,0 +1,37 @@ +/* + * 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 GrSharedEnums_DEFINED +#define GrSharedEnums_DEFINED + +/*************************************************************************************************/ +/* This file is used from both C++ and SkSL, so we need to stick to syntax compatible with both. */ +/*************************************************************************************************/ + +/** + * We have coverage effects that clip rendering to the edge of some geometric primitive. + * This enum specifies how that clipping is performed. Not all factories that take a + * GrProcessorEdgeType will succeed with all values and it is up to the caller to check for + * a NULL return. + */ +enum class GrClipEdgeType { + kFillBW, + kFillAA, + kInverseFillBW, + kInverseFillAA, + kHairlineAA, + + kLast = kHairlineAA +}; + +enum class PMConversion { + kToPremul = 0, + kToUnpremul = 1, + kPMConversionCnt = 2 +}; + +#endif diff --git a/skia/include/private/GrSingleOwner.h b/skia/include/private/GrSingleOwner.h new file mode 100644 index 00000000..64e63d3b --- /dev/null +++ b/skia/include/private/GrSingleOwner.h @@ -0,0 +1,55 @@ +/* + * 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 GrSingleOwner_DEFINED +#define GrSingleOwner_DEFINED + +#include "SkTypes.h" + +#ifdef SK_DEBUG +#include "SkMutex.h" +#include "SkThreadID.h" + +// This is a debug tool to verify an object is only being used from one thread at a time. +class GrSingleOwner { +public: + GrSingleOwner() : fOwner(kIllegalThreadID), fReentranceCount(0) {} + + struct AutoEnforce { + AutoEnforce(GrSingleOwner* so) : fSO(so) { fSO->enter(); } + ~AutoEnforce() { fSO->exit(); } + + GrSingleOwner* fSO; + }; + +private: + void enter() { + SkAutoMutexAcquire lock(fMutex); + SkThreadID self = SkGetThreadID(); + SkASSERT(fOwner == self || fOwner == kIllegalThreadID); + fReentranceCount++; + fOwner = self; + } + + void exit() { + SkAutoMutexAcquire lock(fMutex); + SkASSERT(fOwner == SkGetThreadID()); + fReentranceCount--; + if (fReentranceCount == 0) { + fOwner = kIllegalThreadID; + } + } + + SkMutex fMutex; + SkThreadID fOwner; // guarded by fMutex + int fReentranceCount; // guarded by fMutex +}; +#else +class GrSingleOwner {}; // Provide a dummy implementation so we can pass pointers to constructors +#endif + +#endif diff --git a/skia/include/private/GrSkSLFPFactoryCache.h b/skia/include/private/GrSkSLFPFactoryCache.h new file mode 100644 index 00000000..40e001a6 --- /dev/null +++ b/skia/include/private/GrSkSLFPFactoryCache.h @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSkSLFPFactoryCache_DEFINED +#define GrSkSLFPFactoryCache_DEFINED + +#include "SkRefCnt.h" + +#include + +class GrSkSLFPFactory; + +// This is a cache used by GrSkSLFP to retain GrSkSLFPFactory instances, so we don't have to +// re-process the SkSL source code every time we create a GrSkSLFP instance. +// For thread safety, it is important that GrSkSLFP only interact with the cache from methods that +// are only called from within the rendering thread, like onCreateGLSLInstance and +// onGetGLSLProcessorKey. +class GrSkSLFPFactoryCache : public SkNVRefCnt { +public: + // Returns a factory by its numeric index, or null if no such factory exists. Indices are + // allocated by GrSkSLFP::NewIndex(). + sk_sp get(int index); + + // Stores a new factory with the given index. + void set(int index, sk_sp factory); + + ~GrSkSLFPFactoryCache(); + +private: + std::vector fFactories; +}; + +#endif diff --git a/skia/include/private/GrSurfaceProxy.h b/skia/include/private/GrSurfaceProxy.h new file mode 100644 index 00000000..887400a6 --- /dev/null +++ b/skia/include/private/GrSurfaceProxy.h @@ -0,0 +1,526 @@ +/* + * 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 GrSurfaceProxy_DEFINED +#define GrSurfaceProxy_DEFINED + +#include "../private/SkNoncopyable.h" +#include "GrBackendSurface.h" +#include "GrGpuResource.h" +#include "GrSurface.h" + +#include "SkRect.h" + +class GrCaps; +class GrOpList; +class GrProxyProvider; +class GrRenderTargetOpList; +class GrRenderTargetProxy; +class GrResourceProvider; +class GrSurfaceContext; +class GrSurfaceProxyPriv; +class GrTextureOpList; +class GrTextureProxy; + +// This class replicates the functionality GrIORef but tracks the +// utilitization for later resource allocation (for the deferred case) and +// forwards on the utilization in the wrapped case +class GrIORefProxy : public SkNoncopyable { +public: + void ref() const { + this->validate(); + + ++fRefCnt; + if (fTarget) { + fTarget->ref(); + } + } + + void unref() const { + this->validate(); + + if (fTarget) { + fTarget->unref(); + } + + --fRefCnt; + this->didRemoveRefOrPendingIO(); + } + +#ifdef SK_DEBUG + bool isUnique_debugOnly() const { // For asserts. + SkASSERT(fRefCnt >= 0 && fPendingWrites >= 0 && fPendingReads >= 0); + return 1 == fRefCnt + fPendingWrites + fPendingReads; + } +#endif + + void release() { + // The proxy itself may still have multiple refs. It can be owned by an SkImage and multiple + // SkDeferredDisplayLists at the same time if we are using DDLs. + SkASSERT(0 == fPendingReads); + SkASSERT(0 == fPendingWrites); + + SkASSERT(fRefCnt == fTarget->fRefCnt); + SkASSERT(!fTarget->internalHasPendingIO()); + // In the current hybrid world, the proxy and backing surface are ref/unreffed in + // synchrony. In this instance we're deInstantiating the proxy so, regardless of the + // number of refs on the backing surface, we're going to remove it. If/when the proxy + // is re-instantiated all the refs on the proxy (presumably due to multiple uses in ops) + // will be transfered to the new surface. + for (int refs = fTarget->fRefCnt; refs; --refs) { + fTarget->unref(); + } + fTarget = nullptr; + } + + void validate() const { +#ifdef SK_DEBUG + SkASSERT(fRefCnt >= 0); + SkASSERT(fPendingReads >= 0); + SkASSERT(fPendingWrites >= 0); + SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 1); + + if (fTarget) { + // The backing GrSurface can have more refs than the proxy if the proxy + // started off wrapping an external resource (that came in with refs). + // The GrSurface should never have fewer refs than the proxy however. + SkASSERT(fTarget->fRefCnt >= fRefCnt); + SkASSERT(fTarget->fPendingReads >= fPendingReads); + SkASSERT(fTarget->fPendingWrites >= fPendingWrites); + } +#endif + } + + int32_t getBackingRefCnt_TestOnly() const; + int32_t getPendingReadCnt_TestOnly() const; + int32_t getPendingWriteCnt_TestOnly() const; + + void addPendingRead() const { + this->validate(); + + ++fPendingReads; + if (fTarget) { + fTarget->addPendingRead(); + } + } + + void completedRead() const { + this->validate(); + + if (fTarget) { + fTarget->completedRead(); + } + + --fPendingReads; + this->didRemoveRefOrPendingIO(); + } + + void addPendingWrite() const { + this->validate(); + + ++fPendingWrites; + if (fTarget) { + fTarget->addPendingWrite(); + } + } + + void completedWrite() const { + this->validate(); + + if (fTarget) { + fTarget->completedWrite(); + } + + --fPendingWrites; + this->didRemoveRefOrPendingIO(); + } + +protected: + GrIORefProxy() : fTarget(nullptr), fRefCnt(1), fPendingReads(0), fPendingWrites(0) {} + GrIORefProxy(sk_sp surface) : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { + // Since we're manually forwarding on refs & unrefs we don't want sk_sp doing + // anything extra. + fTarget = surface.release(); + } + virtual ~GrIORefProxy() { + // We don't unref 'fTarget' here since the 'unref' method will already + // have forwarded on the unref call that got us here. + } + + // This GrIORefProxy was deferred before but has just been instantiated. To + // make all the reffing & unreffing work out we now need to transfer any deferred + // refs & unrefs to the new GrSurface + void transferRefs() { + SkASSERT(fTarget); + + SkASSERT(fTarget->fRefCnt > 0); + fTarget->fRefCnt += (fRefCnt-1); // don't xfer the proxy's creation ref + fTarget->fPendingReads += fPendingReads; + fTarget->fPendingWrites += fPendingWrites; + } + + int32_t internalGetProxyRefCnt() const { + return fRefCnt; + } + + bool internalHasPendingIO() const { + if (fTarget) { + return fTarget->internalHasPendingIO(); + } + + return SkToBool(fPendingWrites | fPendingReads); + } + + bool internalHasPendingWrite() const { + if (fTarget) { + return fTarget->internalHasPendingWrite(); + } + + return SkToBool(fPendingWrites); + } + + // For deferred proxies this will be null. For wrapped proxies it will point to the + // wrapped resource. + GrSurface* fTarget; + +private: + // This class is used to manage conversion of refs to pending reads/writes. + template friend class GrProxyRef; + + void didRemoveRefOrPendingIO() const { + if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { + delete this; + } + } + + mutable int32_t fRefCnt; + mutable int32_t fPendingReads; + mutable int32_t fPendingWrites; +}; + +class GrSurfaceProxy : public GrIORefProxy { +public: + enum class LazyInstantiationType { + kSingleUse, // Instantiation callback is allowed to be called only once + kMultipleUse, // Instantiation callback can be called multiple times. + kUninstantiate, // Instantiation callback can be called multiple times, + // but we will uninstantiate the proxy after every flush + }; + + enum class LazyState { + kNot, // The proxy is instantiated or does not have a lazy callback + kPartially, // The proxy has a lazy callback but knows basic information about itself. + kFully, // The proxy has a lazy callback and also doesn't know its width, height, etc. + }; + + LazyState lazyInstantiationState() const { + if (fTarget || !SkToBool(fLazyInstantiateCallback)) { + return LazyState::kNot; + } else { + if (fWidth <= 0) { + SkASSERT(fHeight <= 0); + return LazyState::kFully; + } else { + SkASSERT(fHeight > 0); + return LazyState::kPartially; + } + } + } + + GrPixelConfig config() const { return fConfig; } + int width() const { + SkASSERT(LazyState::kFully != this->lazyInstantiationState()); + return fWidth; + } + int height() const { + SkASSERT(LazyState::kFully != this->lazyInstantiationState()); + return fHeight; + } + + SkISize isize() const { return {fWidth, fHeight}; } + + int worstCaseWidth() const; + int worstCaseHeight() const; + /** + * Helper that gets the width and height of the surface as a bounding rectangle. + */ + SkRect getBoundsRect() const { + SkASSERT(LazyState::kFully != this->lazyInstantiationState()); + return SkRect::MakeIWH(this->width(), this->height()); + } + /** + * Helper that gets the worst case width and height of the surface as a bounding rectangle. + */ + SkRect getWorstCaseBoundsRect() const { + SkASSERT(LazyState::kFully != this->lazyInstantiationState()); + return SkRect::MakeIWH(this->worstCaseWidth(), this->worstCaseHeight()); + } + + GrSurfaceOrigin origin() const { + SkASSERT(kTopLeft_GrSurfaceOrigin == fOrigin || kBottomLeft_GrSurfaceOrigin == fOrigin); + return fOrigin; + } + + const GrBackendFormat& backendFormat() const { return fFormat; } + + GrTextureType textureType() const { return fFormat.textureType(); } + + class UniqueID { + public: + static UniqueID InvalidID() { + return UniqueID(uint32_t(SK_InvalidUniqueID)); + } + + // wrapped + explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } + // deferred and lazy-callback + UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } + + uint32_t asUInt() const { return fID; } + + bool operator==(const UniqueID& other) const { + return fID == other.fID; + } + bool operator!=(const UniqueID& other) const { + return !(*this == other); + } + + void makeInvalid() { fID = SK_InvalidUniqueID; } + bool isInvalid() const { return SK_InvalidUniqueID == fID; } + + private: + explicit UniqueID(uint32_t id) : fID(id) {} + + uint32_t fID; + }; + + /* + * The contract for the uniqueID is: + * for wrapped resources: + * the uniqueID will match that of the wrapped resource + * + * for deferred resources: + * the uniqueID will be different from the real resource, when it is allocated + * the proxy's uniqueID will not change across the instantiate call + * + * the uniqueIDs of the proxies and the resources draw from the same pool + * + * What this boils down to is that the uniqueID of a proxy can be used to consistently + * track/identify a proxy but should never be used to distinguish between + * resources and proxies - beware! + */ + UniqueID uniqueID() const { return fUniqueID; } + + UniqueID underlyingUniqueID() const { + if (fTarget) { + return UniqueID(fTarget->uniqueID()); + } + + return fUniqueID; + } + + virtual bool instantiate(GrResourceProvider* resourceProvider) = 0; + + void deInstantiate(); + + /** + * Proxies that are already instantiated and whose backing surface cannot be recycled to + * instantiate other proxies do not need to be considered by GrResourceAllocator. + */ + bool canSkipResourceAllocator() const; + + /** + * @return the texture proxy associated with the surface proxy, may be NULL. + */ + virtual GrTextureProxy* asTextureProxy() { return nullptr; } + virtual const GrTextureProxy* asTextureProxy() const { return nullptr; } + + /** + * @return the render target proxy associated with the surface proxy, may be NULL. + */ + virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; } + virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; } + + bool isInstantiated() const { return SkToBool(fTarget); } + + // If the proxy is already instantiated, return its backing GrTexture; if not, return null. + GrSurface* peekSurface() const { return fTarget; } + + // If this is a texture proxy and the proxy is already instantiated, return its backing + // GrTexture; if not, return null. + GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; } + + // If this is a render target proxy and the proxy is already instantiated, return its backing + // GrRenderTarget; if not, return null. + GrRenderTarget* peekRenderTarget() const { + return fTarget ? fTarget->asRenderTarget() : nullptr; + } + + /** + * Does the resource count against the resource budget? + */ + SkBudgeted isBudgeted() const { return fBudgeted; } + + void setLastOpList(GrOpList* opList); + GrOpList* getLastOpList() { return fLastOpList; } + + GrRenderTargetOpList* getLastRenderTargetOpList(); + GrTextureOpList* getLastTextureOpList(); + + /** + * Retrieves the amount of GPU memory that will be or currently is used by this resource + * in bytes. It is approximate since we aren't aware of additional padding or copies made + * by the driver. + * + * @return the amount of GPU memory used in bytes + */ + size_t gpuMemorySize() const { + SkASSERT(LazyState::kFully != this->lazyInstantiationState()); + if (fTarget) { + return fTarget->gpuMemorySize(); + } + if (kInvalidGpuMemorySize == fGpuMemorySize) { + fGpuMemorySize = this->onUninstantiatedGpuMemorySize(); + SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); + } + return fGpuMemorySize; + } + + // Helper function that creates a temporary SurfaceContext to perform the copy + // It always returns a kExact-backed proxy bc it is used when converting an SkSpecialImage + // to an SkImage. The copy is is not a render target and not multisampled. + static sk_sp Copy(GrContext*, GrSurfaceProxy* src, GrMipMapped, + SkIRect srcRect, SkBudgeted); + + // Copy the entire 'src' + // It always returns a kExact-backed proxy bc it is used in SkGpuDevice::snapSpecial + static sk_sp Copy(GrContext* context, GrSurfaceProxy* src, GrMipMapped, + SkBudgeted budgeted); + + // Test-only entry point - should decrease in use as proxies propagate + static sk_sp TestCopy(GrContext* context, const GrSurfaceDesc& dstDesc, + GrSurfaceOrigin, GrSurfaceProxy* srcProxy); + + bool isWrapped_ForTesting() const; + + SkDEBUGCODE(void validate(GrContext*) const;) + + // Provides access to functions that aren't part of the public API. + inline GrSurfaceProxyPriv priv(); + inline const GrSurfaceProxyPriv priv() const; + + GrInternalSurfaceFlags testingOnly_getFlags() const; + +protected: + // Deferred version + GrSurfaceProxy(const GrBackendFormat& format, const GrSurfaceDesc& desc, + GrSurfaceOrigin origin, SkBackingFit fit, + SkBudgeted budgeted, GrInternalSurfaceFlags surfaceFlags) + : GrSurfaceProxy(nullptr, LazyInstantiationType::kSingleUse, format, desc, origin, fit, + budgeted, surfaceFlags) { + // Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources + } + + using LazyInstantiateCallback = std::function(GrResourceProvider*)>; + + // Lazy-callback version + GrSurfaceProxy(LazyInstantiateCallback&&, LazyInstantiationType, + const GrBackendFormat& format, const GrSurfaceDesc&, GrSurfaceOrigin, + SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + + // Wrapped version + GrSurfaceProxy(sk_sp, GrSurfaceOrigin, SkBackingFit); + + virtual ~GrSurfaceProxy(); + + friend class GrSurfaceProxyPriv; + + // Methods made available via GrSurfaceProxyPriv + int32_t getProxyRefCnt() const { + return this->internalGetProxyRefCnt(); + } + + bool hasPendingIO() const { + return this->internalHasPendingIO(); + } + + bool hasPendingWrite() const { + return this->internalHasPendingWrite(); + } + + void computeScratchKey(GrScratchKey*) const; + + virtual sk_sp createSurface(GrResourceProvider*) const = 0; + void assign(sk_sp surface); + + sk_sp createSurfaceImpl(GrResourceProvider*, int sampleCnt, bool needsStencil, + GrSurfaceDescFlags, GrMipMapped) const; + + bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, bool needsStencil, + GrSurfaceDescFlags descFlags, GrMipMapped, const GrUniqueKey*); + + // In many cases these flags aren't actually known until the proxy has been instantiated. + // However, Ganesh frequently needs to change its behavior based on these settings. For + // internally create proxies we will know these properties ahead of time. For wrapped + // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the + // call sites to provide the required information ahead of time. At instantiation time + // we verify that the assumed properties match the actual properties. + GrInternalSurfaceFlags fSurfaceFlags; + +private: + // For wrapped resources, 'fFormat', 'fConfig', 'fWidth', 'fHeight', and 'fOrigin; will always + // be filled in from the wrapped resource. + GrBackendFormat fFormat; + GrPixelConfig fConfig; + int fWidth; + int fHeight; + GrSurfaceOrigin fOrigin; + SkBackingFit fFit; // always kApprox for lazy-callback resources + // always kExact for wrapped resources + mutable SkBudgeted fBudgeted; // always kYes for lazy-callback resources + // set from the backing resource for wrapped resources + // mutable bc of SkSurface/SkImage wishy-washiness + + const UniqueID fUniqueID; // set from the backing resource for wrapped resources + + LazyInstantiateCallback fLazyInstantiateCallback; + // If this is set to kSingleuse, then after one call to fLazyInstantiateCallback we will cleanup + // the lazy callback and then delete it. This will allow for any refs and resources being held + // by the standard function to be released. This is specifically useful in non-dll cases where + // we make lazy proxies and instantiate them immediately. + // Note: This is ignored if fLazyInstantiateCallback is null. + LazyInstantiationType fLazyInstantiationType; + + SkDEBUGCODE(void validateSurface(const GrSurface*);) + SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;) + + static const size_t kInvalidGpuMemorySize = ~static_cast(0); + SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) + + virtual size_t onUninstantiatedGpuMemorySize() const = 0; + + bool fNeedsClear; + + // This entry is lazily evaluated so, when the proxy wraps a resource, the resource + // will be called but, when the proxy is deferred, it will compute the answer itself. + // If the proxy computes its own answer that answer is checked (in debug mode) in + // the instantiation method. + mutable size_t fGpuMemorySize; + + // The last opList that wrote to or is currently going to write to this surface + // The opList can be closed (e.g., no surface context is currently bound + // to this proxy). + // This back-pointer is required so that we can add a dependancy between + // the opList used to create the current contents of this surface + // and the opList of a destination surface to which this one is being drawn or copied. + // This pointer is unreffed. OpLists own a ref on their surface proxies. + GrOpList* fLastOpList; + + typedef GrIORefProxy INHERITED; +}; + +#endif diff --git a/skia/include/private/GrTextureProxy.h b/skia/include/private/GrTextureProxy.h new file mode 100644 index 00000000..cdfd07ac --- /dev/null +++ b/skia/include/private/GrTextureProxy.h @@ -0,0 +1,145 @@ +/* + * 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 GrTextureProxy_DEFINED +#define GrTextureProxy_DEFINED + +#include "GrSamplerState.h" +#include "GrSurfaceProxy.h" + +class GrCaps; +class GrDeferredProxyUploader; +class GrProxyProvider; +class GrResourceProvider; +class GrTextureOpList; +class GrTextureProxyPriv; + +// This class delays the acquisition of textures until they are actually required +class GrTextureProxy : virtual public GrSurfaceProxy { +public: + GrTextureProxy* asTextureProxy() override { return this; } + const GrTextureProxy* asTextureProxy() const override { return this; } + + // Actually instantiate the backing texture, if necessary + bool instantiate(GrResourceProvider*) override; + + GrSamplerState::Filter highestFilterMode() const; + + // If we are instantiated and have a target, return the mip state of that target. Otherwise + // returns the proxy's mip state from creation time. This is useful for lazy proxies which may + // claim to not need mips at creation time, but the instantiation happens to give us a mipped + // target. In that case we should use that for our benefit to avoid possible copies/mip + // generation later. + GrMipMapped mipMapped() const; + + // Returns the GrMipMapped value of the proxy from creation time regardless of whether it has + // been instantiated or not. + GrMipMapped proxyMipMapped() const { return fMipMapped; } + + /** If true then the texture does not support MIP maps and only supports clamp wrap mode. */ + bool hasRestrictedSampling() const { + return GrTextureTypeHasRestrictedSampling(this->textureType()); + } + /** + * Return the texture proxy's unique key. It will be invalid if the proxy doesn't have one. + */ + const GrUniqueKey& getUniqueKey() const { +#ifdef SK_DEBUG + if (fTarget && fUniqueKey.isValid()) { + SkASSERT(fTarget->getUniqueKey().isValid()); + // It is possible for a non-keyed proxy to have a uniquely keyed resource assigned to + // it. This just means that a future user of the resource will be filling it with unique + // data. However, if the proxy has a unique key its attached resource should also + // have that key. + SkASSERT(fUniqueKey == fTarget->getUniqueKey()); + } +#endif + + return fUniqueKey; + } + + /** + * Internal-only helper class used for manipulations of the resource by the cache. + */ + class CacheAccess; + inline CacheAccess cacheAccess(); + inline const CacheAccess cacheAccess() const; + + // Provides access to special purpose functions. + GrTextureProxyPriv texPriv(); + const GrTextureProxyPriv texPriv() const; + +protected: + // DDL TODO: rm the GrSurfaceProxy friending + friend class GrSurfaceProxy; // for ctors + friend class GrProxyProvider; // for ctors + friend class GrTextureProxyPriv; + + // Deferred version - when constructed with data the origin is always kTopLeft. + GrTextureProxy(const GrBackendFormat&, const GrSurfaceDesc& srcDesc, GrMipMapped, SkBackingFit, + SkBudgeted, const void* srcData, size_t srcRowBytes, GrInternalSurfaceFlags); + + // Deferred version - no data. + GrTextureProxy(const GrBackendFormat&, const GrSurfaceDesc& srcDesc, GrSurfaceOrigin, + GrMipMapped, SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + + // Lazy-callback version + // There are two main use cases for lazily-instantiated proxies: + // basic knowledge - width, height, config, origin are known + // minimal knowledge - only config is known. + // + // The basic knowledge version is used for DDL where we know the type of proxy we are going to + // use, but we don't have access to the GPU yet to instantiate it. + // + // The minimal knowledge version is used for CCPR where we are generating an atlas but we do not + // know the final size until flush time. + GrTextureProxy(LazyInstantiateCallback&&, LazyInstantiationType, const GrBackendFormat&, + const GrSurfaceDesc& desc, GrSurfaceOrigin, GrMipMapped, SkBackingFit, + SkBudgeted, GrInternalSurfaceFlags); + + // Wrapped version + GrTextureProxy(sk_sp, GrSurfaceOrigin); + + ~GrTextureProxy() override; + + sk_sp createSurface(GrResourceProvider*) const override; + +private: + // WARNING: Be careful when adding or removing fields here. ASAN is likely to trigger warnings + // when instantiating GrTextureRenderTargetProxy. The std::function in GrSurfaceProxy makes + // each class in the diamond require 16 byte alignment. Clang appears to layout the fields for + // each class to achieve the necessary alignment. However, ASAN checks the alignment of 'this' + // in the constructors, and always looks for the full 16 byte alignment, even if the fields in + // that particular class don't require it. Changing the size of this object can move the start + // address of other types, leading to this problem. + + GrMipMapped fMipMapped; + + GrUniqueKey fUniqueKey; + GrProxyProvider* fProxyProvider; // only set when fUniqueKey is valid + + // Only used for proxies whose contents are being prepared on a worker thread. This object + // stores the texture data, allowing the proxy to remain uninstantiated until flush. At that + // point, the proxy is instantiated, and this data is used to perform an ASAP upload. + std::unique_ptr fDeferredUploader; + + size_t onUninstantiatedGpuMemorySize() const override; + + // Methods made available via GrTextureProxy::CacheAccess + void setUniqueKey(GrProxyProvider*, const GrUniqueKey&); + void clearUniqueKey(); + + SkDEBUGCODE(void onValidateSurface(const GrSurface*) override;) + + // For wrapped proxies the GrTexture pointer is stored in GrIORefProxy. + // For deferred proxies that pointer will be filled in when we need to instantiate + // the deferred resource + + typedef GrSurfaceProxy INHERITED; +}; + +#endif diff --git a/skia/include/private/GrTypesPriv.h b/skia/include/private/GrTypesPriv.h new file mode 100644 index 00000000..2e99e960 --- /dev/null +++ b/skia/include/private/GrTypesPriv.h @@ -0,0 +1,1390 @@ +/* + * 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 GrTypesPriv_DEFINED +#define GrTypesPriv_DEFINED + +#include +#include "GrSharedEnums.h" +#include "GrTypes.h" +#include "SkCanvas.h" +#include "SkImageInfo.h" +#include "SkImageInfoPriv.h" +#include "SkRefCnt.h" +#include "SkWeakRefCnt.h" + +class GrCaps; + +// The old libstdc++ uses the draft name "monotonic_clock" rather than "steady_clock". This might +// not actually be monotonic, depending on how libstdc++ was built. However, this is only currently +// used for idle resource purging so it shouldn't cause a correctness problem. +#if defined(__GLIBCXX__) && (__GLIBCXX__ < 20130000) +using GrStdSteadyClock = std::chrono::monotonic_clock; +#else +using GrStdSteadyClock = std::chrono::steady_clock; +#endif + +/** + * Pixel configurations. This type conflates texture formats, CPU pixel formats, and + * premultipliedness. We are moving away from it towards SkColorType and backend API (GL, Vulkan) + * texture formats in the pulbic API. Right now this mostly refers to texture formats as we're + * migrating. + */ +enum GrPixelConfig { + kUnknown_GrPixelConfig, + kAlpha_8_GrPixelConfig, + kGray_8_GrPixelConfig, + kRGB_565_GrPixelConfig, + kRGBA_4444_GrPixelConfig, + kRGBA_8888_GrPixelConfig, + kRGB_888_GrPixelConfig, + kBGRA_8888_GrPixelConfig, + kSRGBA_8888_GrPixelConfig, + kSBGRA_8888_GrPixelConfig, + kRGBA_1010102_GrPixelConfig, + kRGBA_float_GrPixelConfig, + kRG_float_GrPixelConfig, + kAlpha_half_GrPixelConfig, + kRGBA_half_GrPixelConfig, + + /** For internal usage. */ + kPrivateConfig1_GrPixelConfig, + kPrivateConfig2_GrPixelConfig, + kPrivateConfig3_GrPixelConfig, + kPrivateConfig4_GrPixelConfig, + kPrivateConfig5_GrPixelConfig, + + kLast_GrPixelConfig = kPrivateConfig5_GrPixelConfig +}; +static const int kGrPixelConfigCnt = kLast_GrPixelConfig + 1; + +// Aliases for pixel configs that match skia's byte order. +#ifndef SK_CPU_LENDIAN +#error "Skia gpu currently assumes little endian" +#endif +#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A) +static const GrPixelConfig kSkia8888_GrPixelConfig = kBGRA_8888_GrPixelConfig; +#elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A) +static const GrPixelConfig kSkia8888_GrPixelConfig = kRGBA_8888_GrPixelConfig; +#else + #error "SK_*32_SHIFT values must correspond to GL_BGRA or GL_RGBA format." +#endif + +/** + * Geometric primitives used for drawing. + */ +enum class GrPrimitiveType { + kTriangles, + kTriangleStrip, + kPoints, + kLines, // 1 pix wide only + kLineStrip, // 1 pix wide only + kLinesAdjacency // requires geometry shader support. +}; +static constexpr int kNumGrPrimitiveTypes = (int)GrPrimitiveType::kLinesAdjacency + 1; + +static constexpr bool GrIsPrimTypeLines(GrPrimitiveType type) { + return GrPrimitiveType::kLines == type || + GrPrimitiveType::kLineStrip == type || + GrPrimitiveType::kLinesAdjacency == type; +} + +static constexpr bool GrIsPrimTypeTris(GrPrimitiveType type) { + return GrPrimitiveType::kTriangles == type || GrPrimitiveType::kTriangleStrip == type; +} + +static constexpr bool GrPrimTypeRequiresGeometryShaderSupport(GrPrimitiveType type) { + return GrPrimitiveType::kLinesAdjacency == type; +} + +enum class GrPrimitiveRestart : bool { + kNo = false, + kYes = true +}; + +/** + * Formats for masks, used by the font cache. Important that these are 0-based. + */ +enum GrMaskFormat { + kA8_GrMaskFormat, //!< 1-byte per pixel + kA565_GrMaskFormat, //!< 2-bytes per pixel, RGB represent 3-channel LCD coverage + kARGB_GrMaskFormat, //!< 4-bytes per pixel, color format + + kLast_GrMaskFormat = kARGB_GrMaskFormat +}; +static const int kMaskFormatCount = kLast_GrMaskFormat + 1; + +/** + * Return the number of bytes-per-pixel for the specified mask format. + */ +static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) { + SkASSERT(format < kMaskFormatCount); + // kA8 (0) -> 1 + // kA565 (1) -> 2 + // kARGB (2) -> 4 + static const int sBytesPerPixel[] = {1, 2, 4}; + static_assert(SK_ARRAY_COUNT(sBytesPerPixel) == kMaskFormatCount, "array_size_mismatch"); + static_assert(kA8_GrMaskFormat == 0, "enum_order_dependency"); + static_assert(kA565_GrMaskFormat == 1, "enum_order_dependency"); + static_assert(kARGB_GrMaskFormat == 2, "enum_order_dependency"); + + return sBytesPerPixel[(int)format]; +} + +/** + * Optional bitfield flags that can be set on GrSurfaceDesc (below). + */ +enum GrSurfaceFlags { + kNone_GrSurfaceFlags = 0x0, + /** + * Creates a texture that can be rendered to as a GrRenderTarget. Use + * GrTexture::asRenderTarget() to access. + */ + kRenderTarget_GrSurfaceFlag = 0x1, + /** + * Clears to zero on creation. It will cause creation failure if initial data is supplied to the + * texture. This only affects the base level if the texture is created with MIP levels. + */ + kPerformInitialClear_GrSurfaceFlag = 0x2 +}; +GR_MAKE_BITFIELD_OPS(GrSurfaceFlags) + +typedef GrSurfaceFlags GrSurfaceDescFlags; + +/** + * Describes a surface to be created. + */ +struct GrSurfaceDesc { + GrSurfaceDesc() + : fFlags(kNone_GrSurfaceFlags) + , fWidth(0) + , fHeight(0) + , fConfig(kUnknown_GrPixelConfig) + , fSampleCnt(1) {} + + GrSurfaceDescFlags fFlags; //!< bitfield of TextureFlags + int fWidth; //!< Width of the texture + int fHeight; //!< Height of the texture + + /** + * Format of source data of the texture. Not guaranteed to be the same as + * internal format used by 3D API. + */ + GrPixelConfig fConfig; + + /** + * The number of samples per pixel. Zero is treated equivalently to 1. This only + * applies if the kRenderTarget_GrSurfaceFlag is set. The actual number + * of samples may not exactly match the request. The request will be rounded + * up to the next supported sample count. A value larger than the largest + * supported sample count will fail. + */ + int fSampleCnt; +}; + +/** Ownership rules for external GPU resources imported into Skia. */ +enum GrWrapOwnership { + /** Skia will assume the client will keep the resource alive and Skia will not free it. */ + kBorrow_GrWrapOwnership, + + /** Skia will assume ownership of the resource and free it. */ + kAdopt_GrWrapOwnership, +}; + +/** + * Clips are composed from these objects. + */ +enum GrClipType { + kRect_ClipType, + kPath_ClipType +}; + +enum class GrScissorTest : bool { + kDisabled = false, + kEnabled = true +}; + +struct GrMipLevel { + const void* fPixels; + size_t fRowBytes; +}; + +/** + * This enum is used to specify the load operation to be used when an opList/GrGpuCommandBuffer + * begins execution. + */ +enum class GrLoadOp { + kLoad, + kClear, + kDiscard, +}; + +/** + * This enum is used to specify the store operation to be used when an opList/GrGpuCommandBuffer + * ends execution. + */ +enum class GrStoreOp { + kStore, + kDiscard, +}; + +/** + * Used to control antialiasing in draw calls. + */ +enum class GrAA : bool { + kNo = false, + kYes = true +}; + +/** This enum indicates the type of antialiasing to be performed. */ +enum class GrAAType : unsigned { + /** No antialiasing */ + kNone, + /** Use fragment shader code to compute a fractional pixel coverage. */ + kCoverage, + /** Use normal MSAA. */ + kMSAA, + /** + * Use "mixed samples" MSAA such that the stencil buffer is multisampled but the color buffer is + * not. + */ + kMixedSamples +}; + +static inline bool GrAATypeIsHW(GrAAType type) { + switch (type) { + case GrAAType::kNone: + return false; + case GrAAType::kCoverage: + return false; + case GrAAType::kMSAA: + return true; + case GrAAType::kMixedSamples: + return true; + } + SK_ABORT("Unknown AA Type"); + return false; +} + +/** The type of full scene antialiasing supported by a render target. */ +enum class GrFSAAType { + /** No FSAA */ + kNone, + /** Regular MSAA where each attachment has the same sample count. */ + kUnifiedMSAA, + /** One color sample, N stencil samples. */ + kMixedSamples, +}; + +/** + * Not all drawing code paths support using mixed samples when available and instead use + * coverage-based aa. + */ +enum class GrAllowMixedSamples : bool { kNo = false, kYes = true }; + +GrAAType GrChooseAAType(GrAA, GrFSAAType, GrAllowMixedSamples, const GrCaps&); + +enum class GrQuadAAFlags { + kLeft = SkCanvas::kLeft_QuadAAFlag, + kTop = SkCanvas::kTop_QuadAAFlag, + kRight = SkCanvas::kRight_QuadAAFlag, + kBottom = SkCanvas::kBottom_QuadAAFlag, + + kNone = SkCanvas::kNone_QuadAAFlags, + kAll = SkCanvas::kAll_QuadAAFlags +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GrQuadAAFlags) + +static inline GrQuadAAFlags SkToGrQuadAAFlags(unsigned flags) { + return static_cast(flags); +} + +/** + * Types of shader-language-specific boxed variables we can create. + */ +enum GrSLType { + kVoid_GrSLType, + kBool_GrSLType, + kByte_GrSLType, + kByte2_GrSLType, + kByte3_GrSLType, + kByte4_GrSLType, + kUByte_GrSLType, + kUByte2_GrSLType, + kUByte3_GrSLType, + kUByte4_GrSLType, + kShort_GrSLType, + kShort2_GrSLType, + kShort3_GrSLType, + kShort4_GrSLType, + kUShort_GrSLType, + kUShort2_GrSLType, + kUShort3_GrSLType, + kUShort4_GrSLType, + kFloat_GrSLType, + kFloat2_GrSLType, + kFloat3_GrSLType, + kFloat4_GrSLType, + kFloat2x2_GrSLType, + kFloat3x3_GrSLType, + kFloat4x4_GrSLType, + kHalf_GrSLType, + kHalf2_GrSLType, + kHalf3_GrSLType, + kHalf4_GrSLType, + kHalf2x2_GrSLType, + kHalf3x3_GrSLType, + kHalf4x4_GrSLType, + kInt_GrSLType, + kInt2_GrSLType, + kInt3_GrSLType, + kInt4_GrSLType, + kUint_GrSLType, + kUint2_GrSLType, + kTexture2DSampler_GrSLType, + kTextureExternalSampler_GrSLType, + kTexture2DRectSampler_GrSLType, +}; + +/** + * The type of texture. Backends other than GL currently only use the 2D value but the type must + * still be known at the API-neutral layer as it used to determine whether MIP maps, renderability, + * and sampling parameters are legal for proxies that will be instantiated with wrapped textures. + */ +enum class GrTextureType { + k2D, + kRectangle, + kExternal +}; + +enum GrShaderType { + kVertex_GrShaderType, + kGeometry_GrShaderType, + kFragment_GrShaderType, + + kLastkFragment_GrShaderType = kFragment_GrShaderType +}; +static const int kGrShaderTypeCount = kLastkFragment_GrShaderType + 1; + +enum GrShaderFlags { + kNone_GrShaderFlags = 0, + kVertex_GrShaderFlag = 1 << kVertex_GrShaderType, + kGeometry_GrShaderFlag = 1 << kGeometry_GrShaderType, + kFragment_GrShaderFlag = 1 << kFragment_GrShaderType +}; +GR_MAKE_BITFIELD_OPS(GrShaderFlags); + +/** + * Precisions of shader language variables. Not all shading languages support precisions or actually + * vary the internal precision based on the qualifiers. These currently only apply to float types ( + * including float vectors and matrices). + */ +enum GrSLPrecision : int { + kLow_GrSLPrecision, + kMedium_GrSLPrecision, + kHigh_GrSLPrecision, + + // Default precision is a special tag that means "whatever the default for the program/type + // combination is". In other words, it maps to the empty string in shader code. There are some + // scenarios where kDefault is not allowed (as the default precision for a program, or for + // varyings, for example). + kDefault_GrSLPrecision, + + // We only consider the "real" precisions here + kLast_GrSLPrecision = kHigh_GrSLPrecision, +}; + +static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1; + +/** Is the shading language type float (including vectors/matrices)? */ +static inline bool GrSLTypeIsFloatType(GrSLType type) { + switch (type) { + case kFloat_GrSLType: + case kFloat2_GrSLType: + case kFloat3_GrSLType: + case kFloat4_GrSLType: + case kFloat2x2_GrSLType: + case kFloat3x3_GrSLType: + case kFloat4x4_GrSLType: + case kHalf_GrSLType: + case kHalf2_GrSLType: + case kHalf3_GrSLType: + case kHalf4_GrSLType: + case kHalf2x2_GrSLType: + case kHalf3x3_GrSLType: + case kHalf4x4_GrSLType: + return true; + + case kVoid_GrSLType: + case kTexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + case kBool_GrSLType: + case kByte_GrSLType: + case kByte2_GrSLType: + case kByte3_GrSLType: + case kByte4_GrSLType: + case kUByte_GrSLType: + case kUByte2_GrSLType: + case kUByte3_GrSLType: + case kUByte4_GrSLType: + case kShort_GrSLType: + case kShort2_GrSLType: + case kShort3_GrSLType: + case kShort4_GrSLType: + case kUShort_GrSLType: + case kUShort2_GrSLType: + case kUShort3_GrSLType: + case kUShort4_GrSLType: + case kInt_GrSLType: + case kInt2_GrSLType: + case kInt3_GrSLType: + case kInt4_GrSLType: + case kUint_GrSLType: + case kUint2_GrSLType: + return false; + } + SK_ABORT("Unexpected type"); + return false; +} + +/** If the type represents a single value or vector return the vector length, else -1. */ +static inline int GrSLTypeVecLength(GrSLType type) { + switch (type) { + case kFloat_GrSLType: + case kHalf_GrSLType: + case kBool_GrSLType: + case kByte_GrSLType: + case kUByte_GrSLType: + case kShort_GrSLType: + case kUShort_GrSLType: + case kInt_GrSLType: + case kUint_GrSLType: + return 1; + + case kFloat2_GrSLType: + case kHalf2_GrSLType: + case kByte2_GrSLType: + case kUByte2_GrSLType: + case kShort2_GrSLType: + case kUShort2_GrSLType: + case kInt2_GrSLType: + case kUint2_GrSLType: + return 2; + + case kFloat3_GrSLType: + case kHalf3_GrSLType: + case kByte3_GrSLType: + case kUByte3_GrSLType: + case kShort3_GrSLType: + case kUShort3_GrSLType: + case kInt3_GrSLType: + return 3; + + case kFloat4_GrSLType: + case kHalf4_GrSLType: + case kByte4_GrSLType: + case kUByte4_GrSLType: + case kShort4_GrSLType: + case kUShort4_GrSLType: + case kInt4_GrSLType: + return 4; + + case kFloat2x2_GrSLType: + case kFloat3x3_GrSLType: + case kFloat4x4_GrSLType: + case kHalf2x2_GrSLType: + case kHalf3x3_GrSLType: + case kHalf4x4_GrSLType: + case kVoid_GrSLType: + case kTexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + return -1; + } + SK_ABORT("Unexpected type"); + return -1; +} + +static inline GrSLType GrSLCombinedSamplerTypeForTextureType(GrTextureType type) { + switch (type) { + case GrTextureType::k2D: + return kTexture2DSampler_GrSLType; + case GrTextureType::kRectangle: + return kTexture2DRectSampler_GrSLType; + case GrTextureType::kExternal: + return kTextureExternalSampler_GrSLType; + } + SK_ABORT("Unexpected texture type"); + return kTexture2DSampler_GrSLType; +} + +/** Rectangle and external textures ony support the clamp wrap mode and do not support MIP maps. */ +static inline bool GrTextureTypeHasRestrictedSampling(GrTextureType type) { + switch (type) { + case GrTextureType::k2D: + return false; + case GrTextureType::kRectangle: + return true; + case GrTextureType::kExternal: + return true; + } + SK_ABORT("Unexpected texture type"); + return false; +} + +static inline bool GrSLTypeIsCombinedSamplerType(GrSLType type) { + switch (type) { + case kTexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + return true; + + case kVoid_GrSLType: + case kFloat_GrSLType: + case kFloat2_GrSLType: + case kFloat3_GrSLType: + case kFloat4_GrSLType: + case kFloat2x2_GrSLType: + case kFloat3x3_GrSLType: + case kFloat4x4_GrSLType: + case kHalf_GrSLType: + case kHalf2_GrSLType: + case kHalf3_GrSLType: + case kHalf4_GrSLType: + case kHalf2x2_GrSLType: + case kHalf3x3_GrSLType: + case kHalf4x4_GrSLType: + case kInt_GrSLType: + case kInt2_GrSLType: + case kInt3_GrSLType: + case kInt4_GrSLType: + case kUint_GrSLType: + case kUint2_GrSLType: + case kBool_GrSLType: + case kByte_GrSLType: + case kByte2_GrSLType: + case kByte3_GrSLType: + case kByte4_GrSLType: + case kUByte_GrSLType: + case kUByte2_GrSLType: + case kUByte3_GrSLType: + case kUByte4_GrSLType: + case kShort_GrSLType: + case kShort2_GrSLType: + case kShort3_GrSLType: + case kShort4_GrSLType: + case kUShort_GrSLType: + case kUShort2_GrSLType: + case kUShort3_GrSLType: + case kUShort4_GrSLType: + return false; + } + SK_ABORT("Unexpected type"); + return false; +} + +static inline bool GrSLTypeAcceptsPrecision(GrSLType type) { + switch (type) { + case kTexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + return true; + + case kVoid_GrSLType: + case kBool_GrSLType: + case kByte_GrSLType: + case kByte2_GrSLType: + case kByte3_GrSLType: + case kByte4_GrSLType: + case kUByte_GrSLType: + case kUByte2_GrSLType: + case kUByte3_GrSLType: + case kUByte4_GrSLType: + case kShort_GrSLType: + case kShort2_GrSLType: + case kShort3_GrSLType: + case kShort4_GrSLType: + case kUShort_GrSLType: + case kUShort2_GrSLType: + case kUShort3_GrSLType: + case kUShort4_GrSLType: + case kFloat_GrSLType: + case kFloat2_GrSLType: + case kFloat3_GrSLType: + case kFloat4_GrSLType: + case kFloat2x2_GrSLType: + case kFloat3x3_GrSLType: + case kFloat4x4_GrSLType: + case kHalf_GrSLType: + case kHalf2_GrSLType: + case kHalf3_GrSLType: + case kHalf4_GrSLType: + case kHalf2x2_GrSLType: + case kHalf3x3_GrSLType: + case kHalf4x4_GrSLType: + case kInt_GrSLType: + case kInt2_GrSLType: + case kInt3_GrSLType: + case kInt4_GrSLType: + case kUint_GrSLType: + case kUint2_GrSLType: + return false; + } + SK_ABORT("Unexpected type"); + return false; +} + +// temporarily accepting (but ignoring) precision modifiers on the new types; this will be killed +// in a future CL +static inline bool GrSLTypeTemporarilyAcceptsPrecision(GrSLType type) { + switch (type) { + case kShort_GrSLType: + case kUShort_GrSLType: + case kFloat_GrSLType: + case kFloat2_GrSLType: + case kFloat3_GrSLType: + case kFloat4_GrSLType: + case kFloat2x2_GrSLType: + case kFloat3x3_GrSLType: + case kFloat4x4_GrSLType: + case kHalf_GrSLType: + case kHalf2_GrSLType: + case kHalf3_GrSLType: + case kHalf4_GrSLType: + case kHalf2x2_GrSLType: + case kHalf3x3_GrSLType: + case kHalf4x4_GrSLType: + case kInt_GrSLType: + case kInt2_GrSLType: + case kInt3_GrSLType: + case kInt4_GrSLType: + case kUint_GrSLType: + case kUint2_GrSLType: + case kTexture2DSampler_GrSLType: + case kTextureExternalSampler_GrSLType: + case kTexture2DRectSampler_GrSLType: + return true; + + case kVoid_GrSLType: + case kBool_GrSLType: + case kByte_GrSLType: + case kByte2_GrSLType: + case kByte3_GrSLType: + case kByte4_GrSLType: + case kUByte_GrSLType: + case kUByte2_GrSLType: + case kUByte3_GrSLType: + case kUByte4_GrSLType: + case kShort2_GrSLType: + case kShort3_GrSLType: + case kShort4_GrSLType: + case kUShort2_GrSLType: + case kUShort3_GrSLType: + case kUShort4_GrSLType: + return false; + } + SK_ABORT("Unexpected type"); + return false; +} + +////////////////////////////////////////////////////////////////////////////// + +/** + * Types used to describe format of vertices in arrays. + */ +enum GrVertexAttribType { + kFloat_GrVertexAttribType = 0, + kFloat2_GrVertexAttribType, + kFloat3_GrVertexAttribType, + kFloat4_GrVertexAttribType, + kHalf_GrVertexAttribType, + kHalf2_GrVertexAttribType, + kHalf3_GrVertexAttribType, + kHalf4_GrVertexAttribType, + + kInt2_GrVertexAttribType, // vector of 2 32-bit ints + kInt3_GrVertexAttribType, // vector of 3 32-bit ints + kInt4_GrVertexAttribType, // vector of 4 32-bit ints + + + kByte_GrVertexAttribType, // signed byte + kByte2_GrVertexAttribType, // vector of 2 8-bit signed bytes + kByte3_GrVertexAttribType, // vector of 3 8-bit signed bytes + kByte4_GrVertexAttribType, // vector of 4 8-bit signed bytes + kUByte_GrVertexAttribType, // unsigned byte + kUByte2_GrVertexAttribType, // vector of 2 8-bit unsigned bytes + kUByte3_GrVertexAttribType, // vector of 3 8-bit unsigned bytes + kUByte4_GrVertexAttribType, // vector of 4 8-bit unsigned bytes + + kUByte_norm_GrVertexAttribType, // unsigned byte, e.g. coverage, 0 -> 0.0f, 255 -> 1.0f. + kUByte4_norm_GrVertexAttribType, // vector of 4 unsigned bytes, e.g. colors, 0 -> 0.0f, + // 255 -> 1.0f. + + kShort2_GrVertexAttribType, // vector of 2 16-bit shorts. + kShort4_GrVertexAttribType, // vector of 4 16-bit shorts. + + kUShort2_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0, 65535 -> 65535. + kUShort2_norm_GrVertexAttribType, // vector of 2 unsigned shorts. 0 -> 0.0f, 65535 -> 1.0f. + + kInt_GrVertexAttribType, + kUint_GrVertexAttribType, + + kLast_GrVertexAttribType = kUint_GrVertexAttribType +}; +static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; + +////////////////////////////////////////////////////////////////////////////// + +static const int kGrClipEdgeTypeCnt = (int) GrClipEdgeType::kLast + 1; + +static inline bool GrProcessorEdgeTypeIsFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillAA == edgeType || GrClipEdgeType::kFillBW == edgeType); +} + +static inline bool GrProcessorEdgeTypeIsInverseFill(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kInverseFillAA == edgeType || + GrClipEdgeType::kInverseFillBW == edgeType); +} + +static inline bool GrProcessorEdgeTypeIsAA(const GrClipEdgeType edgeType) { + return (GrClipEdgeType::kFillBW != edgeType && + GrClipEdgeType::kInverseFillBW != edgeType); +} + +static inline GrClipEdgeType GrInvertProcessorEdgeType(const GrClipEdgeType edgeType) { + switch (edgeType) { + case GrClipEdgeType::kFillBW: + return GrClipEdgeType::kInverseFillBW; + case GrClipEdgeType::kFillAA: + return GrClipEdgeType::kInverseFillAA; + case GrClipEdgeType::kInverseFillBW: + return GrClipEdgeType::kFillBW; + case GrClipEdgeType::kInverseFillAA: + return GrClipEdgeType::kFillAA; + case GrClipEdgeType::kHairlineAA: + SK_ABORT("Hairline fill isn't invertible."); + } + return GrClipEdgeType::kFillAA; // suppress warning. +} + +/** + * Indicates the type of pending IO operations that can be recorded for gpu resources. + */ +enum GrIOType { + kRead_GrIOType, + kWrite_GrIOType, + kRW_GrIOType +}; + +/** + * Indicates the type of data that a GPU buffer will be used for. + */ +enum GrBufferType { + kVertex_GrBufferType, + kIndex_GrBufferType, + kTexel_GrBufferType, + kDrawIndirect_GrBufferType, + kXferCpuToGpu_GrBufferType, + kXferGpuToCpu_GrBufferType, + + kLast_GrBufferType = kXferGpuToCpu_GrBufferType +}; +static const int kGrBufferTypeCount = kLast_GrBufferType + 1; + +static inline bool GrBufferTypeIsVertexOrIndex(GrBufferType type) { + SkASSERT(type >= 0 && type < kGrBufferTypeCount); + return type <= kIndex_GrBufferType; + + GR_STATIC_ASSERT(0 == kVertex_GrBufferType); + GR_STATIC_ASSERT(1 == kIndex_GrBufferType); +} + +/** + * Provides a performance hint regarding the frequency at which a data store will be accessed. + */ +enum GrAccessPattern { + /** Data store will be respecified repeatedly and used many times. */ + kDynamic_GrAccessPattern, + /** Data store will be specified once and used many times. (Thus disqualified from caching.) */ + kStatic_GrAccessPattern, + /** Data store will be specified once and used at most a few times. (Also can't be cached.) */ + kStream_GrAccessPattern, + + kLast_GrAccessPattern = kStream_GrAccessPattern +}; + +// Flags shared between the GrSurface & GrSurfaceProxy class hierarchies +enum class GrInternalSurfaceFlags { + kNone = 0, + + // Surface-level + kNoPendingIO = 1 << 0, + + kSurfaceMask = kNoPendingIO, + + // RT-only + + // For internal resources: + // this is enabled whenever MSAA is enabled and GrCaps reports mixed samples are supported + // For wrapped resources: + // this is disabled for FBO0 + // but, otherwise, is enabled whenever MSAA is enabled and GrCaps reports mixed samples + // are supported + kMixedSampled = 1 << 2, + + // For internal resources: + // this is enabled whenever GrCaps reports window rect support + // For wrapped resources1 + // this is disabled for FBO0 + // but, otherwise, is enabled whenever GrCaps reports window rect support + kWindowRectsSupport = 1 << 3, + + // This flag is for use with GL only. It tells us that the internal render target wraps FBO 0. + kGLRTFBOIDIs0 = 1 << 4, + + kRenderTargetMask = kMixedSampled | kWindowRectsSupport | kGLRTFBOIDIs0, +}; +GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags) + +#ifdef SK_DEBUG +// Takes a pointer to a GrCaps, and will suppress prints if required +#define GrCapsDebugf(caps, ...) \ + if (!(caps)->suppressPrints()) { \ + SkDebugf(__VA_ARGS__); \ + } +#else +#define GrCapsDebugf(caps, ...) +#endif + +/** + * Specifies if the holder owns the backend, OpenGL or Vulkan, object. + */ +enum class GrBackendObjectOwnership : bool { + /** Holder does not destroy the backend object. */ + kBorrowed = false, + /** Holder destroys the backend object. */ + kOwned = true +}; + +template +T* const* unique_ptr_address_as_pointer_address(std::unique_ptr const* up) { + static_assert(sizeof(T*) == sizeof(std::unique_ptr), "unique_ptr not expected size."); + return reinterpret_cast(up); +} + +/* + * Object for CPU-GPU synchronization + */ +typedef uint64_t GrFence; + +/** + * Used to include or exclude specific GPU path renderers for testing purposes. + */ +enum class GpuPathRenderers { + kNone = 0, // Always use sofware masks and/or GrDefaultPathRenderer. + kDashLine = 1 << 0, + kStencilAndCover = 1 << 1, + kCoverageCounting = 1 << 2, + kAAHairline = 1 << 3, + kAAConvex = 1 << 4, + kAALinearizing = 1 << 5, + kSmall = 1 << 6, + kTessellating = 1 << 7, + + kAll = (kTessellating | (kTessellating - 1)) +}; + +/** + * Used to describe the current state of Mips on a GrTexture + */ +enum class GrMipMapsStatus { + kNotAllocated, // Mips have not been allocated + kDirty, // Mips are allocated but the full mip tree does not have valid data + kValid, // All levels fully allocated and have valid data in them +}; + +GR_MAKE_BITFIELD_CLASS_OPS(GpuPathRenderers) + +/** + * We want to extend the GrPixelConfig enum to add cases for dealing with alpha_8 which is + * internally either alpha8 or red8. Also for Gray_8 which can be luminance_8 or red_8. + */ +static constexpr GrPixelConfig kAlpha_8_as_Alpha_GrPixelConfig = kPrivateConfig1_GrPixelConfig; +static constexpr GrPixelConfig kAlpha_8_as_Red_GrPixelConfig = kPrivateConfig2_GrPixelConfig; +static constexpr GrPixelConfig kAlpha_half_as_Red_GrPixelConfig = kPrivateConfig3_GrPixelConfig; +static constexpr GrPixelConfig kGray_8_as_Lum_GrPixelConfig = kPrivateConfig4_GrPixelConfig; +static constexpr GrPixelConfig kGray_8_as_Red_GrPixelConfig = kPrivateConfig5_GrPixelConfig; + +/** + * Refers to the encoding of a GPU buffer as it will be interpreted by the GPU when sampling and + * blending. + */ +enum class GrSRGBEncoded : bool { kNo = false, kYes = true }; + +/** + * Describes whether pixel data encoding should be converted to/from linear/sRGB encoding. + */ +enum class GrSRGBConversion { + kNone, + kSRGBToLinear, + kLinearToSRGB, +}; + +/** + * Utility functions for GrPixelConfig + */ + +// Returns whether the config's color channels are sRGB encoded. +static inline GrSRGBEncoded GrPixelConfigIsSRGBEncoded(GrPixelConfig config) { + switch (config) { + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + return GrSRGBEncoded::kYes; + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGB_888_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + return GrSRGBEncoded::kNo; + } + SK_ABORT("Invalid pixel config"); + return GrSRGBEncoded::kNo; +} + +static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) { + return GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(config); +} + +static inline size_t GrBytesPerPixel(GrPixelConfig config) { + switch (config) { + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + return 1; + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + return 2; + case kRGBA_8888_GrPixelConfig: + case kRGB_888_GrPixelConfig: // Assuming GPUs store this 4-byte aligned. + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + return 4; + case kRGBA_half_GrPixelConfig: + return 8; + case kRGBA_float_GrPixelConfig: + return 16; + case kRG_float_GrPixelConfig: + return 8; + case kUnknown_GrPixelConfig: + return 0; + } + SK_ABORT("Invalid pixel config"); + return 0; +} + +static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) { + switch (config) { + case kRGB_565_GrPixelConfig: + case kRGB_888_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + case kRG_float_GrPixelConfig: + return true; + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kUnknown_GrPixelConfig: + return false; + } + SK_ABORT("Invalid pixel config"); + return false; +} + +static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) { + switch (config) { + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + return true; + case kUnknown_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kRGB_888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + return false; + } + SK_ABORT("Invalid pixel config."); + return false; +} + +static inline bool GrPixelConfigIsFloatingPoint(GrPixelConfig config) { + switch (config) { + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGB_888_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + return false; + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + return true; + } + SK_ABORT("Invalid pixel config."); + return false; +} + +/** + * Precision qualifier that should be used with a sampler. + */ +static inline GrSLPrecision GrSLSamplerPrecision(GrPixelConfig config) { + switch (config) { + case kUnknown_GrPixelConfig: + case kAlpha_8_GrPixelConfig: + case kAlpha_8_as_Alpha_GrPixelConfig: + case kAlpha_8_as_Red_GrPixelConfig: + case kGray_8_GrPixelConfig: + case kGray_8_as_Lum_GrPixelConfig: + case kGray_8_as_Red_GrPixelConfig: + case kRGB_565_GrPixelConfig: + case kRGBA_4444_GrPixelConfig: + case kRGBA_8888_GrPixelConfig: + case kRGB_888_GrPixelConfig: + case kBGRA_8888_GrPixelConfig: + case kSRGBA_8888_GrPixelConfig: + case kSBGRA_8888_GrPixelConfig: + return kLow_GrSLPrecision; + case kRGBA_float_GrPixelConfig: + case kRG_float_GrPixelConfig: + return kHigh_GrSLPrecision; + case kAlpha_half_GrPixelConfig: + case kAlpha_half_as_Red_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + case kRGBA_1010102_GrPixelConfig: + return kMedium_GrSLPrecision; + } + SK_ABORT("Unexpected type"); + return kHigh_GrSLPrecision; +} + +/** + * Like SkColorType this describes a layout of pixel data in CPU memory. It specifies the channels, + * their type, and width. This exists so that the GPU backend can have private types that have no + * analog in the public facing SkColorType enum and omit types not implemented in the GPU backend. + * It does not refer to a texture format and the mapping to texture formats may be many-to-many. + * It does not specify the sRGB encding of the stored values. + */ +enum class GrColorType { + kUnknown, + kAlpha_8, + kRGB_565, + kABGR_4444, // This name differs from SkColorType. kARGB_4444_SkColorType is misnamed. + kRGBA_8888, + kRGB_888x, + kBGRA_8888, + kRGBA_1010102, + kGray_8, + kAlpha_F16, + kRGBA_F16, + kRG_F32, + kRGBA_F32, +}; + +static inline SkColorType GrColorTypeToSkColorType(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return kUnknown_SkColorType; + case GrColorType::kAlpha_8: return kAlpha_8_SkColorType; + case GrColorType::kRGB_565: return kRGB_565_SkColorType; + case GrColorType::kABGR_4444: return kARGB_4444_SkColorType; + case GrColorType::kRGBA_8888: return kRGBA_8888_SkColorType; + case GrColorType::kRGB_888x: return kRGB_888x_SkColorType; + case GrColorType::kBGRA_8888: return kBGRA_8888_SkColorType; + case GrColorType::kRGBA_1010102: return kRGBA_1010102_SkColorType; + case GrColorType::kGray_8: return kGray_8_SkColorType; + case GrColorType::kAlpha_F16: return kUnknown_SkColorType; + case GrColorType::kRGBA_F16: return kRGBA_F16_SkColorType; + case GrColorType::kRG_F32: return kUnknown_SkColorType; + case GrColorType::kRGBA_F32: return kRGBA_F32_SkColorType; + } + SK_ABORT("Invalid GrColorType"); + return kUnknown_SkColorType; +} + +static inline GrColorType SkColorTypeToGrColorType(SkColorType ct) { + switch (ct) { + case kUnknown_SkColorType: return GrColorType::kUnknown; + case kAlpha_8_SkColorType: return GrColorType::kAlpha_8; + case kRGB_565_SkColorType: return GrColorType::kRGB_565; + case kARGB_4444_SkColorType: return GrColorType::kABGR_4444; + case kRGBA_8888_SkColorType: return GrColorType::kRGBA_8888; + case kRGB_888x_SkColorType: return GrColorType::kRGB_888x; + case kBGRA_8888_SkColorType: return GrColorType::kBGRA_8888; + case kGray_8_SkColorType: return GrColorType::kGray_8; + case kRGBA_F16_SkColorType: return GrColorType::kRGBA_F16; + case kRGBA_1010102_SkColorType: return GrColorType::kRGBA_1010102; + case kRGB_101010x_SkColorType: return GrColorType::kUnknown; + case kRGBA_F32_SkColorType: return GrColorType::kRGBA_F32; + } + SK_ABORT("Invalid SkColorType"); + return GrColorType::kUnknown; +} + +static inline uint32_t GrColorTypeComponentFlags(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return kAlpha_SkColorTypeComponentFlag; + case GrColorType::kRGB_565: return kRGB_SkColorTypeComponentFlags; + case GrColorType::kABGR_4444: return kRGBA_SkColorTypeComponentFlags; + case GrColorType::kRGBA_8888: return kRGBA_SkColorTypeComponentFlags; + case GrColorType::kRGB_888x: return kRGB_SkColorTypeComponentFlags; + case GrColorType::kBGRA_8888: return kRGBA_SkColorTypeComponentFlags; + case GrColorType::kRGBA_1010102: return kRGBA_SkColorTypeComponentFlags; + case GrColorType::kGray_8: return kGray_SkColorTypeComponentFlag; + case GrColorType::kAlpha_F16: return kAlpha_SkColorTypeComponentFlag; + case GrColorType::kRGBA_F16: return kRGBA_SkColorTypeComponentFlags; + case GrColorType::kRG_F32: return kRed_SkColorTypeComponentFlag | + kGreen_SkColorTypeComponentFlag; + case GrColorType::kRGBA_F32: return kRGBA_SkColorTypeComponentFlags; + } + SK_ABORT("Invalid GrColorType"); + return kUnknown_SkColorType; +} + +static inline bool GrColorTypeIsAlphaOnly(GrColorType ct) { + return kAlpha_SkColorTypeComponentFlag == GrColorTypeComponentFlags(ct); +} + +static inline bool GrColorTypeHasAlpha(GrColorType ct) { + return kAlpha_SkColorTypeComponentFlag & GrColorTypeComponentFlags(ct); +} + +static inline int GrColorTypeBytesPerPixel(GrColorType ct) { + switch (ct) { + case GrColorType::kUnknown: return 0; + case GrColorType::kAlpha_8: return 1; + case GrColorType::kRGB_565: return 2; + case GrColorType::kABGR_4444: return 2; + case GrColorType::kRGBA_8888: return 4; + case GrColorType::kRGB_888x: return 4; + case GrColorType::kBGRA_8888: return 4; + case GrColorType::kRGBA_1010102: return 4; + case GrColorType::kGray_8: return 1; + case GrColorType::kAlpha_F16: return 2; + case GrColorType::kRGBA_F16: return 8; + case GrColorType::kRG_F32: return 8; + case GrColorType::kRGBA_F32: return 16; + } + SK_ABORT("Invalid GrColorType"); + return 0; +} + +static inline GrColorType GrPixelConfigToColorTypeAndEncoding(GrPixelConfig config, + GrSRGBEncoded* srgbEncoded) { + SkASSERT(srgbEncoded); + switch (config) { + case kUnknown_GrPixelConfig: + return GrColorType::kUnknown; + case kAlpha_8_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kAlpha_8; + case kGray_8_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kGray_8; + case kRGB_565_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGB_565; + case kRGBA_4444_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kABGR_4444; + case kRGBA_8888_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGBA_8888; + case kRGB_888_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGB_888x; + case kBGRA_8888_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kBGRA_8888; + case kSRGBA_8888_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kYes; + return GrColorType::kRGBA_8888; + case kSBGRA_8888_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kYes; + return GrColorType::kBGRA_8888; + case kRGBA_1010102_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGBA_1010102; + case kRGBA_float_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGBA_F32; + case kRG_float_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRG_F32; + case kAlpha_half_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kAlpha_F16; + case kRGBA_half_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kRGBA_F16; + case kAlpha_8_as_Alpha_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kAlpha_8; + case kAlpha_8_as_Red_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kAlpha_8; + case kAlpha_half_as_Red_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kAlpha_F16; + case kGray_8_as_Lum_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kGray_8; + case kGray_8_as_Red_GrPixelConfig: + *srgbEncoded = GrSRGBEncoded::kNo; + return GrColorType::kGray_8; + } + SK_ABORT("Invalid GrPixelConfig"); + return GrColorType::kUnknown; +} + +static inline GrColorType GrPixelConfigToColorType(GrPixelConfig config) { + GrSRGBEncoded bogusEncoded; + return GrPixelConfigToColorTypeAndEncoding(config, &bogusEncoded); +} + +static inline GrPixelConfig GrColorTypeToPixelConfig(GrColorType config, + GrSRGBEncoded srgbEncoded) { + switch (config) { + case GrColorType::kUnknown: + return kUnknown_GrPixelConfig; + case GrColorType::kAlpha_8: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kAlpha_8_GrPixelConfig; + + case GrColorType::kGray_8: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kGray_8_GrPixelConfig; + + case GrColorType::kRGB_565: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGB_565_GrPixelConfig; + + case GrColorType::kABGR_4444: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGBA_4444_GrPixelConfig; + + case GrColorType::kRGBA_8888: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kSRGBA_8888_GrPixelConfig + : kRGBA_8888_GrPixelConfig; + + case GrColorType::kRGB_888x: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGB_888_GrPixelConfig; + + case GrColorType::kBGRA_8888: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kSBGRA_8888_GrPixelConfig + : kBGRA_8888_GrPixelConfig; + + case GrColorType::kRGBA_1010102: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGBA_1010102_GrPixelConfig; + + case GrColorType::kRGBA_F32: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGBA_float_GrPixelConfig; + + case GrColorType::kRG_F32: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRG_float_GrPixelConfig; + + case GrColorType::kAlpha_F16: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kAlpha_half_GrPixelConfig; + + case GrColorType::kRGBA_F16: + return (GrSRGBEncoded::kYes == srgbEncoded) ? kUnknown_GrPixelConfig + : kRGBA_half_GrPixelConfig; + } + SK_ABORT("Invalid GrColorType"); + return kUnknown_GrPixelConfig; +} + +class GrReleaseProcHelper : public SkWeakRefCnt { +public: + // These match the definitions in SkImage, from whence they came + typedef void* ReleaseCtx; + typedef void (*ReleaseProc)(ReleaseCtx); + + GrReleaseProcHelper(ReleaseProc proc, ReleaseCtx ctx) : fReleaseProc(proc), fReleaseCtx(ctx) {} + ~GrReleaseProcHelper() override {} + + void weak_dispose() const override { + fReleaseProc(fReleaseCtx); + } + +private: + ReleaseProc fReleaseProc; + ReleaseCtx fReleaseCtx; +}; + +#endif diff --git a/skia/include/private/GrVkTypesPriv.h b/skia/include/private/GrVkTypesPriv.h new file mode 100644 index 00000000..dfc26c76 --- /dev/null +++ b/skia/include/private/GrVkTypesPriv.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 GrVkTypesPriv_DEFINED +#define GrVkTypesPriv_DEFINED + +#include "vk/GrVkTypes.h" +#include "SkRefCnt.h" + +class GrVkImageLayout; + +// This struct is to used to store the the actual information about the vulkan backend image on the +// GrBackendTexture and GrBackendRenderTarget. When a client calls getVkImageInfo on a +// GrBackendTexture/RenderTarget, we use the GrVkBackendSurfaceInfo to create a snapshot +// GrVkImgeInfo object. Internally, this uses a ref count GrVkImageLayout object to track the +// current VkImageLayout which can be shared with an internal GrVkImage so that layout updates can +// be seen by all users of the image. +struct GrVkBackendSurfaceInfo { + GrVkBackendSurfaceInfo(GrVkImageInfo info, GrVkImageLayout* layout) + : fImageInfo(info), fLayout(layout) {} + + void cleanup(); + + GrVkBackendSurfaceInfo& operator=(const GrVkBackendSurfaceInfo&) = delete; + + // Assigns the passed in GrVkBackendSurfaceInfo to this object. if isValid is true we will also + // attempt to unref the old fLayout on this object. + void assign(const GrVkBackendSurfaceInfo&, bool isValid); + + void setImageLayout(VkImageLayout layout); + + sk_sp getGrVkImageLayout() const; + + GrVkImageInfo snapImageInfo() const; + +#if GR_TEST_UTILS + bool operator==(const GrVkBackendSurfaceInfo& that) const; +#endif + +private: + GrVkImageInfo fImageInfo; + GrVkImageLayout* fLayout; +}; + +#endif diff --git a/skia/include/private/SkArenaAlloc.h b/skia/include/private/SkArenaAlloc.h new file mode 100644 index 00000000..71b64043 --- /dev/null +++ b/skia/include/private/SkArenaAlloc.h @@ -0,0 +1,240 @@ +/* + * 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 SkArenaAlloc_DEFINED +#define SkArenaAlloc_DEFINED + +#include "../private/SkTFitsIn.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// SkArenaAlloc allocates object and destroys the allocated objects when destroyed. It's designed +// to minimize the number of underlying block allocations. SkArenaAlloc allocates first out of an +// (optional) user-provided block of memory, and when that's exhausted it allocates on the heap, +// starting with an allocation of firstHeapAllocation bytes. If your data (plus a small overhead) +// fits in the user-provided block, SkArenaAlloc never uses the heap, and if it fits in +// firstHeapAllocation bytes, it'll use the heap only once. If 0 is specified for +// firstHeapAllocation, then blockSize is used unless that too is 0, then 1024 is used. +// +// Examples: +// +// char block[mostCasesSize]; +// SkArenaAlloc arena(block, mostCasesSize); +// +// If mostCasesSize is too large for the stack, you can use the following pattern. +// +// std::unique_ptr block{new char[mostCasesSize]}; +// SkArenaAlloc arena(block.get(), mostCasesSize, almostAllCasesSize); +// +// If the program only sometimes allocates memory, use the following pattern. +// +// SkArenaAlloc arena(nullptr, 0, almostAllCasesSize); +// +// The storage does not necessarily need to be on the stack. Embedding the storage in a class also +// works. +// +// class Foo { +// char storage[mostCasesSize]; +// SkArenaAlloc arena (storage, mostCasesSize); +// }; +// +// In addition, the system is optimized to handle POD data including arrays of PODs (where +// POD is really data with no destructors). For POD data it has zero overhead per item, and a +// typical per block overhead of 8 bytes. For non-POD objects there is a per item overhead of 4 +// bytes. For arrays of non-POD objects there is a per array overhead of typically 8 bytes. There +// is an addition overhead when switching from POD data to non-POD data of typically 8 bytes. +// +// If additional blocks are needed they are increased exponentially. This strategy bounds the +// recursion of the RunDtorsOnBlock to be limited to O(log size-of-memory). Block size grow using +// the Fibonacci sequence which means that for 2^32 memory there are 48 allocations, and for 2^48 +// there are 71 allocations. +class SkArenaAlloc { +public: + SkArenaAlloc(char* block, size_t blockSize, size_t firstHeapAllocation); + + explicit SkArenaAlloc(size_t firstHeapAllocation) + : SkArenaAlloc(nullptr, 0, firstHeapAllocation) + {} + + ~SkArenaAlloc(); + + template + T* make(Args&&... args) { + uint32_t size = ToU32(sizeof(T)); + uint32_t alignment = ToU32(alignof(T)); + char* objStart; + if (std::is_trivially_destructible::value) { + objStart = this->allocObject(size, alignment); + fCursor = objStart + size; + } else { + objStart = this->allocObjectWithFooter(size + sizeof(Footer), alignment); + // Can never be UB because max value is alignof(T). + uint32_t padding = ToU32(objStart - fCursor); + + // Advance to end of object to install footer. + fCursor = objStart + size; + FooterAction* releaser = [](char* objEnd) { + char* objStart = objEnd - (sizeof(T) + sizeof(Footer)); + ((T*)objStart)->~T(); + return objStart; + }; + this->installFooter(releaser, padding); + } + + // This must be last to make objects with nested use of this allocator work. + return new(objStart) T(std::forward(args)...); + } + + template + T* makeArrayDefault(size_t count) { + AssertRelease(SkTFitsIn(count)); + uint32_t safeCount = ToU32(count); + T* array = (T*)this->commonArrayAlloc(safeCount); + + // If T is primitive then no initialization takes place. + for (size_t i = 0; i < safeCount; i++) { + new (&array[i]) T; + } + return array; + } + + template + T* makeArray(size_t count) { + AssertRelease(SkTFitsIn(count)); + uint32_t safeCount = ToU32(count); + T* array = (T*)this->commonArrayAlloc(safeCount); + + // If T is primitive then the memory is initialized. For example, an array of chars will + // be zeroed. + for (size_t i = 0; i < safeCount; i++) { + new (&array[i]) T(); + } + return array; + } + + // Only use makeBytesAlignedTo if none of the typed variants are impractical to use. + void* makeBytesAlignedTo(size_t size, size_t align) { + AssertRelease(SkTFitsIn(size)); + auto objStart = this->allocObject(ToU32(size), ToU32(align)); + fCursor = objStart + size; + return objStart; + } + + // Destroy all allocated objects, free any heap allocations. + void reset(); + +private: + static void AssertRelease(bool cond) { if (!cond) { ::abort(); } } + static uint32_t ToU32(size_t v) { + assert(SkTFitsIn(v)); + return (uint32_t)v; + } + + using Footer = int64_t; + using FooterAction = char* (char*); + + static char* SkipPod(char* footerEnd); + static void RunDtorsOnBlock(char* footerEnd); + static char* NextBlock(char* footerEnd); + + void installFooter(FooterAction* releaser, uint32_t padding); + void installUint32Footer(FooterAction* action, uint32_t value, uint32_t padding); + void installPtrFooter(FooterAction* action, char* ptr, uint32_t padding); + + void ensureSpace(uint32_t size, uint32_t alignment); + + char* allocObject(uint32_t size, uint32_t alignment) { + uintptr_t mask = alignment - 1; + uintptr_t alignedOffset = (~reinterpret_cast(fCursor) + 1) & mask; + uintptr_t totalSize = size + alignedOffset; + AssertRelease(totalSize >= size); + if (totalSize > static_cast(fEnd - fCursor)) { + this->ensureSpace(size, alignment); + alignedOffset = (~reinterpret_cast(fCursor) + 1) & mask; + } + return fCursor + alignedOffset; + } + + char* allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment); + + template + char* commonArrayAlloc(uint32_t count) { + char* objStart; + AssertRelease(count <= std::numeric_limits::max() / sizeof(T)); + uint32_t arraySize = ToU32(count * sizeof(T)); + uint32_t alignment = ToU32(alignof(T)); + + if (std::is_trivially_destructible::value) { + objStart = this->allocObject(arraySize, alignment); + fCursor = objStart + arraySize; + } else { + constexpr uint32_t overhead = sizeof(Footer) + sizeof(uint32_t); + AssertRelease(arraySize <= std::numeric_limits::max() - overhead); + uint32_t totalSize = arraySize + overhead; + objStart = this->allocObjectWithFooter(totalSize, alignment); + + // Can never be UB because max value is alignof(T). + uint32_t padding = ToU32(objStart - fCursor); + + // Advance to end of array to install footer.? + fCursor = objStart + arraySize; + this->installUint32Footer( + [](char* footerEnd) { + char* objEnd = footerEnd - (sizeof(Footer) + sizeof(uint32_t)); + uint32_t count; + memmove(&count, objEnd, sizeof(uint32_t)); + char* objStart = objEnd - count * sizeof(T); + T* array = (T*) objStart; + for (uint32_t i = 0; i < count; i++) { + array[i].~T(); + } + return objStart; + }, + ToU32(count), + padding); + } + + return objStart; + } + + char* fDtorCursor; + char* fCursor; + char* fEnd; + char* const fFirstBlock; + const uint32_t fFirstSize; + const uint32_t fFirstHeapAllocationSize; + + // Use the Fibonacci sequence as the growth factor for block size. The size of the block + // allocated is fFib0 * fFirstHeapAllocationSize. Using 2 ^ n * fFirstHeapAllocationSize + // had too much slop for Android. + uint32_t fFib0 {1}, fFib1 {1}; +}; + +// Helper for defining allocators with inline/reserved storage. +// For argument declarations, stick to the base type (SkArenaAlloc). +template +class SkSTArenaAlloc : public SkArenaAlloc { +public: + explicit SkSTArenaAlloc(size_t firstHeapAllocation = InlineStorageSize) + : INHERITED(fInlineStorage, InlineStorageSize, firstHeapAllocation) {} + +private: + char fInlineStorage[InlineStorageSize]; + + using INHERITED = SkArenaAlloc; +}; + +#endif // SkArenaAlloc_DEFINED diff --git a/skia/include/private/SkAtomics.h b/skia/include/private/SkAtomics.h new file mode 100644 index 00000000..349bdc44 --- /dev/null +++ b/skia/include/private/SkAtomics.h @@ -0,0 +1,126 @@ +/* + * 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 SkAtomics_DEFINED +#define SkAtomics_DEFINED + +// This file is not part of the public Skia API. +#include "../private/SkNoncopyable.h" +#include "SkTypes.h" +#include + +// ~~~~~~~~ APIs ~~~~~~~~~ + +enum sk_memory_order { + sk_memory_order_relaxed, + sk_memory_order_consume, + sk_memory_order_acquire, + sk_memory_order_release, + sk_memory_order_acq_rel, + sk_memory_order_seq_cst, +}; + +template +T sk_atomic_load(const T*, sk_memory_order = sk_memory_order_seq_cst); + +template +void sk_atomic_store(T*, T, sk_memory_order = sk_memory_order_seq_cst); + +template +T sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst); + +template +bool sk_atomic_compare_exchange(T*, T* expected, T desired, + sk_memory_order success = sk_memory_order_seq_cst, + sk_memory_order failure = sk_memory_order_seq_cst); + +// A little wrapper class for small T (think, builtins: int, float, void*) to +// ensure they're always used atomically. This is our stand-in for std::atomic. +// !!! Please _really_ know what you're doing if you change default_memory_order. !!! +template +class SkAtomic : SkNoncopyable { +public: + SkAtomic() {} + explicit SkAtomic(const T& val) : fVal(val) {} + + // It is essential we return by value rather than by const&. fVal may change at any time. + T load(sk_memory_order mo = default_memory_order) const { + return sk_atomic_load(&fVal, mo); + } + + void store(const T& val, sk_memory_order mo = default_memory_order) { + sk_atomic_store(&fVal, val, mo); + } + + // Alias for .load(default_memory_order). + operator T() const { + return this->load(); + } + + // Alias for .store(v, default_memory_order). + T operator=(const T& v) { + this->store(v); + return v; + } +private: + T fVal; +}; + +// ~~~~~~~~ Implementations ~~~~~~~~~ + +template +T sk_atomic_load(const T* ptr, sk_memory_order mo) { + SkASSERT(mo == sk_memory_order_relaxed || + mo == sk_memory_order_seq_cst || + mo == sk_memory_order_acquire || + mo == sk_memory_order_consume); + const std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_load_explicit(ap, (std::memory_order)mo); +} + +template +void sk_atomic_store(T* ptr, T val, sk_memory_order mo) { + SkASSERT(mo == sk_memory_order_relaxed || + mo == sk_memory_order_seq_cst || + mo == sk_memory_order_release); + std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_store_explicit(ap, val, (std::memory_order)mo); +} + +template +T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order mo) { + // All values of mo are valid. + std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_fetch_add_explicit(ap, val, (std::memory_order)mo); +} + +template +bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, + sk_memory_order success, + sk_memory_order failure) { + // All values of success are valid. + SkASSERT(failure == sk_memory_order_relaxed || + failure == sk_memory_order_seq_cst || + failure == sk_memory_order_acquire || + failure == sk_memory_order_consume); + SkASSERT(failure <= success); + std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_compare_exchange_strong_explicit(ap, expected, desired, + (std::memory_order)success, + (std::memory_order)failure); +} + +// ~~~~~~~~ Legacy APIs ~~~~~~~~~ + +// From here down we have shims for our old atomics API, to be weaned off of. +// We use the default sequentially-consistent memory order to make things simple +// and to match the practical reality of our old _sync and _win implementations. + +inline int32_t sk_atomic_inc(int32_t* ptr) { return sk_atomic_fetch_add(ptr, +1); } +inline int32_t sk_atomic_dec(int32_t* ptr) { return sk_atomic_fetch_add(ptr, -1); } + +#endif//SkAtomics_DEFINED diff --git a/skia/include/private/SkBitmaskEnum.h b/skia/include/private/SkBitmaskEnum.h new file mode 100644 index 00000000..f787d3b0 --- /dev/null +++ b/skia/include/private/SkBitmaskEnum.h @@ -0,0 +1,34 @@ +/* + * 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 SkEnumOperators_DEFINED +#define SkEnumOperators_DEFINED + +#include "SkTLogic.h" + +namespace skstd { +template struct is_bitmask_enum : std::false_type {}; +} + +template SK_WHEN(skstd::is_bitmask_enum::value, E) operator|(E l, E r) { + using U = skstd::underlying_type_t; + return static_cast(static_cast(l) | static_cast(r)); +} + +template SK_WHEN(skstd::is_bitmask_enum::value, E&) operator|=(E& l, E r) { + return l = l | r; +} + +template SK_WHEN(skstd::is_bitmask_enum::value, E) operator&(E l, E r) { + using U = skstd::underlying_type_t; + return static_cast(static_cast(l) & static_cast(r)); +} + +template SK_WHEN(skstd::is_bitmask_enum::value, E&) operator&=(E& l, E r) { + return l = l & r; +} + +#endif // SkEnumOperators_DEFINED diff --git a/skia/include/private/SkChecksum.h b/skia/include/private/SkChecksum.h new file mode 100644 index 00000000..fceb86bc --- /dev/null +++ b/skia/include/private/SkChecksum.h @@ -0,0 +1,71 @@ +/* + * 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 SkChecksum_DEFINED +#define SkChecksum_DEFINED + +#include "../private/SkNoncopyable.h" +#include "SkString.h" +#include "SkTLogic.h" +#include "SkTypes.h" + +// #include "SkOpts.h" +// It's sort of pesky to be able to include SkOpts.h here, so we'll just re-declare what we need. +namespace SkOpts { + extern uint32_t (*hash_fn)(const void*, size_t, uint32_t); +} + +class SkChecksum : SkNoncopyable { +public: + /** + * uint32_t -> uint32_t hash, useful for when you're about to trucate this hash but you + * suspect its low bits aren't well mixed. + * + * This is the Murmur3 finalizer. + */ + static uint32_t Mix(uint32_t hash) { + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + return hash; + } + + /** + * uint32_t -> uint32_t hash, useful for when you're about to trucate this hash but you + * suspect its low bits aren't well mixed. + * + * This version is 2-lines cheaper than Mix, but seems to be sufficient for the font cache. + */ + static uint32_t CheapMix(uint32_t hash) { + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 16; + return hash; + } +}; + +// SkGoodHash should usually be your first choice in hashing data. +// It should be both reasonably fast and high quality. +struct SkGoodHash { + template + SK_WHEN(sizeof(K) == 4, uint32_t) operator()(const K& k) const { + return SkChecksum::Mix(*(const uint32_t*)&k); + } + + template + SK_WHEN(sizeof(K) != 4, uint32_t) operator()(const K& k) const { + return SkOpts::hash_fn(&k, sizeof(K), 0); + } + + uint32_t operator()(const SkString& k) const { + return SkOpts::hash_fn(k.c_str(), k.size(), 0); + } +}; + +#endif diff --git a/skia/include/private/SkColorData.h b/skia/include/private/SkColorData.h new file mode 100644 index 00000000..20c4260b --- /dev/null +++ b/skia/include/private/SkColorData.h @@ -0,0 +1,444 @@ +/* + * 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 SkColorData_DEFINED +#define SkColorData_DEFINED + +#include "SkColor.h" +#include "SkColorPriv.h" +#include "SkNx.h" +#include "SkTo.h" + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 16bit pixel to a 32bit pixel + +#define SK_R16_BITS 5 +#define SK_G16_BITS 6 +#define SK_B16_BITS 5 + +#define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS) +#define SK_G16_SHIFT (SK_B16_BITS) +#define SK_B16_SHIFT 0 + +#define SK_R16_MASK ((1 << SK_R16_BITS) - 1) +#define SK_G16_MASK ((1 << SK_G16_BITS) - 1) +#define SK_B16_MASK ((1 << SK_B16_BITS) - 1) + +#define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK) +#define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK) +#define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK) + +static inline unsigned SkR16ToR32(unsigned r) { + return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8)); +} + +static inline unsigned SkG16ToG32(unsigned g) { + return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8)); +} + +static inline unsigned SkB16ToB32(unsigned b) { + return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8)); +} + +#define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c)) +#define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c)) +#define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c)) + +////////////////////////////////////////////////////////////////////////////// + +#define SkASSERT_IS_BYTE(x) SkASSERT(0 == ((x) & ~0xFF)) + +// Reverse the bytes coorsponding to RED and BLUE in a packed pixels. Note the +// pair of them are in the same 2 slots in both RGBA and BGRA, thus there is +// no need to pass in the colortype to this function. +static inline uint32_t SkSwizzle_RB(uint32_t c) { + static const uint32_t kRBMask = (0xFF << SK_R32_SHIFT) | (0xFF << SK_B32_SHIFT); + + unsigned c0 = (c >> SK_R32_SHIFT) & 0xFF; + unsigned c1 = (c >> SK_B32_SHIFT) & 0xFF; + return (c & ~kRBMask) | (c0 << SK_B32_SHIFT) | (c1 << SK_R32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_RGBA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_RGBA_A32_SHIFT) | (r << SK_RGBA_R32_SHIFT) | + (g << SK_RGBA_G32_SHIFT) | (b << SK_RGBA_B32_SHIFT); +} + +static inline uint32_t SkPackARGB_as_BGRA(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + SkASSERT_IS_BYTE(a); + SkASSERT_IS_BYTE(r); + SkASSERT_IS_BYTE(g); + SkASSERT_IS_BYTE(b); + return (a << SK_BGRA_A32_SHIFT) | (r << SK_BGRA_R32_SHIFT) | + (g << SK_BGRA_G32_SHIFT) | (b << SK_BGRA_B32_SHIFT); +} + +static inline SkPMColor SkSwizzle_RGBA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_RGBA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +static inline SkPMColor SkSwizzle_BGRA_to_PMColor(uint32_t c) { +#ifdef SK_PMCOLOR_IS_BGRA + return c; +#else + return SkSwizzle_RB(c); +#endif +} + +////////////////////////////////////////////////////////////////////////////// + +///@{ +/** See ITU-R Recommendation BT.709 at http://www.itu.int/rec/R-REC-BT.709/ .*/ +#define SK_ITU_BT709_LUM_COEFF_R (0.2126f) +#define SK_ITU_BT709_LUM_COEFF_G (0.7152f) +#define SK_ITU_BT709_LUM_COEFF_B (0.0722f) +///@} + +///@{ +/** A float value which specifies this channel's contribution to luminance. */ +#define SK_LUM_COEFF_R SK_ITU_BT709_LUM_COEFF_R +#define SK_LUM_COEFF_G SK_ITU_BT709_LUM_COEFF_G +#define SK_LUM_COEFF_B SK_ITU_BT709_LUM_COEFF_B +///@} + +/** Computes the luminance from the given r, g, and b in accordance with + SK_LUM_COEFF_X. For correct results, r, g, and b should be in linear space. +*/ +static inline U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b) { + //The following is + //r * SK_LUM_COEFF_R + g * SK_LUM_COEFF_G + b * SK_LUM_COEFF_B + //with SK_LUM_COEFF_X in 1.8 fixed point (rounding adjusted to sum to 256). + return (r * 54 + g * 183 + b * 19) >> 8; +} + +/** Calculates 256 - (value * alpha256) / 255 in range [0,256], + * for [0,255] value and [0,256] alpha256. + */ +static inline U16CPU SkAlphaMulInv256(U16CPU value, U16CPU alpha256) { + unsigned prod = 0xFFFF - value * alpha256; + return (prod + (prod >> 8)) >> 8; +} + +// The caller may want negative values, so keep all params signed (int) +// so we don't accidentally slip into unsigned math and lose the sign +// extension when we shift (in SkAlphaMul) +static inline int SkAlphaBlend(int src, int dst, int scale256) { + SkASSERT((unsigned)scale256 <= 256); + return dst + SkAlphaMul(src - dst, scale256); +} + +static inline uint16_t SkPackRGB16(unsigned r, unsigned g, unsigned b) { + SkASSERT(r <= SK_R16_MASK); + SkASSERT(g <= SK_G16_MASK); + SkASSERT(b <= SK_B16_MASK); + + return SkToU16((r << SK_R16_SHIFT) | (g << SK_G16_SHIFT) | (b << SK_B16_SHIFT)); +} + +#define SK_R16_MASK_IN_PLACE (SK_R16_MASK << SK_R16_SHIFT) +#define SK_G16_MASK_IN_PLACE (SK_G16_MASK << SK_G16_SHIFT) +#define SK_B16_MASK_IN_PLACE (SK_B16_MASK << SK_B16_SHIFT) + +/////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + * srcWeight is [0..256], unlike SkFourByteInterp which takes [0..255] + */ +static inline SkPMColor SkFourByteInterp256(SkPMColor src, SkPMColor dst, + unsigned scale) { + unsigned a = SkAlphaBlend(SkGetPackedA32(src), SkGetPackedA32(dst), scale); + unsigned r = SkAlphaBlend(SkGetPackedR32(src), SkGetPackedR32(dst), scale); + unsigned g = SkAlphaBlend(SkGetPackedG32(src), SkGetPackedG32(dst), scale); + unsigned b = SkAlphaBlend(SkGetPackedB32(src), SkGetPackedB32(dst), scale); + + return SkPackARGB32(a, r, g, b); +} + +/** + * Abstract 4-byte interpolation, implemented on top of SkPMColor + * utility functions. Third parameter controls blending of the first two: + * (src, dst, 0) returns dst + * (src, dst, 0xFF) returns src + */ +static inline SkPMColor SkFourByteInterp(SkPMColor src, SkPMColor dst, + U8CPU srcWeight) { + unsigned scale = SkAlpha255To256(srcWeight); + return SkFourByteInterp256(src, dst, scale); +} + +/** + * 0xAARRGGBB -> 0x00AA00GG, 0x00RR00BB + */ +static inline void SkSplay(uint32_t color, uint32_t* ag, uint32_t* rb) { + const uint32_t mask = 0x00FF00FF; + *ag = (color >> 8) & mask; + *rb = color & mask; +} + +/** + * 0xAARRGGBB -> 0x00AA00GG00RR00BB + * (note, ARGB -> AGRB) + */ +static inline uint64_t SkSplay(uint32_t color) { + const uint32_t mask = 0x00FF00FF; + uint64_t agrb = (color >> 8) & mask; // 0x0000000000AA00GG + agrb <<= 32; // 0x00AA00GG00000000 + agrb |= color & mask; // 0x00AA00GG00RR00BB + return agrb; +} + +/** + * 0xAAxxGGxx, 0xRRxxBBxx-> 0xAARRGGBB + */ +static inline uint32_t SkUnsplay(uint32_t ag, uint32_t rb) { + const uint32_t mask = 0xFF00FF00; + return (ag & mask) | ((rb & mask) >> 8); +} + +/** + * 0xAAxxGGxxRRxxBBxx -> 0xAARRGGBB + * (note, AGRB -> ARGB) + */ +static inline uint32_t SkUnsplay(uint64_t agrb) { + const uint32_t mask = 0xFF00FF00; + return SkPMColor( + ((agrb & mask) >> 8) | // 0x00RR00BB + ((agrb >> 32) & mask)); // 0xAARRGGBB +} + +static inline SkPMColor SkFastFourByteInterp256_32(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + + // Two 8-bit blends per two 32-bit registers, with space to make sure the math doesn't collide. + uint32_t src_ag, src_rb, dst_ag, dst_rb; + SkSplay(src, &src_ag, &src_rb); + SkSplay(dst, &dst_ag, &dst_rb); + + const uint32_t ret_ag = src_ag * scale + (256 - scale) * dst_ag; + const uint32_t ret_rb = src_rb * scale + (256 - scale) * dst_rb; + + return SkUnsplay(ret_ag, ret_rb); +} + +static inline SkPMColor SkFastFourByteInterp256_64(SkPMColor src, SkPMColor dst, unsigned scale) { + SkASSERT(scale <= 256); + // Four 8-bit blends in one 64-bit register, with space to make sure the math doesn't collide. + return SkUnsplay(SkSplay(src) * scale + (256-scale) * SkSplay(dst)); +} + +// TODO(mtklein): Replace slow versions with fast versions, using scale + (scale>>7) everywhere. + +/** + * Same as SkFourByteInterp256, but faster. + */ +static inline SkPMColor SkFastFourByteInterp256(SkPMColor src, SkPMColor dst, unsigned scale) { + // On a 64-bit machine, _64 is about 10% faster than _32, but ~40% slower on a 32-bit machine. + if (sizeof(void*) == 4) { + return SkFastFourByteInterp256_32(src, dst, scale); + } else { + return SkFastFourByteInterp256_64(src, dst, scale); + } +} + +/** + * Nearly the same as SkFourByteInterp, but faster and a touch more accurate, due to better + * srcWeight scaling to [0, 256]. + */ +static inline SkPMColor SkFastFourByteInterp(SkPMColor src, + SkPMColor dst, + U8CPU srcWeight) { + SkASSERT(srcWeight <= 255); + // scale = srcWeight + (srcWeight >> 7) is more accurate than + // scale = srcWeight + 1, but 7% slower + return SkFastFourByteInterp256(src, dst, srcWeight + (srcWeight >> 7)); +} + +/** + * Interpolates between colors src and dst using [0,256] scale. + */ +static inline SkPMColor SkPMLerp(SkPMColor src, SkPMColor dst, unsigned scale) { + return SkFastFourByteInterp256(src, dst, scale); +} + +static inline SkPMColor SkBlendARGB32(SkPMColor src, SkPMColor dst, U8CPU aa) { + SkASSERT((unsigned)aa <= 255); + + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlphaMulInv256(SkGetPackedA32(src), src_scale); + + const uint32_t mask = 0xFF00FF; + + uint32_t src_rb = (src & mask) * src_scale; + uint32_t src_ag = ((src >> 8) & mask) * src_scale; + + uint32_t dst_rb = (dst & mask) * dst_scale; + uint32_t dst_ag = ((dst >> 8) & mask) * dst_scale; + + return (((src_rb + dst_rb) >> 8) & mask) | ((src_ag + dst_ag) & ~mask); +} + +//////////////////////////////////////////////////////////////////////////////////////////// +// Convert a 32bit pixel to a 16bit pixel (no dither) + +#define SkR32ToR16_MACRO(r) ((unsigned)(r) >> (SK_R32_BITS - SK_R16_BITS)) +#define SkG32ToG16_MACRO(g) ((unsigned)(g) >> (SK_G32_BITS - SK_G16_BITS)) +#define SkB32ToB16_MACRO(b) ((unsigned)(b) >> (SK_B32_BITS - SK_B16_BITS)) + +#ifdef SK_DEBUG + static inline unsigned SkR32ToR16(unsigned r) { + SkR32Assert(r); + return SkR32ToR16_MACRO(r); + } + static inline unsigned SkG32ToG16(unsigned g) { + SkG32Assert(g); + return SkG32ToG16_MACRO(g); + } + static inline unsigned SkB32ToB16(unsigned b) { + SkB32Assert(b); + return SkB32ToB16_MACRO(b); + } +#else + #define SkR32ToR16(r) SkR32ToR16_MACRO(r) + #define SkG32ToG16(g) SkG32ToG16_MACRO(g) + #define SkB32ToB16(b) SkB32ToB16_MACRO(b) +#endif + +static inline U16CPU SkPixel32ToPixel16(SkPMColor c) { + unsigned r = ((c >> (SK_R32_SHIFT + (8 - SK_R16_BITS))) & SK_R16_MASK) << SK_R16_SHIFT; + unsigned g = ((c >> (SK_G32_SHIFT + (8 - SK_G16_BITS))) & SK_G16_MASK) << SK_G16_SHIFT; + unsigned b = ((c >> (SK_B32_SHIFT + (8 - SK_B16_BITS))) & SK_B16_MASK) << SK_B16_SHIFT; + return r | g | b; +} + +static inline U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b) { + return (SkR32ToR16(r) << SK_R16_SHIFT) | + (SkG32ToG16(g) << SK_G16_SHIFT) | + (SkB32ToB16(b) << SK_B16_SHIFT); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/* SrcOver the 32bit src color with the 16bit dst, returning a 16bit value + (with dirt in the high 16bits, so caller beware). +*/ +static inline U16CPU SkSrcOver32To16(SkPMColor src, uint16_t dst) { + unsigned sr = SkGetPackedR32(src); + unsigned sg = SkGetPackedG32(src); + unsigned sb = SkGetPackedB32(src); + + unsigned dr = SkGetPackedR16(dst); + unsigned dg = SkGetPackedG16(dst); + unsigned db = SkGetPackedB16(dst); + + unsigned isa = 255 - SkGetPackedA32(src); + + dr = (sr + SkMul16ShiftRound(dr, isa, SK_R16_BITS)) >> (8 - SK_R16_BITS); + dg = (sg + SkMul16ShiftRound(dg, isa, SK_G16_BITS)) >> (8 - SK_G16_BITS); + db = (sb + SkMul16ShiftRound(db, isa, SK_B16_BITS)) >> (8 - SK_B16_BITS); + + return SkPackRGB16(dr, dg, db); +} + +static inline SkColor SkPixel16ToColor(U16CPU src) { + SkASSERT(src == SkToU16(src)); + + unsigned r = SkPacked16ToR32(src); + unsigned g = SkPacked16ToG32(src); + unsigned b = SkPacked16ToB32(src); + + SkASSERT((r >> (8 - SK_R16_BITS)) == SkGetPackedR16(src)); + SkASSERT((g >> (8 - SK_G16_BITS)) == SkGetPackedG16(src)); + SkASSERT((b >> (8 - SK_B16_BITS)) == SkGetPackedB16(src)); + + return SkColorSetRGB(r, g, b); +} + +/////////////////////////////////////////////////////////////////////////////// + +typedef uint16_t SkPMColor16; + +// Put in OpenGL order (r g b a) +#define SK_A4444_SHIFT 0 +#define SK_R4444_SHIFT 12 +#define SK_G4444_SHIFT 8 +#define SK_B4444_SHIFT 4 + +static inline U8CPU SkReplicateNibble(unsigned nib) { + SkASSERT(nib <= 0xF); + return (nib << 4) | nib; +} + +#define SkGetPackedA4444(c) (((unsigned)(c) >> SK_A4444_SHIFT) & 0xF) +#define SkGetPackedR4444(c) (((unsigned)(c) >> SK_R4444_SHIFT) & 0xF) +#define SkGetPackedG4444(c) (((unsigned)(c) >> SK_G4444_SHIFT) & 0xF) +#define SkGetPackedB4444(c) (((unsigned)(c) >> SK_B4444_SHIFT) & 0xF) + +#define SkPacked4444ToA32(c) SkReplicateNibble(SkGetPackedA4444(c)) + +static inline SkPMColor SkPixel4444ToPixel32(U16CPU c) { + uint32_t d = (SkGetPackedA4444(c) << SK_A32_SHIFT) | + (SkGetPackedR4444(c) << SK_R32_SHIFT) | + (SkGetPackedG4444(c) << SK_G32_SHIFT) | + (SkGetPackedB4444(c) << SK_B32_SHIFT); + return d | (d << 4); +} + +static inline Sk4f swizzle_rb(const Sk4f& x) { + return SkNx_shuffle<2, 1, 0, 3>(x); +} + +static inline Sk4f swizzle_rb_if_bgra(const Sk4f& x) { +#ifdef SK_PMCOLOR_IS_BGRA + return swizzle_rb(x); +#else + return x; +#endif +} + +static inline Sk4f Sk4f_fromL32(uint32_t px) { + return SkNx_cast(Sk4b::Load(&px)) * (1 / 255.0f); +} + +static inline uint32_t Sk4f_toL32(const Sk4f& px) { + Sk4f v = px; + +#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + // SkNx_cast() pins, and we don't anticipate giant floats +#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) + // SkNx_cast() pins, and so does Sk4f_round(). +#else + // No guarantee of a pin. + v = Sk4f::Max(0, Sk4f::Min(v, 1)); +#endif + + uint32_t l32; + SkNx_cast(Sk4f_round(v * 255.0f)).store(&l32); + return l32; +} + +using SkPMColor4f = SkRGBA4f; + +constexpr SkPMColor4f SK_PMColor4fTRANSPARENT = { 0, 0, 0, 0 }; +constexpr SkPMColor4f SK_PMColor4fWHITE = { 1, 1, 1, 1 }; +constexpr SkPMColor4f SK_PMColor4fILLEGAL = { SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity, + SK_FloatNegativeInfinity }; + +#endif diff --git a/skia/include/private/SkDeferredDisplayList.h b/skia/include/private/SkDeferredDisplayList.h new file mode 100644 index 00000000..4285910e --- /dev/null +++ b/skia/include/private/SkDeferredDisplayList.h @@ -0,0 +1,75 @@ +/* + * 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 SkDeferredDisplayList_DEFINED +#define SkDeferredDisplayList_DEFINED + +#include "SkSurfaceCharacterization.h" + +#if SK_SUPPORT_GPU +#include "GrCCPerOpListPaths.h" +#include "GrOpList.h" + +#include +#endif + +class SkDeferredDisplayListPriv; +class SkSurface; +/* + * This class contains pre-processed gpu operations that can be replayed into + * an SkSurface via draw(SkDeferredDisplayList*). + * + * TODO: we probably need to expose this class so users can query it for memory usage. + */ +class SK_API SkDeferredDisplayList { +public: + +#if SK_SUPPORT_GPU + // This object is the source from which the lazy proxy backing the DDL will pull its backing + // texture when the DDL is replayed. It has to be separately ref counted bc the lazy proxy + // can outlive the DDL. + class LazyProxyData : public SkRefCnt { + public: + // Upon being replayed - this field will be filled in (by the DrawingManager) with the proxy + // backing the destination SkSurface. Note that, since there is no good place to clear it + // it can become a dangling pointer. + GrRenderTargetProxy* fReplayDest = nullptr; + }; +#else + class LazyProxyData : public SkRefCnt {}; +#endif + + SkDeferredDisplayList(const SkSurfaceCharacterization& characterization, + sk_sp); + ~SkDeferredDisplayList(); + + const SkSurfaceCharacterization& characterization() const { + return fCharacterization; + } + + // Provides access to functions that aren't part of the public API. + SkDeferredDisplayListPriv priv(); + const SkDeferredDisplayListPriv priv() const; + +private: + friend class GrDrawingManager; // for access to 'fOpLists' and 'fLazyProxyData' + friend class SkDeferredDisplayListRecorder; // for access to 'fLazyProxyData' + friend class SkDeferredDisplayListPriv; + + const SkSurfaceCharacterization fCharacterization; + +#if SK_SUPPORT_GPU + // This needs to match the same type in GrCoverageCountingPathRenderer.h + using PendingPathsMap = std::map>; + + SkTArray> fOpLists; + PendingPathsMap fPendingPaths; // This is the path data from CCPR. +#endif + sk_sp fLazyProxyData; +}; + +#endif diff --git a/skia/include/private/SkEncodedInfo.h b/skia/include/private/SkEncodedInfo.h new file mode 100644 index 00000000..a539824a --- /dev/null +++ b/skia/include/private/SkEncodedInfo.h @@ -0,0 +1,249 @@ +/* + * 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 SkEncodedInfo_DEFINED +#define SkEncodedInfo_DEFINED + +#include "SkData.h" +#include "SkImageInfo.h" +#include "../../third_party/skcms/skcms.h" + +struct SkEncodedInfo { +public: + class ICCProfile { + public: + static std::unique_ptr Make(sk_sp); + static std::unique_ptr Make(const skcms_ICCProfile&); + + const skcms_ICCProfile* profile() const { return &fProfile; } + private: + ICCProfile(const skcms_ICCProfile&, sk_sp = nullptr); + + skcms_ICCProfile fProfile; + sk_sp fData; + }; + + enum Alpha { + kOpaque_Alpha, + kUnpremul_Alpha, + + // Each pixel is either fully opaque or fully transparent. + // There is no difference between requesting kPremul or kUnpremul. + kBinary_Alpha, + }; + + /* + * We strive to make the number of components per pixel obvious through + * our naming conventions. + * Ex: kRGB has 3 components. kRGBA has 4 components. + * + * This sometimes results in redundant Alpha and Color information. + * Ex: kRGB images must also be kOpaque. + */ + enum Color { + // PNG, WBMP + kGray_Color, + + // PNG + kGrayAlpha_Color, + + // PNG with Skia-specific sBIT + // Like kGrayAlpha, except this expects to be treated as + // kAlpha_8_SkColorType, which ignores the gray component. If + // decoded to full color (e.g. kN32), the gray component is respected + // (so it can share code with kGrayAlpha). + kXAlpha_Color, + + // PNG + // 565 images may be encoded to PNG by specifying the number of + // significant bits for each channel. This is a strange 565 + // representation because the image is still encoded with 8 bits per + // component. + k565_Color, + + // PNG, GIF, BMP + kPalette_Color, + + // PNG, RAW + kRGB_Color, + kRGBA_Color, + + // BMP + kBGR_Color, + kBGRX_Color, + kBGRA_Color, + + // JPEG, WEBP + kYUV_Color, + + // WEBP + kYUVA_Color, + + // JPEG + // Photoshop actually writes inverted CMYK data into JPEGs, where zero + // represents 100% ink coverage. For this reason, we treat CMYK JPEGs + // as having inverted CMYK. libjpeg-turbo warns that this may break + // other applications, but the CMYK JPEGs we see on the web expect to + // be treated as inverted CMYK. + kInvertedCMYK_Color, + kYCCK_Color, + }; + + static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, + int bitsPerComponent) { + return Make(width, height, color, alpha, bitsPerComponent, nullptr); + } + + static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, + int bitsPerComponent, std::unique_ptr profile) { + SkASSERT(1 == bitsPerComponent || + 2 == bitsPerComponent || + 4 == bitsPerComponent || + 8 == bitsPerComponent || + 16 == bitsPerComponent); + + switch (color) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == alpha); + break; + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != alpha); + break; + case kPalette_Color: + SkASSERT(16 != bitsPerComponent); + break; + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case kRGBA_Color: + SkASSERT(kOpaque_Alpha != alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(kOpaque_Alpha != alpha); + SkASSERT(8 == bitsPerComponent); + break; + case kXAlpha_Color: + SkASSERT(kUnpremul_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case k565_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + default: + SkASSERT(false); + break; + } + + return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile)); + } + + /* + * Returns a recommended SkImageInfo. + * + * TODO: Leave this up to the client. + */ + SkImageInfo makeImageInfo() const { + auto ct = kGray_Color == fColor ? kGray_8_SkColorType : + kXAlpha_Color == fColor ? kAlpha_8_SkColorType : + k565_Color == fColor ? kRGB_565_SkColorType : + kN32_SkColorType ; + auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType + : kUnpremul_SkAlphaType; + sk_sp cs = fProfile ? SkColorSpace::Make(*fProfile->profile()) + : nullptr; + if (!cs) { + cs = SkColorSpace::MakeSRGB(); + } + return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs)); + } + + int width() const { return fWidth; } + int height() const { return fHeight; } + Color color() const { return fColor; } + Alpha alpha() const { return fAlpha; } + bool opaque() const { return fAlpha == kOpaque_Alpha; } + const skcms_ICCProfile* profile() const { + if (!fProfile) return nullptr; + return fProfile->profile(); + } + + uint8_t bitsPerComponent() const { return fBitsPerComponent; } + + uint8_t bitsPerPixel() const { + switch (fColor) { + case kGray_Color: + return fBitsPerComponent; + case kXAlpha_Color: + case kGrayAlpha_Color: + return 2 * fBitsPerComponent; + case kPalette_Color: + return fBitsPerComponent; + case kRGB_Color: + case kBGR_Color: + case kYUV_Color: + case k565_Color: + return 3 * fBitsPerComponent; + case kRGBA_Color: + case kBGRA_Color: + case kBGRX_Color: + case kYUVA_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + return 4 * fBitsPerComponent; + default: + SkASSERT(false); + return 0; + } + } + + SkEncodedInfo(const SkEncodedInfo& orig) = delete; + SkEncodedInfo& operator=(const SkEncodedInfo&) = delete; + + SkEncodedInfo(SkEncodedInfo&& orig) = default; + SkEncodedInfo& operator=(SkEncodedInfo&&) = default; + + // Explicit copy method, to avoid accidental copying. + SkEncodedInfo copy() const { + auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent); + if (fProfile) { + copy.fProfile.reset(new ICCProfile(*fProfile.get())); + } + return copy; + } + +private: + SkEncodedInfo(int width, int height, Color color, Alpha alpha, + uint8_t bitsPerComponent, std::unique_ptr profile) + : fWidth(width) + , fHeight(height) + , fColor(color) + , fAlpha(alpha) + , fBitsPerComponent(bitsPerComponent) + , fProfile(std::move(profile)) + {} + + int fWidth; + int fHeight; + Color fColor; + Alpha fAlpha; + uint8_t fBitsPerComponent; + std::unique_ptr fProfile; +}; + +#endif diff --git a/skia/include/private/SkFixed.h b/skia/include/private/SkFixed.h new file mode 100644 index 00000000..0d15e02a --- /dev/null +++ b/skia/include/private/SkFixed.h @@ -0,0 +1,140 @@ +/* + * 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 SkFixed_DEFINED +#define SkFixed_DEFINED + +#include "SkSafe_math.h" +#include "SkScalar.h" +#include "SkTo.h" +#include "SkTypes.h" + +/** \file SkFixed.h + + Types and macros for 16.16 fixed point +*/ + +/** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point +*/ +typedef int32_t SkFixed; +#define SK_Fixed1 (1 << 16) +#define SK_FixedHalf (1 << 15) +#define SK_FixedQuarter (1 << 14) +#define SK_FixedMax (0x7FFFFFFF) +#define SK_FixedMin (-SK_FixedMax) +#define SK_FixedPI (0x3243F) +#define SK_FixedSqrt2 (92682) +#define SK_FixedTanPIOver8 (0x6A0A) +#define SK_FixedRoot2Over2 (0xB505) + +// NOTE: SkFixedToFloat is exact. SkFloatToFixed seems to lack a rounding step. For all fixed-point +// values, this version is as accurate as possible for (fixed -> float -> fixed). Rounding reduces +// accuracy if the intermediate floats are in the range that only holds integers (adding 0.5f to an +// odd integer then snaps to nearest even). Using double for the rounding math gives maximum +// accuracy for (float -> fixed -> float), but that's usually overkill. +#define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) +#define SkFloatToFixed(x) sk_float_saturate2int((x) * SK_Fixed1) + +#ifdef SK_DEBUG + static inline SkFixed SkFloatToFixed_Check(float x) { + int64_t n64 = (int64_t)(x * SK_Fixed1); + SkFixed n32 = (SkFixed)n64; + SkASSERT(n64 == n32); + return n32; + } +#else + #define SkFloatToFixed_Check(x) SkFloatToFixed(x) +#endif + +#define SkFixedToDouble(x) ((x) * 1.52587890625e-5) +#define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) + +/** Converts an integer to a SkFixed, asserting that the result does not overflow + a 32 bit signed integer +*/ +#ifdef SK_DEBUG + inline SkFixed SkIntToFixed(int n) + { + SkASSERT(n >= -32768 && n <= 32767); + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. + return (unsigned)n << 16; + } +#else + // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before + // shifting. Then we force the cast to SkFixed to ensure that the answer is signed (like the + // debug version). + #define SkIntToFixed(n) (SkFixed)((unsigned)(n) << 16) +#endif + +#define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) +#define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) +#define SkFixedFloorToInt(x) ((x) >> 16) + +static inline SkFixed SkFixedRoundToFixed(SkFixed x) { + return (x + SK_FixedHalf) & 0xFFFF0000; +} +static inline SkFixed SkFixedCeilToFixed(SkFixed x) { + return (x + SK_Fixed1 - 1) & 0xFFFF0000; +} +static inline SkFixed SkFixedFloorToFixed(SkFixed x) { + return x & 0xFFFF0000; +} + +#define SkFixedAbs(x) SkAbs32(x) +#define SkFixedAve(a, b) (((a) + (b)) >> 1) + +// The divide may exceed 32 bits. Clamp to a signed 32 bit result. +#define SkFixedDiv(numer, denom) \ + SkToS32(SkTPin((SkLeftShift((int64_t)(numer), 16) / (denom)), SK_MinS32, SK_MaxS32)) + +static inline SkFixed SkFixedMul(SkFixed a, SkFixed b) { + return (SkFixed)((int64_t)a * b >> 16); +} + +/////////////////////////////////////////////////////////////////////////////// +// Platform-specific alternatives to our portable versions. + +// The VCVT float-to-fixed instruction is part of the VFPv3 instruction set. +#if defined(__ARM_VFPV3__) + /* This guy does not handle NaN or other obscurities, but is faster than + than (int)(x*65536). When built on Android with -Os, needs forcing + to inline or we lose the speed benefit. + */ + SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) + { + int32_t y; + asm("vcvt.s32.f32 %0, %0, #16": "+w"(x)); + memcpy(&y, &x, sizeof(y)); + return y; + } + #undef SkFloatToFixed + #define SkFloatToFixed(x) SkFloatToFixed_arm(x) +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#define SkFixedToScalar(x) SkFixedToFloat(x) +#define SkScalarToFixed(x) SkFloatToFixed(x) + +/////////////////////////////////////////////////////////////////////////////// + +typedef int64_t SkFixed3232; // 32.32 + +#define SkFixed3232Max SK_MaxS64 +#define SkFixed3232Min (-SkFixed3232Max) + +#define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) +#define SkFixed3232ToInt(x) ((int)((x) >> 32)) +#define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) +#define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) +#define SkFloatToFixed3232(x) sk_float_saturate2int64((x) * (65536.0f * 65536.0f)) +#define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) + +#define SkScalarToFixed3232(x) SkFloatToFixed3232(x) + +#endif diff --git a/skia/include/private/SkFloatBits.h b/skia/include/private/SkFloatBits.h new file mode 100644 index 00000000..7eb059b8 --- /dev/null +++ b/skia/include/private/SkFloatBits.h @@ -0,0 +1,91 @@ +/* + * 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 SkFloatBits_DEFINED +#define SkFloatBits_DEFINED + +#include "SkTypes.h" +#include "SkSafe_math.h" + +#include + +/** Convert a sign-bit int (i.e. float interpreted as int) into a 2s compliement + int. This also converts -0 (0x80000000) to 0. Doing this to a float allows + it to be compared using normal C operators (<, <=, etc.) +*/ +static inline int32_t SkSignBitTo2sCompliment(int32_t x) { + if (x < 0) { + x &= 0x7FFFFFFF; + x = -x; + } + return x; +} + +/** Convert a 2s compliment int to a sign-bit (i.e. int interpreted as float). + This undoes the result of SkSignBitTo2sCompliment(). + */ +static inline int32_t Sk2sComplimentToSignBit(int32_t x) { + int sign = x >> 31; + // make x positive + x = (x ^ sign) - sign; + // set the sign bit as needed + x |= SkLeftShift(sign, 31); + return x; +} + +union SkFloatIntUnion { + float fFloat; + int32_t fSignBitInt; +}; + +// Helper to see a float as its bit pattern (w/o aliasing warnings) +static inline int32_t SkFloat2Bits(float x) { + SkFloatIntUnion data; + data.fFloat = x; + return data.fSignBitInt; +} + +// Helper to see a bit pattern as a float (w/o aliasing warnings) +static inline float SkBits2Float(int32_t floatAsBits) { + SkFloatIntUnion data; + data.fSignBitInt = floatAsBits; + return data.fFloat; +} + +constexpr int32_t gFloatBits_exponent_mask = 0x7F800000; +constexpr int32_t gFloatBits_matissa_mask = 0x007FFFFF; + +static inline bool SkFloatBits_IsFinite(int32_t bits) { + return (bits & gFloatBits_exponent_mask) != gFloatBits_exponent_mask; +} + +static inline bool SkFloatBits_IsInf(int32_t bits) { + return ((bits & gFloatBits_exponent_mask) == gFloatBits_exponent_mask) && + (bits & gFloatBits_matissa_mask) == 0; +} + +/** Return the float as a 2s compliment int. Just to be used to compare floats + to each other or against positive float-bit-constants (like 0). This does + not return the int equivalent of the float, just something cheaper for + compares-only. + */ +static inline int32_t SkFloatAs2sCompliment(float x) { + return SkSignBitTo2sCompliment(SkFloat2Bits(x)); +} + +/** Return the 2s compliment int as a float. This undos the result of + SkFloatAs2sCompliment + */ +static inline float Sk2sComplimentAsFloat(int32_t x) { + return SkBits2Float(Sk2sComplimentToSignBit(x)); +} + +// Scalar wrappers for float-bit routines + +#define SkScalarAs2sCompliment(x) SkFloatAs2sCompliment(x) + +#endif diff --git a/skia/include/private/SkFloatingPoint.h b/skia/include/private/SkFloatingPoint.h new file mode 100644 index 00000000..ba304752 --- /dev/null +++ b/skia/include/private/SkFloatingPoint.h @@ -0,0 +1,221 @@ +/* + * 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 SkFloatingPoint_DEFINED +#define SkFloatingPoint_DEFINED + +#include "../private/SkFloatBits.h" +#include "SkTypes.h" +#include "SkSafe_math.h" +#include +#include +#include +#include + + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 + #include +#elif defined(SK_ARM_HAS_NEON) + #include +#endif + +// For _POSIX_VERSION +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include +#endif + +// C++98 cmath std::pow seems to be the earliest portable way to get float pow. +// However, on Linux including cmath undefines isfinite. +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=14608 +static inline float sk_float_pow(float base, float exp) { + return powf(base, exp); +} + +#define sk_float_sqrt(x) sqrtf(x) +#define sk_float_sin(x) sinf(x) +#define sk_float_cos(x) cosf(x) +#define sk_float_tan(x) tanf(x) +#define sk_float_floor(x) floorf(x) +#define sk_float_ceil(x) ceilf(x) +#define sk_float_trunc(x) truncf(x) +#ifdef SK_BUILD_FOR_MAC +# define sk_float_acos(x) static_cast(acos(x)) +# define sk_float_asin(x) static_cast(asin(x)) +#else +# define sk_float_acos(x) acosf(x) +# define sk_float_asin(x) asinf(x) +#endif +#define sk_float_atan2(y,x) atan2f(y,x) +#define sk_float_abs(x) fabsf(x) +#define sk_float_copysign(x, y) copysignf(x, y) +#define sk_float_mod(x,y) fmodf(x,y) +#define sk_float_exp(x) expf(x) +#define sk_float_log(x) logf(x) + +#define sk_float_round(x) sk_float_floor((x) + 0.5f) + +// can't find log2f on android, but maybe that just a tool bug? +#ifdef SK_BUILD_FOR_ANDROID + static inline float sk_float_log2(float x) { + const double inv_ln_2 = 1.44269504088896; + return (float)(log(x) * inv_ln_2); + } +#else + #define sk_float_log2(x) log2f(x) +#endif + +static inline bool sk_float_isfinite(float x) { + return SkFloatBits_IsFinite(SkFloat2Bits(x)); +} + +static inline bool sk_float_isinf(float x) { + return SkFloatBits_IsInf(SkFloat2Bits(x)); +} + +static inline bool sk_float_isnan(float x) { + return !(x == x); +} + +#define sk_double_isnan(a) sk_float_isnan(a) + +#define SK_MaxS32FitsInFloat 2147483520 +#define SK_MinS32FitsInFloat -SK_MaxS32FitsInFloat + +#define SK_MaxS64FitsInFloat (SK_MaxS64 >> (63-24) << (63-24)) // 0x7fffff8000000000 +#define SK_MinS64FitsInFloat -SK_MaxS64FitsInFloat + +/** + * Return the closest int for the given float. Returns SK_MaxS32FitsInFloat for NaN. + */ +static inline int sk_float_saturate2int(float x) { + x = SkTMin(x, SK_MaxS32FitsInFloat); + x = SkTMax(x, SK_MinS32FitsInFloat); + return (int)x; +} + +/** + * Return the closest int for the given double. Returns SK_MaxS32 for NaN. + */ +static inline int sk_double_saturate2int(double x) { + x = SkTMin(x, SK_MaxS32); + x = SkTMax(x, SK_MinS32); + return (int)x; +} + +/** + * Return the closest int64_t for the given float. Returns SK_MaxS64FitsInFloat for NaN. + */ +static inline int64_t sk_float_saturate2int64(float x) { + x = SkTMin(x, SK_MaxS64FitsInFloat); + x = SkTMax(x, SK_MinS64FitsInFloat); + return (int64_t)x; +} + +#define sk_float_floor2int(x) sk_float_saturate2int(sk_float_floor(x)) +#define sk_float_round2int(x) sk_float_saturate2int(sk_float_floor((x) + 0.5f)) +#define sk_float_ceil2int(x) sk_float_saturate2int(sk_float_ceil(x)) + +#define sk_float_floor2int_no_saturate(x) (int)sk_float_floor(x) +#define sk_float_round2int_no_saturate(x) (int)sk_float_floor((x) + 0.5f) +#define sk_float_ceil2int_no_saturate(x) (int)sk_float_ceil(x) + +#define sk_double_floor(x) floor(x) +#define sk_double_round(x) floor((x) + 0.5) +#define sk_double_ceil(x) ceil(x) +#define sk_double_floor2int(x) (int)floor(x) +#define sk_double_round2int(x) (int)floor((x) + 0.5) +#define sk_double_ceil2int(x) (int)ceil(x) + +// Cast double to float, ignoring any warning about too-large finite values being cast to float. +// Clang thinks this is undefined, but it's actually implementation defined to return either +// the largest float or infinity (one of the two bracketing representable floats). Good enough! +#if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007 +__attribute__((no_sanitize("float-cast-overflow"))) +#endif +static inline float sk_double_to_float(double x) { + return static_cast(x); +} + +#define SK_FloatNaN std::numeric_limits::quiet_NaN() +#define SK_FloatInfinity (+std::numeric_limits::infinity()) +#define SK_FloatNegativeInfinity (-std::numeric_limits::infinity()) + +static inline float sk_float_rsqrt_portable(float x) { + // Get initial estimate. + int i; + memcpy(&i, &x, 4); + i = 0x5F1FFFF9 - (i>>1); + float estimate; + memcpy(&estimate, &i, 4); + + // One step of Newton's method to refine. + const float estimate_sq = estimate*estimate; + estimate *= 0.703952253f*(2.38924456f-x*estimate_sq); + return estimate; +} + +// Fast, approximate inverse square root. +// Compare to name-brand "1.0f / sk_float_sqrt(x)". Should be around 10x faster on SSE, 2x on NEON. +static inline float sk_float_rsqrt(float x) { +// We want all this inlined, so we'll inline SIMD and just take the hit when we don't know we've got +// it at compile time. This is going to be too fast to productively hide behind a function pointer. +// +// We do one step of Newton's method to refine the estimates in the NEON and portable paths. No +// refinement is faster, but very innacurate. Two steps is more accurate, but slower than 1/sqrt. +// +// Optimized constants in the portable path courtesy of http://rrrola.wz.cz/inv_sqrt.html +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 + return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); +#elif defined(SK_ARM_HAS_NEON) + // Get initial estimate. + const float32x2_t xx = vdup_n_f32(x); // Clever readers will note we're doing everything 2x. + float32x2_t estimate = vrsqrte_f32(xx); + + // One step of Newton's method to refine. + const float32x2_t estimate_sq = vmul_f32(estimate, estimate); + estimate = vmul_f32(estimate, vrsqrts_f32(xx, estimate_sq)); + return vget_lane_f32(estimate, 0); // 1 will work fine too; the answer's in both places. +#else + return sk_float_rsqrt_portable(x); +#endif +} + +// This is the number of significant digits we can print in a string such that when we read that +// string back we get the floating point number we expect. The minimum value C requires is 6, but +// most compilers support 9 +#ifdef FLT_DECIMAL_DIG +#define SK_FLT_DECIMAL_DIG FLT_DECIMAL_DIG +#else +#define SK_FLT_DECIMAL_DIG 9 +#endif + +// IEEE defines how float divide behaves for non-finite values and zero-denoms, but C does not +// so we have a helper that suppresses the possible undefined-behavior warnings. + +#ifdef __clang__ +__attribute__((no_sanitize("float-divide-by-zero"))) +#endif +static inline float sk_ieee_float_divide(float numer, float denom) { + return numer / denom; +} + +#ifdef __clang__ +__attribute__((no_sanitize("float-divide-by-zero"))) +#endif +static inline double sk_ieee_double_divide(double numer, double denom) { + return numer / denom; +} + +// While we clean up divide by zero, we'll replace places that do divide by zero with this TODO. +static inline float sk_ieee_float_divide_TODO_IS_DIVIDE_BY_ZERO_SAFE_HERE(float n, float d) { + return sk_ieee_float_divide(n,d); +} +static inline float sk_ieee_double_divide_TODO_IS_DIVIDE_BY_ZERO_SAFE_HERE(double n, double d) { + return sk_ieee_double_divide(n,d); +} + +#endif diff --git a/skia/include/private/SkHalf.h b/skia/include/private/SkHalf.h new file mode 100644 index 00000000..a862990d --- /dev/null +++ b/skia/include/private/SkHalf.h @@ -0,0 +1,85 @@ +/* + * 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 SkHalf_DEFINED +#define SkHalf_DEFINED + +#include "SkNx.h" +#include "SkTypes.h" + +// 16-bit floating point value +// format is 1 bit sign, 5 bits exponent, 10 bits mantissa +// only used for storage +typedef uint16_t SkHalf; + +static constexpr uint16_t SK_HalfMin = 0x0400; // 2^-14 (minimum positive normal value) +static constexpr uint16_t SK_HalfMax = 0x7bff; // 65504 +static constexpr uint16_t SK_HalfEpsilon = 0x1400; // 2^-10 +static constexpr uint16_t SK_Half1 = 0x3C00; // 1 + +// convert between half and single precision floating point +float SkHalfToFloat(SkHalf h); +SkHalf SK_API SkFloatToHalf(float f); + +// Convert between half and single precision floating point, +// assuming inputs and outputs are both finite, and may +// flush values which would be denormal half floats to zero. +static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t); +static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f&); + +// ~~~~~~~~~~~ impl ~~~~~~~~~~~~~~ // + +// Like the serial versions in SkHalf.cpp, these are based on +// https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ + +// GCC 4.9 lacks the intrinsics to use ARMv8 f16<->f32 instructions, so we use inline assembly. + +static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t rgba) { + Sk4h hs = Sk4h::Load(&rgba); +#if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64) + float32x4_t fs; + asm ("fcvtl %[fs].4s, %[hs].4h \n" // vcvt_f32_f16(...) + : [fs] "=w" (fs) // =w: write-only NEON register + : [hs] "w" (hs.fVec)); // w: read-only NEON register + return fs; +#else + Sk4i bits = SkNx_cast(hs), // Expand to 32 bit. + sign = bits & 0x00008000, // Save the sign bit for later... + positive = bits ^ sign, // ...but strip it off for now. + is_norm = 0x03ff < positive; // Exponent > 0? + + // For normal half floats, extend the mantissa by 13 zero bits, + // then adjust the exponent from 15 bias to 127 bias. + Sk4i norm = (positive << 13) + ((127 - 15) << 23); + + Sk4i merged = (sign << 16) | (norm & is_norm); + return Sk4f::Load(&merged); +#endif +} + +static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f& fs) { +#if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64) + float32x4_t vec = fs.fVec; + asm ("fcvtn %[vec].4h, %[vec].4s \n" // vcvt_f16_f32(vec) + : [vec] "+w" (vec)); // +w: read-write NEON register + return vreinterpret_u16_f32(vget_low_f32(vec)); +#else + Sk4i bits = Sk4i::Load(&fs), + sign = bits & 0x80000000, // Save the sign bit for later... + positive = bits ^ sign, // ...but strip it off for now. + will_be_norm = 0x387fdfff < positive; // greater than largest denorm half? + + // For normal half floats, adjust the exponent from 127 bias to 15 bias, + // then drop the bottom 13 mantissa bits. + Sk4i norm = (positive - ((127 - 15) << 23)) >> 13; + + Sk4i merged = (sign >> 16) | (will_be_norm & norm); + return SkNx_cast(merged); +#endif +} + +#endif diff --git a/skia/include/private/SkImageInfoPriv.h b/skia/include/private/SkImageInfoPriv.h new file mode 100644 index 00000000..1f064bdd --- /dev/null +++ b/skia/include/private/SkImageInfoPriv.h @@ -0,0 +1,119 @@ +/* + * 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 SkImageInfoPriv_DEFINED +#define SkImageInfoPriv_DEFINED + +#include "SkImageInfo.h" + +enum SkColorTypeComponentFlag { + kRed_SkColorTypeComponentFlag = 0x1, + kGreen_SkColorTypeComponentFlag = 0x2, + kBlue_SkColorTypeComponentFlag = 0x4, + kAlpha_SkColorTypeComponentFlag = 0x8, + kGray_SkColorTypeComponentFlag = 0x10, + kRGB_SkColorTypeComponentFlags = kRed_SkColorTypeComponentFlag | + kGreen_SkColorTypeComponentFlag | + kBlue_SkColorTypeComponentFlag, + kRGBA_SkColorTypeComponentFlags = kRGB_SkColorTypeComponentFlags | + kAlpha_SkColorTypeComponentFlag, +}; + +static inline uint32_t SkColorTypeComponentFlags(SkColorType ct) { + switch (ct) { + case kUnknown_SkColorType: return 0; + case kAlpha_8_SkColorType: return kAlpha_SkColorTypeComponentFlag; + case kRGB_565_SkColorType: return kRGB_SkColorTypeComponentFlags; + case kARGB_4444_SkColorType: return kRGBA_SkColorTypeComponentFlags; + case kRGBA_8888_SkColorType: return kRGBA_SkColorTypeComponentFlags; + case kRGB_888x_SkColorType: return kRGB_SkColorTypeComponentFlags; + case kBGRA_8888_SkColorType: return kRGBA_SkColorTypeComponentFlags; + case kRGBA_1010102_SkColorType: return kRGBA_SkColorTypeComponentFlags; + case kRGB_101010x_SkColorType: return kRGB_SkColorTypeComponentFlags; + case kGray_8_SkColorType: return kGray_SkColorTypeComponentFlag; + case kRGBA_F16_SkColorType: return kRGBA_SkColorTypeComponentFlags; + case kRGBA_F32_SkColorType: return kRGBA_SkColorTypeComponentFlags; + } + return 0; +} + +static inline bool SkColorTypeIsAlphaOnly(SkColorType ct) { + return kAlpha_SkColorTypeComponentFlag == SkColorTypeComponentFlags(ct); +} + +static inline bool SkAlphaTypeIsValid(unsigned value) { + return value <= kLastEnum_SkAlphaType; +} + +static inline bool SkColorTypeIsGray(SkColorType ct) { + auto flags = SkColorTypeComponentFlags(ct); + // Currently assuming that a color type has only gray or does not have gray. + SkASSERT(!(kGray_SkColorTypeComponentFlag & flags) || kGray_SkColorTypeComponentFlag == flags); + return kGray_SkColorTypeComponentFlag == flags; +} + +static int SkColorTypeShiftPerPixel(SkColorType ct) { + switch (ct) { + case kUnknown_SkColorType: return 0; + case kAlpha_8_SkColorType: return 0; + case kRGB_565_SkColorType: return 1; + case kARGB_4444_SkColorType: return 1; + case kRGBA_8888_SkColorType: return 2; + case kRGB_888x_SkColorType: return 2; + case kBGRA_8888_SkColorType: return 2; + case kRGBA_1010102_SkColorType: return 2; + case kRGB_101010x_SkColorType: return 2; + case kGray_8_SkColorType: return 0; + case kRGBA_F16_SkColorType: return 3; + case kRGBA_F32_SkColorType: return 4; + } + return 0; +} + +static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) { + return width * SkColorTypeBytesPerPixel(ct); +} + +static inline bool SkColorTypeIsValid(unsigned value) { + return value <= kLastEnum_SkColorType; +} + +static inline size_t SkColorTypeComputeOffset(SkColorType ct, int x, int y, size_t rowBytes) { + if (kUnknown_SkColorType == ct) { + return 0; + } + return y * rowBytes + (x << SkColorTypeShiftPerPixel(ct)); +} + +/** + * Returns true if |info| contains a valid combination of width, height, colorType, and alphaType. + */ +static inline bool SkImageInfoIsValid(const SkImageInfo& info) { + if (info.width() <= 0 || info.height() <= 0) { + return false; + } + + const int kMaxDimension = SK_MaxS32 >> 2; + if (info.width() > kMaxDimension || info.height() > kMaxDimension) { + return false; + } + + if (kUnknown_SkColorType == info.colorType() || kUnknown_SkAlphaType == info.alphaType()) { + return false; + } + + return true; +} + +/** + * Returns true if Skia has defined a pixel conversion from the |src| to the |dst|. + * Returns false otherwise. + */ +static inline bool SkImageInfoValidConversion(const SkImageInfo& dst, const SkImageInfo& src) { + return SkImageInfoIsValid(dst) && SkImageInfoIsValid(src); +} +#endif // SkImageInfoPriv_DEFINED diff --git a/skia/include/private/SkLeanWindows.h b/skia/include/private/SkLeanWindows.h new file mode 100644 index 00000000..2bdddbba --- /dev/null +++ b/skia/include/private/SkLeanWindows.h @@ -0,0 +1,34 @@ +/* + * 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 SkLeanWindows_DEFINED +#define SkLeanWindows_DEFINED + +#include "SkTypes.h" + +#ifdef SK_BUILD_FOR_WIN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# define WIN32_IS_MEAN_WAS_LOCALLY_DEFINED +# endif +# ifndef NOMINMAX +# define NOMINMAX +# define NOMINMAX_WAS_LOCALLY_DEFINED +# endif +# +# include +# +# ifdef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED +# undef WIN32_IS_MEAN_WAS_LOCALLY_DEFINED +# undef WIN32_LEAN_AND_MEAN +# endif +# ifdef NOMINMAX_WAS_LOCALLY_DEFINED +# undef NOMINMAX_WAS_LOCALLY_DEFINED +# undef NOMINMAX +# endif +#endif + +#endif // SkLeanWindows_DEFINED diff --git a/skia/include/private/SkMacros.h b/skia/include/private/SkMacros.h new file mode 100644 index 00000000..a6819322 --- /dev/null +++ b/skia/include/private/SkMacros.h @@ -0,0 +1,67 @@ +/* + * 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 SkMacros_DEFINED +#define SkMacros_DEFINED + +/* + * Usage: SK_MACRO_CONCAT(a, b) to construct the symbol ab + * + * SK_MACRO_CONCAT_IMPL_PRIV just exists to make this work. Do not use directly + * + */ +#define SK_MACRO_CONCAT(X, Y) SK_MACRO_CONCAT_IMPL_PRIV(X, Y) +#define SK_MACRO_CONCAT_IMPL_PRIV(X, Y) X ## Y + +/* + * Usage: SK_MACRO_APPEND_LINE(foo) to make foo123, where 123 is the current + * line number. Easy way to construct + * unique names for local functions or + * variables. + */ +#define SK_MACRO_APPEND_LINE(name) SK_MACRO_CONCAT(name, __LINE__) + +/** + * For some classes, it's almost always an error to instantiate one without a name, e.g. + * { + * SkAutoMutexAcquire(&mutex); + * + * } + * In this case, the writer meant to hold mutex while the rest of the code in the block runs, + * but instead the mutex is acquired and then immediately released. The correct usage is + * { + * SkAutoMutexAcquire lock(&mutex); + * + * } + * + * To prevent callers from instantiating your class without a name, use SK_REQUIRE_LOCAL_VAR + * like this: + * class classname { + * + * }; + * #define classname(...) SK_REQUIRE_LOCAL_VAR(classname) + * + * This won't work with templates, and you must inline the class' constructors and destructors. + * Take a look at SkAutoFree and SkAutoMalloc in this file for examples. + */ +#define SK_REQUIRE_LOCAL_VAR(classname) \ + static_assert(false, "missing name for " #classname) + +//////////////////////////////////////////////////////////////////////////////// + +// Can be used to bracket data types that must be dense, e.g. hash keys. +#if defined(__clang__) // This should work on GCC too, but GCC diagnostic pop didn't seem to work! + #define SK_BEGIN_REQUIRE_DENSE _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic error \"-Wpadded\"") + #define SK_END_REQUIRE_DENSE _Pragma("GCC diagnostic pop") +#else + #define SK_BEGIN_REQUIRE_DENSE + #define SK_END_REQUIRE_DENSE +#endif + +#define SK_INIT_TO_AVOID_WARNING = 0 + +#endif // SkMacros_DEFINED diff --git a/skia/include/private/SkMalloc.h b/skia/include/private/SkMalloc.h new file mode 100644 index 00000000..0e41073b --- /dev/null +++ b/skia/include/private/SkMalloc.h @@ -0,0 +1,127 @@ +/* + * 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 SkMalloc_DEFINED +#define SkMalloc_DEFINED + +#include +#include + +#include "SkTypes.h" + +/* + memory wrappers to be implemented by the porting layer (platform) +*/ + + +/** Free memory returned by sk_malloc(). It is safe to pass null. */ +SK_API extern void sk_free(void*); + +/** + * Called internally if we run out of memory. The platform implementation must + * not return, but should either throw an exception or otherwise exit. + */ +SK_API extern void sk_out_of_memory(void); + +enum { + /** + * If this bit is set, the returned buffer must be zero-initialized. If this bit is not set + * the buffer can be uninitialized. + */ + SK_MALLOC_ZERO_INITIALIZE = 1 << 0, + + /** + * If this bit is set, the implementation must throw/crash/quit if the request cannot + * be fulfilled. If this bit is not set, then it should return nullptr on failure. + */ + SK_MALLOC_THROW = 1 << 1, +}; +/** + * Return a block of memory (at least 4-byte aligned) of at least the specified size. + * If the requested memory cannot be returned, either return nullptr or throw/exit, depending + * on the SK_MALLOC_THROW bit. If the allocation succeeds, the memory will be zero-initialized + * if the SK_MALLOC_ZERO_INITIALIZE bit was set. + * + * To free the memory, call sk_free() + */ +SK_API extern void* sk_malloc_flags(size_t size, unsigned flags); + +/** Same as standard realloc(), but this one never returns null on failure. It will throw + * an exception if it fails. + */ +SK_API extern void* sk_realloc_throw(void* buffer, size_t size); + +static inline void* sk_malloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW); +} + +static inline void* sk_calloc_throw(size_t size) { + return sk_malloc_flags(size, SK_MALLOC_THROW | SK_MALLOC_ZERO_INITIALIZE); +} + +static inline void* sk_calloc_canfail(size_t size) { +#if defined(IS_FUZZING_WITH_LIBFUZZER) + // The Libfuzzer environment is very susceptible to OOM, so to avoid those + // just pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, SK_MALLOC_ZERO_INITIALIZE); +} + +// Performs a safe multiply count * elemSize, checking for overflow +SK_API extern void* sk_calloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_malloc_throw(size_t count, size_t elemSize); +SK_API extern void* sk_realloc_throw(void* buffer, size_t count, size_t elemSize); + +/** + * These variants return nullptr on failure + */ +static inline void* sk_malloc_canfail(size_t size) { +#if defined(IS_FUZZING_WITH_LIBFUZZER) + // The Libfuzzer environment is very susceptible to OOM, so to avoid those + // just pretend we can't allocate more than 200kb. + if (size > 200000) { + return nullptr; + } +#endif + return sk_malloc_flags(size, 0); +} +SK_API extern void* sk_malloc_canfail(size_t count, size_t elemSize); + +// bzero is safer than memset, but we can't rely on it, so... sk_bzero() +static inline void sk_bzero(void* buffer, size_t size) { + // Please c.f. sk_careful_memcpy. It's undefined behavior to call memset(null, 0, 0). + if (size) { + memset(buffer, 0, size); + } +} + +/** + * sk_careful_memcpy() is just like memcpy(), but guards against undefined behavior. + * + * It is undefined behavior to call memcpy() with null dst or src, even if len is 0. + * If an optimizer is "smart" enough, it can exploit this to do unexpected things. + * memcpy(dst, src, 0); + * if (src) { + * printf("%x\n", *src); + * } + * In this code the compiler can assume src is not null and omit the if (src) {...} check, + * unconditionally running the printf, crashing the program if src really is null. + * Of the compilers we pay attention to only GCC performs this optimization in practice. + */ +static inline void* sk_careful_memcpy(void* dst, const void* src, size_t len) { + // When we pass >0 len we had better already be passing valid pointers. + // So we just need to skip calling memcpy when len == 0. + if (len) { + memcpy(dst,src,len); + } + return dst; +} + +#endif // SkMalloc_DEFINED diff --git a/skia/include/private/SkMessageBus.h b/skia/include/private/SkMessageBus.h new file mode 100644 index 00000000..649edf60 --- /dev/null +++ b/skia/include/private/SkMessageBus.h @@ -0,0 +1,125 @@ +/* + * 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 SkMessageBus_DEFINED +#define SkMessageBus_DEFINED + +#include "../private/SkNoncopyable.h" +#include "SkMutex.h" +#include "SkOnce.h" +#include "SkTArray.h" +#include "SkTDArray.h" +#include "SkTypes.h" + +/** + * The following method must have a specialization for type 'Message': + * + * bool SkShouldPostMessageToBus(const Message&, uint32_t msgBusUniqueID) + * + * We may want to consider providing a default template implementation, to avoid this requirement by + * sending to all inboxes when the specialization for type 'Message' is not present. + */ +template +class SkMessageBus : SkNoncopyable { +public: + // Post a message to be received by Inboxes for this Message type. Checks + // SkShouldPostMessageToBus() for each inbox. Threadsafe. + static void Post(const Message& m); + + class Inbox { + public: + Inbox(uint32_t uniqueID = SK_InvalidUniqueID); + ~Inbox(); + + uint32_t uniqueID() const { return fUniqueID; } + + // Overwrite out with all the messages we've received since the last call. Threadsafe. + void poll(SkTArray* out); + + private: + SkTArray fMessages; + SkMutex fMessagesMutex; + uint32_t fUniqueID; + + friend class SkMessageBus; + void receive(const Message& m); // SkMessageBus is a friend only to call this. + }; + +private: + SkMessageBus(); + static SkMessageBus* Get(); + + SkTDArray fInboxes; + SkMutex fInboxesMutex; +}; + +// This must go in a single .cpp file, not some .h, or we risk creating more than one global +// SkMessageBus per type when using shared libraries. NOTE: at most one per file will compile. +#define DECLARE_SKMESSAGEBUS_MESSAGE(Message) \ + template <> \ + SkMessageBus* SkMessageBus::Get() { \ + static SkOnce once; \ + static SkMessageBus* bus; \ + once([] { bus = new SkMessageBus(); }); \ + return bus; \ + } + +// ----------------------- Implementation of SkMessageBus::Inbox ----------------------- + +template +SkMessageBus::Inbox::Inbox(uint32_t uniqueID) : fUniqueID(uniqueID) { + // Register ourselves with the corresponding message bus. + SkMessageBus* bus = SkMessageBus::Get(); + SkAutoMutexAcquire lock(bus->fInboxesMutex); + bus->fInboxes.push_back(this); +} + +template +SkMessageBus::Inbox::~Inbox() { + // Remove ourselves from the corresponding message bus. + SkMessageBus* bus = SkMessageBus::Get(); + SkAutoMutexAcquire lock(bus->fInboxesMutex); + // This is a cheaper fInboxes.remove(fInboxes.find(this)) when order doesn't matter. + for (int i = 0; i < bus->fInboxes.count(); i++) { + if (this == bus->fInboxes[i]) { + bus->fInboxes.removeShuffle(i); + break; + } + } +} + +template +void SkMessageBus::Inbox::receive(const Message& m) { + SkAutoMutexAcquire lock(fMessagesMutex); + fMessages.push_back(m); +} + +template +void SkMessageBus::Inbox::poll(SkTArray* messages) { + SkASSERT(messages); + messages->reset(); + SkAutoMutexAcquire lock(fMessagesMutex); + fMessages.swap(*messages); +} + +// ----------------------- Implementation of SkMessageBus ----------------------- + +template +SkMessageBus::SkMessageBus() {} + +template +/*static*/ void SkMessageBus::Post(const Message& m) { + SkMessageBus* bus = SkMessageBus::Get(); + SkAutoMutexAcquire lock(bus->fInboxesMutex); + for (int i = 0; i < bus->fInboxes.count(); i++) { + if (SkShouldPostMessageToBus(m, bus->fInboxes[i]->fUniqueID)) { + bus->fInboxes[i]->receive(m); + } + } +} + +#endif // SkMessageBus_DEFINED diff --git a/skia/include/private/SkMutex.h b/skia/include/private/SkMutex.h new file mode 100644 index 00000000..9af23ada --- /dev/null +++ b/skia/include/private/SkMutex.h @@ -0,0 +1,94 @@ +/* + * 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 SkMutex_DEFINED +#define SkMutex_DEFINED + +#include "../private/SkMacros.h" +#include "../private/SkSemaphore.h" +#include "../private/SkThreadID.h" +#include "SkTypes.h" + +#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name; + +class SkBaseMutex { +public: + constexpr SkBaseMutex() = default; + + void acquire() { + fSemaphore.wait(); + SkDEBUGCODE(fOwner = SkGetThreadID();) + } + + void release() { + this->assertHeld(); + SkDEBUGCODE(fOwner = kIllegalThreadID;) + fSemaphore.signal(); + } + + void assertHeld() { + SkASSERT(fOwner == SkGetThreadID()); + } + +protected: + SkBaseSemaphore fSemaphore{1}; + SkDEBUGCODE(SkThreadID fOwner{kIllegalThreadID};) +}; + +class SkMutex : public SkBaseMutex { +public: + using SkBaseMutex::SkBaseMutex; + ~SkMutex() { fSemaphore.cleanup(); } +}; + +class SkAutoMutexAcquire { +public: + template + SkAutoMutexAcquire(T* mutex) : fMutex(mutex) { + if (mutex) { + mutex->acquire(); + } + fRelease = [](void* mutex) { ((T*)mutex)->release(); }; + } + + template + SkAutoMutexAcquire(T& mutex) : SkAutoMutexAcquire(&mutex) {} + + ~SkAutoMutexAcquire() { this->release(); } + + void release() { + if (fMutex) { + fRelease(fMutex); + } + fMutex = nullptr; + } + +private: + void* fMutex; + void (*fRelease)(void*); +}; +#define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire) + +// SkAutoExclusive is a lighter weight version of SkAutoMutexAcquire. +// It assumes that there is a valid mutex, obviating the null check. +class SkAutoExclusive { +public: + template + SkAutoExclusive(T& mutex) : fMutex(&mutex) { + mutex.acquire(); + + fRelease = [](void* mutex) { ((T*)mutex)->release(); }; + } + ~SkAutoExclusive() { fRelease(fMutex); } + +private: + void* fMutex; + void (*fRelease)(void*); +}; +#define SkAutoExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoExclusive) + +#endif//SkMutex_DEFINED diff --git a/skia/include/private/SkNoncopyable.h b/skia/include/private/SkNoncopyable.h new file mode 100644 index 00000000..518b3eeb --- /dev/null +++ b/skia/include/private/SkNoncopyable.h @@ -0,0 +1,30 @@ +/* + * 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 SkNoncopyable_DEFINED +#define SkNoncopyable_DEFINED + +#include "SkTypes.h" + +/** \class SkNoncopyable + + SkNoncopyable is the base class for objects that do not want to + be copied. It hides its copy-constructor and its assignment-operator. +*/ +class SK_API SkNoncopyable { +public: + SkNoncopyable() = default; + + SkNoncopyable(SkNoncopyable&&) = default; + SkNoncopyable& operator =(SkNoncopyable&&) = default; + +private: + SkNoncopyable(const SkNoncopyable&) = delete; + SkNoncopyable& operator=(const SkNoncopyable&) = delete; +}; + +#endif diff --git a/skia/include/private/SkNx.h b/skia/include/private/SkNx.h new file mode 100644 index 00000000..29c4d735 --- /dev/null +++ b/skia/include/private/SkNx.h @@ -0,0 +1,434 @@ +/* + * 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 SkNx_DEFINED +#define SkNx_DEFINED + +#include "SkSafe_math.h" +#include "SkScalar.h" +#include "SkTypes.h" + +#include +#include +#include + +// Every single SkNx method wants to be fully inlined. (We know better than MSVC). +#define AI SK_ALWAYS_INLINE + +namespace { + +// The default SkNx just proxies down to a pair of SkNx. +template +struct SkNx { + typedef SkNx Half; + + Half fLo, fHi; + + AI SkNx() = default; + AI SkNx(const Half& lo, const Half& hi) : fLo(lo), fHi(hi) {} + + AI SkNx(T v) : fLo(v), fHi(v) {} + + AI SkNx(T a, T b) : fLo(a) , fHi(b) { static_assert(N==2, ""); } + AI SkNx(T a, T b, T c, T d) : fLo(a,b), fHi(c,d) { static_assert(N==4, ""); } + AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h) : fLo(a,b,c,d), fHi(e,f,g,h) { + static_assert(N==8, ""); + } + AI SkNx(T a, T b, T c, T d, T e, T f, T g, T h, + T i, T j, T k, T l, T m, T n, T o, T p) + : fLo(a,b,c,d, e,f,g,h), fHi(i,j,k,l, m,n,o,p) { + static_assert(N==16, ""); + } + + AI T operator[](int k) const { + SkASSERT(0 <= k && k < N); + return k < N/2 ? fLo[k] : fHi[k-N/2]; + } + + AI static SkNx Load(const void* vptr) { + auto ptr = (const char*)vptr; + return { Half::Load(ptr), Half::Load(ptr + N/2*sizeof(T)) }; + } + AI void store(void* vptr) const { + auto ptr = (char*)vptr; + fLo.store(ptr); + fHi.store(ptr + N/2*sizeof(T)); + } + + AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { + auto ptr = (const char*)vptr; + Half al, bl, cl, dl, + ah, bh, ch, dh; + Half::Load4(ptr , &al, &bl, &cl, &dl); + Half::Load4(ptr + 4*N/2*sizeof(T), &ah, &bh, &ch, &dh); + *a = SkNx{al, ah}; + *b = SkNx{bl, bh}; + *c = SkNx{cl, ch}; + *d = SkNx{dl, dh}; + } + AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) { + auto ptr = (const char*)vptr; + Half al, bl, cl, + ah, bh, ch; + Half::Load3(ptr , &al, &bl, &cl); + Half::Load3(ptr + 3*N/2*sizeof(T), &ah, &bh, &ch); + *a = SkNx{al, ah}; + *b = SkNx{bl, bh}; + *c = SkNx{cl, ch}; + } + AI static void Load2(const void* vptr, SkNx* a, SkNx* b) { + auto ptr = (const char*)vptr; + Half al, bl, + ah, bh; + Half::Load2(ptr , &al, &bl); + Half::Load2(ptr + 2*N/2*sizeof(T), &ah, &bh); + *a = SkNx{al, ah}; + *b = SkNx{bl, bh}; + } + AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + auto ptr = (char*)vptr; + Half::Store4(ptr, a.fLo, b.fLo, c.fLo, d.fLo); + Half::Store4(ptr + 4*N/2*sizeof(T), a.fHi, b.fHi, c.fHi, d.fHi); + } + AI static void Store3(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c) { + auto ptr = (char*)vptr; + Half::Store3(ptr, a.fLo, b.fLo, c.fLo); + Half::Store3(ptr + 3*N/2*sizeof(T), a.fHi, b.fHi, c.fHi); + } + AI static void Store2(void* vptr, const SkNx& a, const SkNx& b) { + auto ptr = (char*)vptr; + Half::Store2(ptr, a.fLo, b.fLo); + Half::Store2(ptr + 2*N/2*sizeof(T), a.fHi, b.fHi); + } + + AI T min() const { return SkTMin(fLo.min(), fHi.min()); } + AI T max() const { return SkTMax(fLo.max(), fHi.max()); } + AI bool anyTrue() const { return fLo.anyTrue() || fHi.anyTrue(); } + AI bool allTrue() const { return fLo.allTrue() && fHi.allTrue(); } + + AI SkNx abs() const { return { fLo. abs(), fHi. abs() }; } + AI SkNx sqrt() const { return { fLo. sqrt(), fHi. sqrt() }; } + AI SkNx rsqrt() const { return { fLo. rsqrt(), fHi. rsqrt() }; } + AI SkNx floor() const { return { fLo. floor(), fHi. floor() }; } + AI SkNx invert() const { return { fLo.invert(), fHi.invert() }; } + + AI SkNx operator!() const { return { !fLo, !fHi }; } + AI SkNx operator-() const { return { -fLo, -fHi }; } + AI SkNx operator~() const { return { ~fLo, ~fHi }; } + + AI SkNx operator<<(int bits) const { return { fLo << bits, fHi << bits }; } + AI SkNx operator>>(int bits) const { return { fLo >> bits, fHi >> bits }; } + + AI SkNx operator+(const SkNx& y) const { return { fLo + y.fLo, fHi + y.fHi }; } + AI SkNx operator-(const SkNx& y) const { return { fLo - y.fLo, fHi - y.fHi }; } + AI SkNx operator*(const SkNx& y) const { return { fLo * y.fLo, fHi * y.fHi }; } + AI SkNx operator/(const SkNx& y) const { return { fLo / y.fLo, fHi / y.fHi }; } + + AI SkNx operator&(const SkNx& y) const { return { fLo & y.fLo, fHi & y.fHi }; } + AI SkNx operator|(const SkNx& y) const { return { fLo | y.fLo, fHi | y.fHi }; } + AI SkNx operator^(const SkNx& y) const { return { fLo ^ y.fLo, fHi ^ y.fHi }; } + + AI SkNx operator==(const SkNx& y) const { return { fLo == y.fLo, fHi == y.fHi }; } + AI SkNx operator!=(const SkNx& y) const { return { fLo != y.fLo, fHi != y.fHi }; } + AI SkNx operator<=(const SkNx& y) const { return { fLo <= y.fLo, fHi <= y.fHi }; } + AI SkNx operator>=(const SkNx& y) const { return { fLo >= y.fLo, fHi >= y.fHi }; } + AI SkNx operator< (const SkNx& y) const { return { fLo < y.fLo, fHi < y.fHi }; } + AI SkNx operator> (const SkNx& y) const { return { fLo > y.fLo, fHi > y.fHi }; } + + AI SkNx saturatedAdd(const SkNx& y) const { + return { fLo.saturatedAdd(y.fLo), fHi.saturatedAdd(y.fHi) }; + } + + AI SkNx mulHi(const SkNx& m) const { + return { fLo.mulHi(m.fLo), fHi.mulHi(m.fHi) }; + } + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return { fLo.thenElse(t.fLo, e.fLo), fHi.thenElse(t.fHi, e.fHi) }; + } + AI static SkNx Min(const SkNx& x, const SkNx& y) { + return { Half::Min(x.fLo, y.fLo), Half::Min(x.fHi, y.fHi) }; + } + AI static SkNx Max(const SkNx& x, const SkNx& y) { + return { Half::Max(x.fLo, y.fLo), Half::Max(x.fHi, y.fHi) }; + } +}; + +// The N -> N/2 recursion bottoms out at N == 1, a scalar value. +template +struct SkNx<1,T> { + T fVal; + + AI SkNx() = default; + AI SkNx(T v) : fVal(v) {} + + // Android complains against unused parameters, so we guard it + AI T operator[](int SkDEBUGCODE(k)) const { + SkASSERT(k == 0); + return fVal; + } + + AI static SkNx Load(const void* ptr) { + SkNx v; + memcpy(&v, ptr, sizeof(T)); + return v; + } + AI void store(void* ptr) const { memcpy(ptr, &fVal, sizeof(T)); } + + AI static void Load4(const void* vptr, SkNx* a, SkNx* b, SkNx* c, SkNx* d) { + auto ptr = (const char*)vptr; + *a = Load(ptr + 0*sizeof(T)); + *b = Load(ptr + 1*sizeof(T)); + *c = Load(ptr + 2*sizeof(T)); + *d = Load(ptr + 3*sizeof(T)); + } + AI static void Load3(const void* vptr, SkNx* a, SkNx* b, SkNx* c) { + auto ptr = (const char*)vptr; + *a = Load(ptr + 0*sizeof(T)); + *b = Load(ptr + 1*sizeof(T)); + *c = Load(ptr + 2*sizeof(T)); + } + AI static void Load2(const void* vptr, SkNx* a, SkNx* b) { + auto ptr = (const char*)vptr; + *a = Load(ptr + 0*sizeof(T)); + *b = Load(ptr + 1*sizeof(T)); + } + AI static void Store4(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + auto ptr = (char*)vptr; + a.store(ptr + 0*sizeof(T)); + b.store(ptr + 1*sizeof(T)); + c.store(ptr + 2*sizeof(T)); + d.store(ptr + 3*sizeof(T)); + } + AI static void Store3(void* vptr, const SkNx& a, const SkNx& b, const SkNx& c) { + auto ptr = (char*)vptr; + a.store(ptr + 0*sizeof(T)); + b.store(ptr + 1*sizeof(T)); + c.store(ptr + 2*sizeof(T)); + } + AI static void Store2(void* vptr, const SkNx& a, const SkNx& b) { + auto ptr = (char*)vptr; + a.store(ptr + 0*sizeof(T)); + b.store(ptr + 1*sizeof(T)); + } + + AI T min() const { return fVal; } + AI T max() const { return fVal; } + AI bool anyTrue() const { return fVal != 0; } + AI bool allTrue() const { return fVal != 0; } + + AI SkNx abs() const { return Abs(fVal); } + AI SkNx sqrt() const { return Sqrt(fVal); } + AI SkNx rsqrt() const { return T(1) / this->sqrt(); } + AI SkNx floor() const { return Floor(fVal); } + AI SkNx invert() const { return T(1) / *this; } + + AI SkNx operator!() const { return !fVal; } + AI SkNx operator-() const { return -fVal; } + AI SkNx operator~() const { return FromBits(~ToBits(fVal)); } + + AI SkNx operator<<(int bits) const { return fVal << bits; } + AI SkNx operator>>(int bits) const { return fVal >> bits; } + + AI SkNx operator+(const SkNx& y) const { return fVal + y.fVal; } + AI SkNx operator-(const SkNx& y) const { return fVal - y.fVal; } + AI SkNx operator*(const SkNx& y) const { return fVal * y.fVal; } + AI SkNx operator/(const SkNx& y) const { return fVal / y.fVal; } + + AI SkNx operator&(const SkNx& y) const { return FromBits(ToBits(fVal) & ToBits(y.fVal)); } + AI SkNx operator|(const SkNx& y) const { return FromBits(ToBits(fVal) | ToBits(y.fVal)); } + AI SkNx operator^(const SkNx& y) const { return FromBits(ToBits(fVal) ^ ToBits(y.fVal)); } + + AI SkNx operator==(const SkNx& y) const { return FromBits(fVal == y.fVal ? ~0 : 0); } + AI SkNx operator!=(const SkNx& y) const { return FromBits(fVal != y.fVal ? ~0 : 0); } + AI SkNx operator<=(const SkNx& y) const { return FromBits(fVal <= y.fVal ? ~0 : 0); } + AI SkNx operator>=(const SkNx& y) const { return FromBits(fVal >= y.fVal ? ~0 : 0); } + AI SkNx operator< (const SkNx& y) const { return FromBits(fVal < y.fVal ? ~0 : 0); } + AI SkNx operator> (const SkNx& y) const { return FromBits(fVal > y.fVal ? ~0 : 0); } + + AI static SkNx Min(const SkNx& x, const SkNx& y) { return x.fVal < y.fVal ? x : y; } + AI static SkNx Max(const SkNx& x, const SkNx& y) { return x.fVal > y.fVal ? x : y; } + + AI SkNx saturatedAdd(const SkNx& y) const { + static_assert(std::is_unsigned::value, ""); + T sum = fVal + y.fVal; + return sum < fVal ? std::numeric_limits::max() : sum; + } + + AI SkNx mulHi(const SkNx& m) const { + static_assert(std::is_unsigned::value, ""); + static_assert(sizeof(T) <= 4, ""); + return static_cast((static_cast(fVal) * m.fVal) >> (sizeof(T)*8)); + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { return fVal != 0 ? t : e; } + +private: + // Helper functions to choose the right float/double methods. (In madness lies...) + AI static int Abs(int val) { return val < 0 ? -val : val; } + + AI static float Abs(float val) { return ::fabsf(val); } + AI static float Sqrt(float val) { return ::sqrtf(val); } + AI static float Floor(float val) { return ::floorf(val); } + + AI static double Abs(double val) { return ::fabs(val); } + AI static double Sqrt(double val) { return ::sqrt(val); } + AI static double Floor(double val) { return ::floor(val); } + + // Helper functions for working with floats/doubles as bit patterns. + template + AI static U ToBits(U v) { return v; } + AI static int32_t ToBits(float v) { int32_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } + AI static int64_t ToBits(double v) { int64_t bits; memcpy(&bits, &v, sizeof(v)); return bits; } + + template + AI static T FromBits(Bits bits) { + static_assert(std::is_pod::value && + std::is_pod::value && + sizeof(T) <= sizeof(Bits), ""); + T val; + memcpy(&val, &bits, sizeof(T)); + return val; + } +}; + +// Allow scalars on the left or right of binary operators, and things like +=, &=, etc. +#define V template AI static SkNx + V operator+ (T x, const SkNx& y) { return SkNx(x) + y; } + V operator- (T x, const SkNx& y) { return SkNx(x) - y; } + V operator* (T x, const SkNx& y) { return SkNx(x) * y; } + V operator/ (T x, const SkNx& y) { return SkNx(x) / y; } + V operator& (T x, const SkNx& y) { return SkNx(x) & y; } + V operator| (T x, const SkNx& y) { return SkNx(x) | y; } + V operator^ (T x, const SkNx& y) { return SkNx(x) ^ y; } + V operator==(T x, const SkNx& y) { return SkNx(x) == y; } + V operator!=(T x, const SkNx& y) { return SkNx(x) != y; } + V operator<=(T x, const SkNx& y) { return SkNx(x) <= y; } + V operator>=(T x, const SkNx& y) { return SkNx(x) >= y; } + V operator< (T x, const SkNx& y) { return SkNx(x) < y; } + V operator> (T x, const SkNx& y) { return SkNx(x) > y; } + + V operator+ (const SkNx& x, T y) { return x + SkNx(y); } + V operator- (const SkNx& x, T y) { return x - SkNx(y); } + V operator* (const SkNx& x, T y) { return x * SkNx(y); } + V operator/ (const SkNx& x, T y) { return x / SkNx(y); } + V operator& (const SkNx& x, T y) { return x & SkNx(y); } + V operator| (const SkNx& x, T y) { return x | SkNx(y); } + V operator^ (const SkNx& x, T y) { return x ^ SkNx(y); } + V operator==(const SkNx& x, T y) { return x == SkNx(y); } + V operator!=(const SkNx& x, T y) { return x != SkNx(y); } + V operator<=(const SkNx& x, T y) { return x <= SkNx(y); } + V operator>=(const SkNx& x, T y) { return x >= SkNx(y); } + V operator< (const SkNx& x, T y) { return x < SkNx(y); } + V operator> (const SkNx& x, T y) { return x > SkNx(y); } + + V& operator<<=(SkNx& x, int bits) { return (x = x << bits); } + V& operator>>=(SkNx& x, int bits) { return (x = x >> bits); } + + V& operator +=(SkNx& x, const SkNx& y) { return (x = x + y); } + V& operator -=(SkNx& x, const SkNx& y) { return (x = x - y); } + V& operator *=(SkNx& x, const SkNx& y) { return (x = x * y); } + V& operator /=(SkNx& x, const SkNx& y) { return (x = x / y); } + V& operator &=(SkNx& x, const SkNx& y) { return (x = x & y); } + V& operator |=(SkNx& x, const SkNx& y) { return (x = x | y); } + V& operator ^=(SkNx& x, const SkNx& y) { return (x = x ^ y); } + + V& operator +=(SkNx& x, T y) { return (x = x + SkNx(y)); } + V& operator -=(SkNx& x, T y) { return (x = x - SkNx(y)); } + V& operator *=(SkNx& x, T y) { return (x = x * SkNx(y)); } + V& operator /=(SkNx& x, T y) { return (x = x / SkNx(y)); } + V& operator &=(SkNx& x, T y) { return (x = x & SkNx(y)); } + V& operator |=(SkNx& x, T y) { return (x = x | SkNx(y)); } + V& operator ^=(SkNx& x, T y) { return (x = x ^ SkNx(y)); } +#undef V + +// SkNx ~~> SkNx + SkNx +template +AI static void SkNx_split(const SkNx& v, SkNx* lo, SkNx* hi) { + *lo = v.fLo; + *hi = v.fHi; +} + +// SkNx + SkNx ~~> SkNx +template +AI static SkNx SkNx_join(const SkNx& lo, const SkNx& hi) { + return { lo, hi }; +} + +// A very generic shuffle. Can reorder, duplicate, contract, expand... +// Sk4f v = { R,G,B,A }; +// SkNx_shuffle<2,1,0,3>(v) ~~> {B,G,R,A} +// SkNx_shuffle<2,1>(v) ~~> {B,G} +// SkNx_shuffle<2,1,2,1,2,1,2,1>(v) ~~> {B,G,B,G,B,G,B,G} +// SkNx_shuffle<3,3,3,3>(v) ~~> {A,A,A,A} +template +AI static SkNx SkNx_shuffle(const SkNx& v) { + return { v[Ix]... }; +} + +// Cast from SkNx to SkNx, as if you called static_cast(Src). +template +AI static SkNx SkNx_cast(const SkNx& v) { + return { SkNx_cast(v.fLo), SkNx_cast(v.fHi) }; +} +template +AI static SkNx<1,Dst> SkNx_cast(const SkNx<1,Src>& v) { + return static_cast(v.fVal); +} + +template +AI static SkNx SkNx_fma(const SkNx& f, const SkNx& m, const SkNx& a) { + return f*m+a; +} + +} // namespace + +typedef SkNx<2, float> Sk2f; +typedef SkNx<4, float> Sk4f; +typedef SkNx<8, float> Sk8f; +typedef SkNx<16, float> Sk16f; + +typedef SkNx<2, SkScalar> Sk2s; +typedef SkNx<4, SkScalar> Sk4s; +typedef SkNx<8, SkScalar> Sk8s; +typedef SkNx<16, SkScalar> Sk16s; + +typedef SkNx<4, uint8_t> Sk4b; +typedef SkNx<8, uint8_t> Sk8b; +typedef SkNx<16, uint8_t> Sk16b; + +typedef SkNx<4, uint16_t> Sk4h; +typedef SkNx<8, uint16_t> Sk8h; +typedef SkNx<16, uint16_t> Sk16h; + +typedef SkNx<4, int32_t> Sk4i; +typedef SkNx<8, int32_t> Sk8i; +typedef SkNx<4, uint32_t> Sk4u; + +// Include platform specific specializations if available. +#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + #include "SkNx_sse.h" +#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) + #include "SkNx_neon.h" +#else + +AI static Sk4i Sk4f_round(const Sk4f& x) { + return { (int) lrintf (x[0]), + (int) lrintf (x[1]), + (int) lrintf (x[2]), + (int) lrintf (x[3]), }; +} + +#endif + +AI static void Sk4f_ToBytes(uint8_t p[16], + const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { + SkNx_cast(SkNx_join(SkNx_join(a,b), SkNx_join(c,d))).store(p); +} + +#undef AI + +#endif//SkNx_DEFINED diff --git a/skia/include/private/SkNx_neon.h b/skia/include/private/SkNx_neon.h new file mode 100644 index 00000000..98ef3fe7 --- /dev/null +++ b/skia/include/private/SkNx_neon.h @@ -0,0 +1,734 @@ +/* + * 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 SkNx_neon_DEFINED +#define SkNx_neon_DEFINED + +#include + +namespace { + +// ARMv8 has vrndm(q)_f32 to floor floats. Here we emulate it: +// - roundtrip through integers via truncation +// - subtract 1 if that's too big (possible for negative values). +// This restricts the domain of our inputs to a maximum somehwere around 2^31. Seems plenty big. +AI static float32x4_t emulate_vrndmq_f32(float32x4_t v) { + auto roundtrip = vcvtq_f32_s32(vcvtq_s32_f32(v)); + auto too_big = vcgtq_f32(roundtrip, v); + return vsubq_f32(roundtrip, (float32x4_t)vandq_u32(too_big, (uint32x4_t)vdupq_n_f32(1))); +} +AI static float32x2_t emulate_vrndm_f32(float32x2_t v) { + auto roundtrip = vcvt_f32_s32(vcvt_s32_f32(v)); + auto too_big = vcgt_f32(roundtrip, v); + return vsub_f32(roundtrip, (float32x2_t)vand_u32(too_big, (uint32x2_t)vdup_n_f32(1))); +} + +template <> +class SkNx<2, float> { +public: + AI SkNx(float32x2_t vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(float val) : fVec(vdup_n_f32(val)) {} + AI SkNx(float a, float b) { fVec = (float32x2_t) { a, b }; } + + AI static SkNx Load(const void* ptr) { return vld1_f32((const float*)ptr); } + AI void store(void* ptr) const { vst1_f32((float*)ptr, fVec); } + + AI static void Load2(const void* ptr, SkNx* x, SkNx* y) { + float32x2x2_t xy = vld2_f32((const float*) ptr); + *x = xy.val[0]; + *y = xy.val[1]; + } + + AI static void Store2(void* dst, const SkNx& a, const SkNx& b) { + float32x2x2_t ab = {{ + a.fVec, + b.fVec, + }}; + vst2_f32((float*) dst, ab); + } + + AI static void Store3(void* dst, const SkNx& a, const SkNx& b, const SkNx& c) { + float32x2x3_t abc = {{ + a.fVec, + b.fVec, + c.fVec, + }}; + vst3_f32((float*) dst, abc); + } + + AI static void Store4(void* dst, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + float32x2x4_t abcd = {{ + a.fVec, + b.fVec, + c.fVec, + d.fVec, + }}; + vst4_f32((float*) dst, abcd); + } + + AI SkNx invert() const { + float32x2_t est0 = vrecpe_f32(fVec), + est1 = vmul_f32(vrecps_f32(est0, fVec), est0); + return est1; + } + + AI SkNx operator - () const { return vneg_f32(fVec); } + + AI SkNx operator + (const SkNx& o) const { return vadd_f32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsub_f32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmul_f32(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { + #if defined(SK_CPU_ARM64) + return vdiv_f32(fVec, o.fVec); + #else + float32x2_t est0 = vrecpe_f32(o.fVec), + est1 = vmul_f32(vrecps_f32(est0, o.fVec), est0), + est2 = vmul_f32(vrecps_f32(est1, o.fVec), est1); + return vmul_f32(fVec, est2); + #endif + } + + AI SkNx operator==(const SkNx& o) const { return vreinterpret_f32_u32(vceq_f32(fVec, o.fVec)); } + AI SkNx operator <(const SkNx& o) const { return vreinterpret_f32_u32(vclt_f32(fVec, o.fVec)); } + AI SkNx operator >(const SkNx& o) const { return vreinterpret_f32_u32(vcgt_f32(fVec, o.fVec)); } + AI SkNx operator<=(const SkNx& o) const { return vreinterpret_f32_u32(vcle_f32(fVec, o.fVec)); } + AI SkNx operator>=(const SkNx& o) const { return vreinterpret_f32_u32(vcge_f32(fVec, o.fVec)); } + AI SkNx operator!=(const SkNx& o) const { + return vreinterpret_f32_u32(vmvn_u32(vceq_f32(fVec, o.fVec))); + } + + AI static SkNx Min(const SkNx& l, const SkNx& r) { return vmin_f32(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return vmax_f32(l.fVec, r.fVec); } + + AI SkNx abs() const { return vabs_f32(fVec); } + AI SkNx floor() const { + #if defined(SK_CPU_ARM64) + return vrndm_f32(fVec); + #else + return emulate_vrndm_f32(fVec); + #endif + } + + AI SkNx rsqrt() const { + float32x2_t est0 = vrsqrte_f32(fVec); + return vmul_f32(vrsqrts_f32(fVec, vmul_f32(est0, est0)), est0); + } + + AI SkNx sqrt() const { + #if defined(SK_CPU_ARM64) + return vsqrt_f32(fVec); + #else + float32x2_t est0 = vrsqrte_f32(fVec), + est1 = vmul_f32(vrsqrts_f32(fVec, vmul_f32(est0, est0)), est0), + est2 = vmul_f32(vrsqrts_f32(fVec, vmul_f32(est1, est1)), est1); + return vmul_f32(fVec, est2); + #endif + } + + AI float operator[](int k) const { + SkASSERT(0 <= k && k < 2); + union { float32x2_t v; float fs[2]; } pun = {fVec}; + return pun.fs[k&1]; + } + + AI bool allTrue() const { + #if defined(SK_CPU_ARM64) + return 0 != vminv_u32(vreinterpret_u32_f32(fVec)); + #else + auto v = vreinterpret_u32_f32(fVec); + return vget_lane_u32(v,0) && vget_lane_u32(v,1); + #endif + } + AI bool anyTrue() const { + #if defined(SK_CPU_ARM64) + return 0 != vmaxv_u32(vreinterpret_u32_f32(fVec)); + #else + auto v = vreinterpret_u32_f32(fVec); + return vget_lane_u32(v,0) || vget_lane_u32(v,1); + #endif + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbsl_f32(vreinterpret_u32_f32(fVec), t.fVec, e.fVec); + } + + float32x2_t fVec; +}; + +template <> +class SkNx<4, float> { +public: + AI SkNx(float32x4_t vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(float val) : fVec(vdupq_n_f32(val)) {} + AI SkNx(float a, float b, float c, float d) { fVec = (float32x4_t) { a, b, c, d }; } + + AI static SkNx Load(const void* ptr) { return vld1q_f32((const float*)ptr); } + AI void store(void* ptr) const { vst1q_f32((float*)ptr, fVec); } + + AI static void Load2(const void* ptr, SkNx* x, SkNx* y) { + float32x4x2_t xy = vld2q_f32((const float*) ptr); + *x = xy.val[0]; + *y = xy.val[1]; + } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + float32x4x4_t rgba = vld4q_f32((const float*) ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + float32x4x4_t rgba = {{ + r.fVec, + g.fVec, + b.fVec, + a.fVec, + }}; + vst4q_f32((float*) dst, rgba); + } + + AI SkNx invert() const { + float32x4_t est0 = vrecpeq_f32(fVec), + est1 = vmulq_f32(vrecpsq_f32(est0, fVec), est0); + return est1; + } + + AI SkNx operator - () const { return vnegq_f32(fVec); } + + AI SkNx operator + (const SkNx& o) const { return vaddq_f32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_f32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_f32(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { + #if defined(SK_CPU_ARM64) + return vdivq_f32(fVec, o.fVec); + #else + float32x4_t est0 = vrecpeq_f32(o.fVec), + est1 = vmulq_f32(vrecpsq_f32(est0, o.fVec), est0), + est2 = vmulq_f32(vrecpsq_f32(est1, o.fVec), est1); + return vmulq_f32(fVec, est2); + #endif + } + + AI SkNx operator==(const SkNx& o) const {return vreinterpretq_f32_u32(vceqq_f32(fVec, o.fVec));} + AI SkNx operator <(const SkNx& o) const {return vreinterpretq_f32_u32(vcltq_f32(fVec, o.fVec));} + AI SkNx operator >(const SkNx& o) const {return vreinterpretq_f32_u32(vcgtq_f32(fVec, o.fVec));} + AI SkNx operator<=(const SkNx& o) const {return vreinterpretq_f32_u32(vcleq_f32(fVec, o.fVec));} + AI SkNx operator>=(const SkNx& o) const {return vreinterpretq_f32_u32(vcgeq_f32(fVec, o.fVec));} + AI SkNx operator!=(const SkNx& o) const { + return vreinterpretq_f32_u32(vmvnq_u32(vceqq_f32(fVec, o.fVec))); + } + + AI static SkNx Min(const SkNx& l, const SkNx& r) { return vminq_f32(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return vmaxq_f32(l.fVec, r.fVec); } + + AI SkNx abs() const { return vabsq_f32(fVec); } + AI SkNx floor() const { + #if defined(SK_CPU_ARM64) + return vrndmq_f32(fVec); + #else + return emulate_vrndmq_f32(fVec); + #endif + } + + + AI SkNx rsqrt() const { + float32x4_t est0 = vrsqrteq_f32(fVec); + return vmulq_f32(vrsqrtsq_f32(fVec, vmulq_f32(est0, est0)), est0); + } + + AI SkNx sqrt() const { + #if defined(SK_CPU_ARM64) + return vsqrtq_f32(fVec); + #else + float32x4_t est0 = vrsqrteq_f32(fVec), + est1 = vmulq_f32(vrsqrtsq_f32(fVec, vmulq_f32(est0, est0)), est0), + est2 = vmulq_f32(vrsqrtsq_f32(fVec, vmulq_f32(est1, est1)), est1); + return vmulq_f32(fVec, est2); + #endif + } + + AI float operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { float32x4_t v; float fs[4]; } pun = {fVec}; + return pun.fs[k&3]; + } + + AI float min() const { + #if defined(SK_CPU_ARM64) + return vminvq_f32(fVec); + #else + SkNx min = Min(*this, vrev64q_f32(fVec)); + return SkTMin(min[0], min[2]); + #endif + } + + AI float max() const { + #if defined(SK_CPU_ARM64) + return vmaxvq_f32(fVec); + #else + SkNx max = Max(*this, vrev64q_f32(fVec)); + return SkTMax(max[0], max[2]); + #endif + } + + AI bool allTrue() const { + #if defined(SK_CPU_ARM64) + return 0 != vminvq_u32(vreinterpretq_u32_f32(fVec)); + #else + auto v = vreinterpretq_u32_f32(fVec); + return vgetq_lane_u32(v,0) && vgetq_lane_u32(v,1) + && vgetq_lane_u32(v,2) && vgetq_lane_u32(v,3); + #endif + } + AI bool anyTrue() const { + #if defined(SK_CPU_ARM64) + return 0 != vmaxvq_u32(vreinterpretq_u32_f32(fVec)); + #else + auto v = vreinterpretq_u32_f32(fVec); + return vgetq_lane_u32(v,0) || vgetq_lane_u32(v,1) + || vgetq_lane_u32(v,2) || vgetq_lane_u32(v,3); + #endif + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbslq_f32(vreinterpretq_u32_f32(fVec), t.fVec, e.fVec); + } + + float32x4_t fVec; +}; + +#if defined(SK_CPU_ARM64) + AI static Sk4f SkNx_fma(const Sk4f& f, const Sk4f& m, const Sk4f& a) { + return vfmaq_f32(a.fVec, f.fVec, m.fVec); + } +#endif + +// It's possible that for our current use cases, representing this as +// half a uint16x8_t might be better than representing it as a uint16x4_t. +// It'd make conversion to Sk4b one step simpler. +template <> +class SkNx<4, uint16_t> { +public: + AI SkNx(const uint16x4_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(vdup_n_u16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) { + fVec = (uint16x4_t) { a,b,c,d }; + } + + AI static SkNx Load(const void* ptr) { return vld1_u16((const uint16_t*)ptr); } + AI void store(void* ptr) const { vst1_u16((uint16_t*)ptr, fVec); } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + uint16x4x4_t rgba = vld4_u16((const uint16_t*)ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + uint16x4x3_t rgba = vld3_u16((const uint16_t*)ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + uint16x4x4_t rgba = {{ + r.fVec, + g.fVec, + b.fVec, + a.fVec, + }}; + vst4_u16((uint16_t*) dst, rgba); + } + + AI SkNx operator + (const SkNx& o) const { return vadd_u16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsub_u16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmul_u16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vand_u16(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorr_u16(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vmin_u16(a.fVec, b.fVec); } + + AI uint16_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { uint16x4_t v; uint16_t us[4]; } pun = {fVec}; + return pun.us[k&3]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbsl_u16(fVec, t.fVec, e.fVec); + } + + uint16x4_t fVec; +}; + +template <> +class SkNx<8, uint16_t> { +public: + AI SkNx(const uint16x8_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(vdupq_n_u16(val)) {} + AI static SkNx Load(const void* ptr) { return vld1q_u16((const uint16_t*)ptr); } + + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + uint16_t e, uint16_t f, uint16_t g, uint16_t h) { + fVec = (uint16x8_t) { a,b,c,d, e,f,g,h }; + } + + AI void store(void* ptr) const { vst1q_u16((uint16_t*)ptr, fVec); } + + AI SkNx operator + (const SkNx& o) const { return vaddq_u16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_u16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return vandq_u16(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_u16(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u16(a.fVec, b.fVec); } + + AI uint16_t operator[](int k) const { + SkASSERT(0 <= k && k < 8); + union { uint16x8_t v; uint16_t us[8]; } pun = {fVec}; + return pun.us[k&7]; + } + + AI SkNx mulHi(const SkNx& m) const { + uint32x4_t hi = vmull_u16(vget_high_u16(fVec), vget_high_u16(m.fVec)); + uint32x4_t lo = vmull_u16( vget_low_u16(fVec), vget_low_u16(m.fVec)); + + return { vcombine_u16(vshrn_n_u32(lo,16), vshrn_n_u32(hi,16)) }; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbslq_u16(fVec, t.fVec, e.fVec); + } + + uint16x8_t fVec; +}; + +template <> +class SkNx<4, uint8_t> { +public: + typedef uint32_t __attribute__((aligned(1))) unaligned_uint32_t; + + AI SkNx(const uint8x8_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) { + fVec = (uint8x8_t){a,b,c,d, 0,0,0,0}; + } + AI static SkNx Load(const void* ptr) { + return (uint8x8_t)vld1_dup_u32((const unaligned_uint32_t*)ptr); + } + AI void store(void* ptr) const { + return vst1_lane_u32((unaligned_uint32_t*)ptr, (uint32x2_t)fVec, 0); + } + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { uint8x8_t v; uint8_t us[8]; } pun = {fVec}; + return pun.us[k&3]; + } + + // TODO as needed + + uint8x8_t fVec; +}; + +template <> +class SkNx<8, uint8_t> { +public: + AI SkNx(const uint8x8_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(vdup_n_u8(val)) {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h) { + fVec = (uint8x8_t) { a,b,c,d, e,f,g,h }; + } + + AI static SkNx Load(const void* ptr) { return vld1_u8((const uint8_t*)ptr); } + AI void store(void* ptr) const { vst1_u8((uint8_t*)ptr, fVec); } + + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 8); + union { uint8x8_t v; uint8_t us[8]; } pun = {fVec}; + return pun.us[k&7]; + } + + uint8x8_t fVec; +}; + +template <> +class SkNx<16, uint8_t> { +public: + AI SkNx(const uint8x16_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(vdupq_n_u8(val)) {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, + uint8_t m, uint8_t n, uint8_t o, uint8_t p) { + fVec = (uint8x16_t) { a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p }; + } + + AI static SkNx Load(const void* ptr) { return vld1q_u8((const uint8_t*)ptr); } + AI void store(void* ptr) const { vst1q_u8((uint8_t*)ptr, fVec); } + + AI SkNx saturatedAdd(const SkNx& o) const { return vqaddq_u8(fVec, o.fVec); } + + AI SkNx operator + (const SkNx& o) const { return vaddq_u8(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u8(fVec, o.fVec); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u8(a.fVec, b.fVec); } + AI SkNx operator < (const SkNx& o) const { return vcltq_u8(fVec, o.fVec); } + + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 16); + union { uint8x16_t v; uint8_t us[16]; } pun = {fVec}; + return pun.us[k&15]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbslq_u8(fVec, t.fVec, e.fVec); + } + + uint8x16_t fVec; +}; + +template <> +class SkNx<4, int32_t> { +public: + AI SkNx(const int32x4_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(int32_t v) { + fVec = vdupq_n_s32(v); + } + AI SkNx(int32_t a, int32_t b, int32_t c, int32_t d) { + fVec = (int32x4_t){a,b,c,d}; + } + AI static SkNx Load(const void* ptr) { + return vld1q_s32((const int32_t*)ptr); + } + AI void store(void* ptr) const { + return vst1q_s32((int32_t*)ptr, fVec); + } + AI int32_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { int32x4_t v; int32_t is[4]; } pun = {fVec}; + return pun.is[k&3]; + } + + AI SkNx operator + (const SkNx& o) const { return vaddq_s32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_s32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_s32(fVec, o.fVec); } + + AI SkNx operator & (const SkNx& o) const { return vandq_s32(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_s32(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return veorq_s32(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + + AI SkNx operator == (const SkNx& o) const { + return vreinterpretq_s32_u32(vceqq_s32(fVec, o.fVec)); + } + AI SkNx operator < (const SkNx& o) const { + return vreinterpretq_s32_u32(vcltq_s32(fVec, o.fVec)); + } + AI SkNx operator > (const SkNx& o) const { + return vreinterpretq_s32_u32(vcgtq_s32(fVec, o.fVec)); + } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_s32(a.fVec, b.fVec); } + AI static SkNx Max(const SkNx& a, const SkNx& b) { return vmaxq_s32(a.fVec, b.fVec); } + // TODO as needed + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbslq_s32(vreinterpretq_u32_s32(fVec), t.fVec, e.fVec); + } + + AI SkNx abs() const { return vabsq_s32(fVec); } + + int32x4_t fVec; +}; + +template <> +class SkNx<4, uint32_t> { +public: + AI SkNx(const uint32x4_t& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint32_t v) { + fVec = vdupq_n_u32(v); + } + AI SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) { + fVec = (uint32x4_t){a,b,c,d}; + } + AI static SkNx Load(const void* ptr) { + return vld1q_u32((const uint32_t*)ptr); + } + AI void store(void* ptr) const { + return vst1q_u32((uint32_t*)ptr, fVec); + } + AI uint32_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { uint32x4_t v; uint32_t us[4]; } pun = {fVec}; + return pun.us[k&3]; + } + + AI SkNx operator + (const SkNx& o) const { return vaddq_u32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return vsubq_u32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return vmulq_u32(fVec, o.fVec); } + + AI SkNx operator & (const SkNx& o) const { return vandq_u32(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return vorrq_u32(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return veorq_u32(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return fVec << SkNx(bits).fVec; } + AI SkNx operator >> (int bits) const { return fVec >> SkNx(bits).fVec; } + + AI SkNx operator == (const SkNx& o) const { return vceqq_u32(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return vcltq_u32(fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return vcgtq_u32(fVec, o.fVec); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return vminq_u32(a.fVec, b.fVec); } + // TODO as needed + + AI SkNx mulHi(const SkNx& m) const { + uint64x2_t hi = vmull_u32(vget_high_u32(fVec), vget_high_u32(m.fVec)); + uint64x2_t lo = vmull_u32( vget_low_u32(fVec), vget_low_u32(m.fVec)); + + return { vcombine_u32(vshrn_n_u64(lo,32), vshrn_n_u64(hi,32)) }; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return vbslq_u32(fVec, t.fVec, e.fVec); + } + + uint32x4_t fVec; +}; + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4f& src) { + return vcvtq_s32_f32(src.fVec); + +} +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4i& src) { + return vcvtq_f32_s32(src.fVec); +} +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4u& src) { + return SkNx_cast(Sk4i::Load(&src)); +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4f& src) { + return vqmovn_u32(vcvtq_u32_f32(src.fVec)); +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4h& src) { + return vcvtq_f32_u32(vmovl_u16(src.fVec)); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4f& src) { + uint32x4_t _32 = vcvtq_u32_f32(src.fVec); + uint16x4_t _16 = vqmovn_u32(_32); + return vqmovn_u16(vcombine_u16(_16, _16)); +} + +template<> AI /*static*/ Sk4u SkNx_cast(const Sk4b& src) { + uint16x8_t _16 = vmovl_u8(src.fVec); + return vmovl_u16(vget_low_u16(_16)); +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4b& src) { + return vreinterpretq_s32_u32(SkNx_cast(src).fVec); +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4b& src) { + return vcvtq_f32_s32(SkNx_cast(src).fVec); +} + +template<> AI /*static*/ Sk16b SkNx_cast(const Sk16f& src) { + Sk8f ab, cd; + SkNx_split(src, &ab, &cd); + + Sk4f a,b,c,d; + SkNx_split(ab, &a, &b); + SkNx_split(cd, &c, &d); + return vuzpq_u8(vuzpq_u8((uint8x16_t)vcvtq_u32_f32(a.fVec), + (uint8x16_t)vcvtq_u32_f32(b.fVec)).val[0], + vuzpq_u8((uint8x16_t)vcvtq_u32_f32(c.fVec), + (uint8x16_t)vcvtq_u32_f32(d.fVec)).val[0]).val[0]; +} + +template<> AI /*static*/ Sk8b SkNx_cast(const Sk8i& src) { + Sk4i a, b; + SkNx_split(src, &a, &b); + uint16x4_t a16 = vqmovun_s32(a.fVec); + uint16x4_t b16 = vqmovun_s32(b.fVec); + + return vqmovn_u16(vcombine_u16(a16, b16)); +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4b& src) { + return vget_low_u16(vmovl_u8(src.fVec)); +} + +template<> AI /*static*/ Sk8h SkNx_cast(const Sk8b& src) { + return vmovl_u8(src.fVec); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4h& src) { + return vmovn_u16(vcombine_u16(src.fVec, src.fVec)); +} + +template<> AI /*static*/ Sk8b SkNx_cast(const Sk8h& src) { + return vqmovn_u16(src.fVec); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4i& src) { + uint16x4_t _16 = vqmovun_s32(src.fVec); + return vqmovn_u16(vcombine_u16(_16, _16)); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4u& src) { + uint16x4_t _16 = vqmovn_u32(src.fVec); + return vqmovn_u16(vcombine_u16(_16, _16)); +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4h& src) { + return vreinterpretq_s32_u32(vmovl_u16(src.fVec)); +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4i& src) { + return vmovn_u32(vreinterpretq_u32_s32(src.fVec)); +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4u& src) { + return vreinterpretq_s32_u32(src.fVec); +} + +AI static Sk4i Sk4f_round(const Sk4f& x) { + return vcvtq_s32_f32((x + 0.5f).fVec); +} + +} // namespace + +#endif//SkNx_neon_DEFINED diff --git a/skia/include/private/SkNx_sse.h b/skia/include/private/SkNx_sse.h new file mode 100644 index 00000000..335b70c1 --- /dev/null +++ b/skia/include/private/SkNx_sse.h @@ -0,0 +1,819 @@ +/* + * 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 SkNx_sse_DEFINED +#define SkNx_sse_DEFINED + +#include "SkTypes.h" + +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + #include +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + #include +#else + #include +#endif + +// This file may assume <= SSE2, but must check SK_CPU_SSE_LEVEL for anything more recent. +// If you do, make sure this is in a static inline function... anywhere else risks violating ODR. + +namespace { + +// Emulate _mm_floor_ps() with SSE2: +// - roundtrip through integers via truncation +// - subtract 1 if that's too big (possible for negative values). +// This restricts the domain of our inputs to a maximum somehwere around 2^31. +// Seems plenty big. +AI static __m128 emulate_mm_floor_ps(__m128 v) { + __m128 roundtrip = _mm_cvtepi32_ps(_mm_cvttps_epi32(v)); + __m128 too_big = _mm_cmpgt_ps(roundtrip, v); + return _mm_sub_ps(roundtrip, _mm_and_ps(too_big, _mm_set1_ps(1.0f))); +} + +template <> +class SkNx<2, float> { +public: + AI SkNx(const __m128& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(float val) : fVec(_mm_set1_ps(val)) {} + AI static SkNx Load(const void* ptr) { + return _mm_castsi128_ps(_mm_loadl_epi64((const __m128i*)ptr)); + } + AI SkNx(float a, float b) : fVec(_mm_setr_ps(a,b,0,0)) {} + + AI void store(void* ptr) const { _mm_storel_pi((__m64*)ptr, fVec); } + + AI static void Load2(const void* ptr, SkNx* x, SkNx* y) { + const float* m = (const float*)ptr; + *x = SkNx{m[0], m[2]}; + *y = SkNx{m[1], m[3]}; + } + + AI static void Store2(void* dst, const SkNx& a, const SkNx& b) { + auto vals = _mm_unpacklo_ps(a.fVec, b.fVec); + _mm_storeu_ps((float*)dst, vals); + } + + AI static void Store3(void* dst, const SkNx& a, const SkNx& b, const SkNx& c) { + auto lo = _mm_setr_ps(a[0], b[0], c[0], a[1]), + hi = _mm_setr_ps(b[1], c[1], 0, 0); + _mm_storeu_ps((float*)dst, lo); + _mm_storel_pi(((__m64*)dst) + 2, hi); + } + + AI static void Store4(void* dst, const SkNx& a, const SkNx& b, const SkNx& c, const SkNx& d) { + auto lo = _mm_setr_ps(a[0], b[0], c[0], d[0]), + hi = _mm_setr_ps(a[1], b[1], c[1], d[1]); + _mm_storeu_ps((float*)dst, lo); + _mm_storeu_ps(((float*)dst) + 4, hi); + } + + AI SkNx operator - () const { return _mm_xor_ps(_mm_set1_ps(-0.0f), fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } + + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } + AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } + AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } + + AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } + + AI SkNx abs() const { return _mm_andnot_ps(_mm_set1_ps(-0.0f), fVec); } + AI SkNx floor() const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_floor_ps(fVec); + #else + return emulate_mm_floor_ps(fVec); + #endif + } + + AI SkNx sqrt() const { return _mm_sqrt_ps (fVec); } + AI SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } + AI SkNx invert() const { return _mm_rcp_ps(fVec); } + + AI float operator[](int k) const { + SkASSERT(0 <= k && k < 2); + union { __m128 v; float fs[4]; } pun = {fVec}; + return pun.fs[k&1]; + } + + AI bool allTrue() const { return 0xff == (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } + AI bool anyTrue() const { return 0x00 != (_mm_movemask_epi8(_mm_castps_si128(fVec)) & 0xff); } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_blendv_ps(e.fVec, t.fVec, fVec); + #else + return _mm_or_ps(_mm_and_ps (fVec, t.fVec), + _mm_andnot_ps(fVec, e.fVec)); + #endif + } + + __m128 fVec; +}; + +template <> +class SkNx<4, float> { +public: + AI SkNx(const __m128& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(float val) : fVec( _mm_set1_ps(val) ) {} + AI SkNx(float a, float b, float c, float d) : fVec(_mm_setr_ps(a,b,c,d)) {} + + AI static SkNx Load(const void* ptr) { return _mm_loadu_ps((const float*)ptr); } + AI void store(void* ptr) const { _mm_storeu_ps((float*)ptr, fVec); } + + AI static void Load2(const void* ptr, SkNx* x, SkNx* y) { + SkNx lo = SkNx::Load((const float*)ptr+0), + hi = SkNx::Load((const float*)ptr+4); + *x = SkNx{lo[0], lo[2], hi[0], hi[2]}; + *y = SkNx{lo[1], lo[3], hi[1], hi[3]}; + } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128 v0 = _mm_loadu_ps(((float*)ptr) + 0), + v1 = _mm_loadu_ps(((float*)ptr) + 4), + v2 = _mm_loadu_ps(((float*)ptr) + 8), + v3 = _mm_loadu_ps(((float*)ptr) + 12); + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + *r = v0; + *g = v1; + *b = v2; + *a = v3; + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128 v0 = r.fVec, + v1 = g.fVec, + v2 = b.fVec, + v3 = a.fVec; + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + _mm_storeu_ps(((float*) dst) + 0, v0); + _mm_storeu_ps(((float*) dst) + 4, v1); + _mm_storeu_ps(((float*) dst) + 8, v2); + _mm_storeu_ps(((float*) dst) + 12, v3); + } + + AI SkNx operator - () const { return _mm_xor_ps(_mm_set1_ps(-0.0f), fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_ps(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_ps(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mul_ps(fVec, o.fVec); } + AI SkNx operator / (const SkNx& o) const { return _mm_div_ps(fVec, o.fVec); } + + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_ps (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return _mm_cmpneq_ps(fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_ps (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_ps (fVec, o.fVec); } + AI SkNx operator <= (const SkNx& o) const { return _mm_cmple_ps (fVec, o.fVec); } + AI SkNx operator >= (const SkNx& o) const { return _mm_cmpge_ps (fVec, o.fVec); } + + AI static SkNx Min(const SkNx& l, const SkNx& r) { return _mm_min_ps(l.fVec, r.fVec); } + AI static SkNx Max(const SkNx& l, const SkNx& r) { return _mm_max_ps(l.fVec, r.fVec); } + + AI SkNx abs() const { return _mm_andnot_ps(_mm_set1_ps(-0.0f), fVec); } + AI SkNx floor() const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_floor_ps(fVec); + #else + return emulate_mm_floor_ps(fVec); + #endif + } + + AI SkNx sqrt() const { return _mm_sqrt_ps (fVec); } + AI SkNx rsqrt() const { return _mm_rsqrt_ps(fVec); } + AI SkNx invert() const { return _mm_rcp_ps(fVec); } + + AI float operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { __m128 v; float fs[4]; } pun = {fVec}; + return pun.fs[k&3]; + } + + AI float min() const { + SkNx min = Min(*this, _mm_shuffle_ps(fVec, fVec, _MM_SHUFFLE(2,3,0,1))); + min = Min(min, _mm_shuffle_ps(min.fVec, min.fVec, _MM_SHUFFLE(0,1,2,3))); + return min[0]; + } + + AI float max() const { + SkNx max = Max(*this, _mm_shuffle_ps(fVec, fVec, _MM_SHUFFLE(2,3,0,1))); + max = Max(max, _mm_shuffle_ps(max.fVec, max.fVec, _MM_SHUFFLE(0,1,2,3))); + return max[0]; + } + + AI bool allTrue() const { return 0xffff == _mm_movemask_epi8(_mm_castps_si128(fVec)); } + AI bool anyTrue() const { return 0x0000 != _mm_movemask_epi8(_mm_castps_si128(fVec)); } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_blendv_ps(e.fVec, t.fVec, fVec); + #else + return _mm_or_ps(_mm_and_ps (fVec, t.fVec), + _mm_andnot_ps(fVec, e.fVec)); + #endif + } + + __m128 fVec; +}; + +AI static __m128i mullo32(__m128i a, __m128i b) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_mullo_epi32(a, b); +#else + __m128i mul20 = _mm_mul_epu32(a, b), + mul31 = _mm_mul_epu32(_mm_srli_si128(a, 4), _mm_srli_si128(b, 4)); + return _mm_unpacklo_epi32(_mm_shuffle_epi32(mul20, _MM_SHUFFLE(0,0,2,0)), + _mm_shuffle_epi32(mul31, _MM_SHUFFLE(0,0,2,0))); +#endif +} + +template <> +class SkNx<4, int32_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(int32_t val) : fVec(_mm_set1_epi32(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(int32_t a, int32_t b, int32_t c, int32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} + + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return mullo32(fVec, o.fVec); } + + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srai_epi32(fVec, bits); } + + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } + AI SkNx operator < (const SkNx& o) const { return _mm_cmplt_epi32 (fVec, o.fVec); } + AI SkNx operator > (const SkNx& o) const { return _mm_cmpgt_epi32 (fVec, o.fVec); } + + AI int32_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { __m128i v; int32_t is[4]; } pun = {fVec}; + return pun.is[k&3]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_blendv_epi8(e.fVec, t.fVec, fVec); + #else + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); + #endif + } + + AI SkNx abs() const { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + return _mm_abs_epi32(fVec); +#else + SkNx mask = (*this) >> 31; + return (mask ^ (*this)) - mask; +#endif + } + + AI static SkNx Min(const SkNx& x, const SkNx& y) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_min_epi32(x.fVec, y.fVec); +#else + return (x < y).thenElse(x, y); +#endif + } + + AI static SkNx Max(const SkNx& x, const SkNx& y) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_max_epi32(x.fVec, y.fVec); +#else + return (x > y).thenElse(x, y); +#endif + } + + __m128i fVec; +}; + +template <> +class SkNx<2, uint32_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint32_t val) : fVec(_mm_set1_epi32(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); } + AI SkNx(uint32_t a, uint32_t b) : fVec(_mm_setr_epi32(a,b,0,0)) {} + + AI void store(void* ptr) const { _mm_storel_epi64((__m128i*)ptr, fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return mullo32(fVec, o.fVec); } + + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi32(fVec, bits); } + + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return (*this == o) ^ 0xffffffff; } + // operator < and > take a little extra fiddling to make work for unsigned ints. + + AI uint32_t operator[](int k) const { + SkASSERT(0 <= k && k < 2); + union { __m128i v; uint32_t us[4]; } pun = {fVec}; + return pun.us[k&1]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_blendv_epi8(e.fVec, t.fVec, fVec); +#else + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); +#endif + } + + AI bool allTrue() const { return 0xff == (_mm_movemask_epi8(fVec) & 0xff); } + + __m128i fVec; +}; + +template <> +class SkNx<4, uint32_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint32_t val) : fVec(_mm_set1_epi32(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(uint32_t a, uint32_t b, uint32_t c, uint32_t d) : fVec(_mm_setr_epi32(a,b,c,d)) {} + + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi32(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi32(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return mullo32(fVec, o.fVec); } + + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + AI SkNx operator ^ (const SkNx& o) const { return _mm_xor_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi32(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi32(fVec, bits); } + + AI SkNx operator == (const SkNx& o) const { return _mm_cmpeq_epi32 (fVec, o.fVec); } + AI SkNx operator != (const SkNx& o) const { return (*this == o) ^ 0xffffffff; } + + // operator < and > take a little extra fiddling to make work for unsigned ints. + + AI uint32_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { __m128i v; uint32_t us[4]; } pun = {fVec}; + return pun.us[k&3]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + return _mm_blendv_epi8(e.fVec, t.fVec, fVec); + #else + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); + #endif + } + + AI SkNx mulHi(SkNx m) const { + SkNx v20{_mm_mul_epu32(m.fVec, fVec)}; + SkNx v31{_mm_mul_epu32(_mm_srli_si128(m.fVec, 4), _mm_srli_si128(fVec, 4))}; + + return SkNx{v20[1], v31[1], v20[3], v31[3]}; + } + + __m128i fVec; +}; + +template <> +class SkNx<4, uint16_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d) + : fVec(_mm_setr_epi16(a,b,c,d,0,0,0,0)) {} + + AI static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); } + AI void store(void* ptr) const { _mm_storel_epi64((__m128i*)ptr, fVec); } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128i lo = _mm_loadu_si128(((__m128i*)ptr) + 0), + hi = _mm_loadu_si128(((__m128i*)ptr) + 1); + __m128i even = _mm_unpacklo_epi16(lo, hi), // r0 r2 g0 g2 b0 b2 a0 a2 + odd = _mm_unpackhi_epi16(lo, hi); // r1 r3 ... + __m128i rg = _mm_unpacklo_epi16(even, odd), // r0 r1 r2 r3 g0 g1 g2 g3 + ba = _mm_unpackhi_epi16(even, odd); // b0 b1 ... a0 a1 ... + *r = rg; + *g = _mm_srli_si128(rg, 8); + *b = ba; + *a = _mm_srli_si128(ba, 8); + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + // The idea here is to get 4 vectors that are R G B _ _ _ _ _. + // The second load is at a funny location to make sure we don't read past + // the bounds of memory. This is fine, we just need to shift it a little bit. + const uint8_t* ptr8 = (const uint8_t*) ptr; + __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 + 0)); + __m128i rgb1 = _mm_srli_si128(rgb0, 3*2); + __m128i rgb2 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 4*2)), 2*2); + __m128i rgb3 = _mm_srli_si128(rgb2, 3*2); + + __m128i rrggbb01 = _mm_unpacklo_epi16(rgb0, rgb1); + __m128i rrggbb23 = _mm_unpacklo_epi16(rgb2, rgb3); + *r = _mm_unpacklo_epi32(rrggbb01, rrggbb23); + *g = _mm_srli_si128(r->fVec, 4*2); + *b = _mm_unpackhi_epi32(rrggbb01, rrggbb23); + } + AI static void Store4(void* dst, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128i rg = _mm_unpacklo_epi16(r.fVec, g.fVec); + __m128i ba = _mm_unpacklo_epi16(b.fVec, a.fVec); + __m128i lo = _mm_unpacklo_epi32(rg, ba); + __m128i hi = _mm_unpackhi_epi32(rg, ba); + _mm_storeu_si128(((__m128i*) dst) + 0, lo); + _mm_storeu_si128(((__m128i*) dst) + 1, hi); + } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + + AI uint16_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { __m128i v; uint16_t us[8]; } pun = {fVec}; + return pun.us[k&3]; + } + + __m128i fVec; +}; + +template <> +class SkNx<8, uint16_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint16_t val) : fVec(_mm_set1_epi16(val)) {} + AI SkNx(uint16_t a, uint16_t b, uint16_t c, uint16_t d, + uint16_t e, uint16_t f, uint16_t g, uint16_t h) + : fVec(_mm_setr_epi16(a,b,c,d,e,f,g,h)) {} + + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + + AI static void Load4(const void* ptr, SkNx* r, SkNx* g, SkNx* b, SkNx* a) { + __m128i _01 = _mm_loadu_si128(((__m128i*)ptr) + 0), + _23 = _mm_loadu_si128(((__m128i*)ptr) + 1), + _45 = _mm_loadu_si128(((__m128i*)ptr) + 2), + _67 = _mm_loadu_si128(((__m128i*)ptr) + 3); + + __m128i _02 = _mm_unpacklo_epi16(_01, _23), // r0 r2 g0 g2 b0 b2 a0 a2 + _13 = _mm_unpackhi_epi16(_01, _23), // r1 r3 g1 g3 b1 b3 a1 a3 + _46 = _mm_unpacklo_epi16(_45, _67), + _57 = _mm_unpackhi_epi16(_45, _67); + + __m128i rg0123 = _mm_unpacklo_epi16(_02, _13), // r0 r1 r2 r3 g0 g1 g2 g3 + ba0123 = _mm_unpackhi_epi16(_02, _13), // b0 b1 b2 b3 a0 a1 a2 a3 + rg4567 = _mm_unpacklo_epi16(_46, _57), + ba4567 = _mm_unpackhi_epi16(_46, _57); + + *r = _mm_unpacklo_epi64(rg0123, rg4567); + *g = _mm_unpackhi_epi64(rg0123, rg4567); + *b = _mm_unpacklo_epi64(ba0123, ba4567); + *a = _mm_unpackhi_epi64(ba0123, ba4567); + } + AI static void Load3(const void* ptr, SkNx* r, SkNx* g, SkNx* b) { + const uint8_t* ptr8 = (const uint8_t*) ptr; + __m128i rgb0 = _mm_loadu_si128((const __m128i*) (ptr8 + 0*2)); + __m128i rgb1 = _mm_srli_si128(rgb0, 3*2); + __m128i rgb2 = _mm_loadu_si128((const __m128i*) (ptr8 + 6*2)); + __m128i rgb3 = _mm_srli_si128(rgb2, 3*2); + __m128i rgb4 = _mm_loadu_si128((const __m128i*) (ptr8 + 12*2)); + __m128i rgb5 = _mm_srli_si128(rgb4, 3*2); + __m128i rgb6 = _mm_srli_si128(_mm_loadu_si128((const __m128i*) (ptr8 + 16*2)), 2*2); + __m128i rgb7 = _mm_srli_si128(rgb6, 3*2); + + __m128i rgb01 = _mm_unpacklo_epi16(rgb0, rgb1); + __m128i rgb23 = _mm_unpacklo_epi16(rgb2, rgb3); + __m128i rgb45 = _mm_unpacklo_epi16(rgb4, rgb5); + __m128i rgb67 = _mm_unpacklo_epi16(rgb6, rgb7); + + __m128i rg03 = _mm_unpacklo_epi32(rgb01, rgb23); + __m128i bx03 = _mm_unpackhi_epi32(rgb01, rgb23); + __m128i rg47 = _mm_unpacklo_epi32(rgb45, rgb67); + __m128i bx47 = _mm_unpackhi_epi32(rgb45, rgb67); + + *r = _mm_unpacklo_epi64(rg03, rg47); + *g = _mm_unpackhi_epi64(rg03, rg47); + *b = _mm_unpacklo_epi64(bx03, bx47); + } + AI static void Store4(void* ptr, const SkNx& r, const SkNx& g, const SkNx& b, const SkNx& a) { + __m128i rg0123 = _mm_unpacklo_epi16(r.fVec, g.fVec), // r0 g0 r1 g1 r2 g2 r3 g3 + rg4567 = _mm_unpackhi_epi16(r.fVec, g.fVec), // r4 g4 r5 g5 r6 g6 r7 g7 + ba0123 = _mm_unpacklo_epi16(b.fVec, a.fVec), + ba4567 = _mm_unpackhi_epi16(b.fVec, a.fVec); + + _mm_storeu_si128((__m128i*)ptr + 0, _mm_unpacklo_epi32(rg0123, ba0123)); + _mm_storeu_si128((__m128i*)ptr + 1, _mm_unpackhi_epi32(rg0123, ba0123)); + _mm_storeu_si128((__m128i*)ptr + 2, _mm_unpacklo_epi32(rg4567, ba4567)); + _mm_storeu_si128((__m128i*)ptr + 3, _mm_unpackhi_epi32(rg4567, ba4567)); + } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi16(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi16(fVec, o.fVec); } + AI SkNx operator * (const SkNx& o) const { return _mm_mullo_epi16(fVec, o.fVec); } + AI SkNx operator & (const SkNx& o) const { return _mm_and_si128(fVec, o.fVec); } + AI SkNx operator | (const SkNx& o) const { return _mm_or_si128(fVec, o.fVec); } + + AI SkNx operator << (int bits) const { return _mm_slli_epi16(fVec, bits); } + AI SkNx operator >> (int bits) const { return _mm_srli_epi16(fVec, bits); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { + // No unsigned _mm_min_epu16, so we'll shift into a space where we can use the + // signed version, _mm_min_epi16, then shift back. + const uint16_t top = 0x8000; // Keep this separate from _mm_set1_epi16 or MSVC will whine. + const __m128i top_8x = _mm_set1_epi16(top); + return _mm_add_epi8(top_8x, _mm_min_epi16(_mm_sub_epi8(a.fVec, top_8x), + _mm_sub_epi8(b.fVec, top_8x))); + } + + AI SkNx mulHi(const SkNx& m) const { + return _mm_mulhi_epu16(fVec, m.fVec); + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); + } + + AI uint16_t operator[](int k) const { + SkASSERT(0 <= k && k < 8); + union { __m128i v; uint16_t us[8]; } pun = {fVec}; + return pun.us[k&7]; + } + + __m128i fVec; +}; + +template <> +class SkNx<4, uint8_t> { +public: + AI SkNx() {} + AI SkNx(const __m128i& vec) : fVec(vec) {} + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d) + : fVec(_mm_setr_epi8(a,b,c,d, 0,0,0,0, 0,0,0,0, 0,0,0,0)) {} + + AI static SkNx Load(const void* ptr) { return _mm_cvtsi32_si128(*(const int*)ptr); } + AI void store(void* ptr) const { *(int*)ptr = _mm_cvtsi128_si32(fVec); } + + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 4); + union { __m128i v; uint8_t us[16]; } pun = {fVec}; + return pun.us[k&3]; + } + + // TODO as needed + + __m128i fVec; +}; + +template <> +class SkNx<8, uint8_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(_mm_set1_epi8(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadl_epi64((const __m128i*)ptr); } + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h) + : fVec(_mm_setr_epi8(a,b,c,d, e,f,g,h, 0,0,0,0, 0,0,0,0)) {} + + AI void store(void* ptr) const {_mm_storel_epi64((__m128i*)ptr, fVec);} + + AI SkNx saturatedAdd(const SkNx& o) const { return _mm_adds_epu8(fVec, o.fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi8(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi8(fVec, o.fVec); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return _mm_min_epu8(a.fVec, b.fVec); } + AI SkNx operator < (const SkNx& o) const { + // There's no unsigned _mm_cmplt_epu8, so we flip the sign bits then use a signed compare. + auto flip = _mm_set1_epi8(char(0x80)); + return _mm_cmplt_epi8(_mm_xor_si128(flip, fVec), _mm_xor_si128(flip, o.fVec)); + } + + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 16); + union { __m128i v; uint8_t us[16]; } pun = {fVec}; + return pun.us[k&15]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); + } + + __m128i fVec; +}; + +template <> +class SkNx<16, uint8_t> { +public: + AI SkNx(const __m128i& vec) : fVec(vec) {} + + AI SkNx() {} + AI SkNx(uint8_t val) : fVec(_mm_set1_epi8(val)) {} + AI static SkNx Load(const void* ptr) { return _mm_loadu_si128((const __m128i*)ptr); } + AI SkNx(uint8_t a, uint8_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g, uint8_t h, + uint8_t i, uint8_t j, uint8_t k, uint8_t l, + uint8_t m, uint8_t n, uint8_t o, uint8_t p) + : fVec(_mm_setr_epi8(a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p)) {} + + AI void store(void* ptr) const { _mm_storeu_si128((__m128i*)ptr, fVec); } + + AI SkNx saturatedAdd(const SkNx& o) const { return _mm_adds_epu8(fVec, o.fVec); } + + AI SkNx operator + (const SkNx& o) const { return _mm_add_epi8(fVec, o.fVec); } + AI SkNx operator - (const SkNx& o) const { return _mm_sub_epi8(fVec, o.fVec); } + + AI static SkNx Min(const SkNx& a, const SkNx& b) { return _mm_min_epu8(a.fVec, b.fVec); } + AI SkNx operator < (const SkNx& o) const { + // There's no unsigned _mm_cmplt_epu8, so we flip the sign bits then use a signed compare. + auto flip = _mm_set1_epi8(char(0x80)); + return _mm_cmplt_epi8(_mm_xor_si128(flip, fVec), _mm_xor_si128(flip, o.fVec)); + } + + AI uint8_t operator[](int k) const { + SkASSERT(0 <= k && k < 16); + union { __m128i v; uint8_t us[16]; } pun = {fVec}; + return pun.us[k&15]; + } + + AI SkNx thenElse(const SkNx& t, const SkNx& e) const { + return _mm_or_si128(_mm_and_si128 (fVec, t.fVec), + _mm_andnot_si128(fVec, e.fVec)); + } + + __m128i fVec; +}; + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4i& src) { + return _mm_cvtepi32_ps(src.fVec); +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4u& src) { + return SkNx_cast(Sk4i::Load(&src)); +} + +template <> AI /*static*/ Sk4i SkNx_cast(const Sk4f& src) { + return _mm_cvttps_epi32(src.fVec); +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4i& src) { +#if 0 && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + // TODO: This seems to be causing code generation problems. Investigate? + return _mm_packus_epi32(src.fVec); +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + // With SSSE3, we can just shuffle the low 2 bytes from each lane right into place. + const int _ = ~0; + return _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,1, 4,5, 8,9, 12,13, _,_,_,_,_,_,_,_)); +#else + // With SSE2, we have to sign extend our input, making _mm_packs_epi32 do the pack we want. + __m128i x = _mm_srai_epi32(_mm_slli_epi32(src.fVec, 16), 16); + return _mm_packs_epi32(x,x); +#endif +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4f& src) { + return SkNx_cast(SkNx_cast(src)); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4f& src) { + auto _32 = _mm_cvttps_epi32(src.fVec); +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + return _mm_shuffle_epi8(_32, _mm_setr_epi8(0,4,8,12, _,_,_,_, _,_,_,_, _,_,_,_)); +#else + auto _16 = _mm_packus_epi16(_32, _32); + return _mm_packus_epi16(_16, _16); +#endif +} + +template<> AI /*static*/ Sk4u SkNx_cast(const Sk4b& src) { +#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + const int _ = ~0; + return _mm_shuffle_epi8(src.fVec, _mm_setr_epi8(0,_,_,_, 1,_,_,_, 2,_,_,_, 3,_,_,_)); +#else + auto _16 = _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()); + return _mm_unpacklo_epi16(_16, _mm_setzero_si128()); +#endif +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4b& src) { + return SkNx_cast(src).fVec; +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4b& src) { + return _mm_cvtepi32_ps(SkNx_cast(src).fVec); +} + +template<> AI /*static*/ Sk4f SkNx_cast(const Sk4h& src) { + auto _32 = _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128()); + return _mm_cvtepi32_ps(_32); +} + +template<> AI /*static*/ Sk8b SkNx_cast(const Sk8i& src) { + Sk4i lo, hi; + SkNx_split(src, &lo, &hi); + + auto t = _mm_packs_epi32(lo.fVec, hi.fVec); + return _mm_packus_epi16(t, t); +} + +template<> AI /*static*/ Sk16b SkNx_cast(const Sk16f& src) { + Sk8f ab, cd; + SkNx_split(src, &ab, &cd); + + Sk4f a,b,c,d; + SkNx_split(ab, &a, &b); + SkNx_split(cd, &c, &d); + + return _mm_packus_epi16(_mm_packus_epi16(_mm_cvttps_epi32(a.fVec), + _mm_cvttps_epi32(b.fVec)), + _mm_packus_epi16(_mm_cvttps_epi32(c.fVec), + _mm_cvttps_epi32(d.fVec))); +} + +template<> AI /*static*/ Sk4h SkNx_cast(const Sk4b& src) { + return _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()); +} + +template<> AI /*static*/ Sk8h SkNx_cast(const Sk8b& src) { + return _mm_unpacklo_epi8(src.fVec, _mm_setzero_si128()); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4h& src) { + return _mm_packus_epi16(src.fVec, src.fVec); +} + +template<> AI /*static*/ Sk8b SkNx_cast(const Sk8h& src) { + return _mm_packus_epi16(src.fVec, src.fVec); +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4h& src) { + return _mm_unpacklo_epi16(src.fVec, _mm_setzero_si128()); +} + + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4i& src) { + return _mm_packus_epi16(_mm_packus_epi16(src.fVec, src.fVec), src.fVec); +} + +template<> AI /*static*/ Sk4b SkNx_cast(const Sk4u& src) { + return _mm_packus_epi16(_mm_packus_epi16(src.fVec, src.fVec), src.fVec); +} + +template<> AI /*static*/ Sk4i SkNx_cast(const Sk4u& src) { + return src.fVec; +} + +AI static Sk4i Sk4f_round(const Sk4f& x) { + return _mm_cvtps_epi32(x.fVec); +} + +} // namespace + +#endif//SkNx_sse_DEFINED diff --git a/skia/include/private/SkOnce.h b/skia/include/private/SkOnce.h new file mode 100644 index 00000000..72189112 --- /dev/null +++ b/skia/include/private/SkOnce.h @@ -0,0 +1,51 @@ +/* + * 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 SkOnce_DEFINED +#define SkOnce_DEFINED + +#include +#include +#include "SkTypes.h" + +// SkOnce provides call-once guarantees for Skia, much like std::once_flag/std::call_once(). +// +// There should be no particularly error-prone gotcha use cases when using SkOnce. +// It works correctly as a class member, a local, a global, a function-scoped static, whatever. + +class SkOnce { +public: + constexpr SkOnce() = default; + + template + void operator()(Fn&& fn, Args&&... args) { + auto state = fState.load(std::memory_order_acquire); + + if (state == Done) { + return; + } + + // If it looks like no one has started calling fn(), try to claim that job. + if (state == NotStarted && fState.compare_exchange_strong(state, Claimed, + std::memory_order_relaxed, + std::memory_order_relaxed)) { + // Great! We'll run fn() then notify the other threads by releasing Done into fState. + fn(std::forward(args)...); + return fState.store(Done, std::memory_order_release); + } + + // Some other thread is calling fn(). + // We'll just spin here acquiring until it releases Done into fState. + while (fState.load(std::memory_order_acquire) != Done) { /*spin*/ } + } + +private: + enum State : uint8_t { NotStarted, Claimed, Done}; + std::atomic fState{NotStarted}; +}; + +#endif // SkOnce_DEFINED diff --git a/skia/include/private/SkPathRef.h b/skia/include/private/SkPathRef.h new file mode 100644 index 00000000..d250fc37 --- /dev/null +++ b/skia/include/private/SkPathRef.h @@ -0,0 +1,582 @@ +/* + * 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 SkPathRef_DEFINED +#define SkPathRef_DEFINED + +#include "SkAtomics.h" +#include "SkMatrix.h" +#include "SkMutex.h" +#include "SkPoint.h" +#include "SkRRect.h" +#include "SkRect.h" +#include "SkRefCnt.h" +#include "SkTDArray.h" +#include "SkTemplates.h" +#include "SkTo.h" + +#include + +class SkRBuffer; +class SkWBuffer; + +/** + * Holds the path verbs and points. It is versioned by a generation ID. None of its public methods + * modify the contents. To modify or append to the verbs/points wrap the SkPathRef in an + * SkPathRef::Editor object. Installing the editor resets the generation ID. It also performs + * copy-on-write if the SkPathRef is shared by multiple SkPaths. The caller passes the Editor's + * constructor a pointer to a sk_sp, which may be updated to point to a new SkPathRef + * after the editor's constructor returns. + * + * The points and verbs are stored in a single allocation. The points are at the begining of the + * allocation while the verbs are stored at end of the allocation, in reverse order. Thus the points + * and verbs both grow into the middle of the allocation until the meet. To access verb i in the + * verb array use ref.verbs()[~i] (because verbs() returns a pointer just beyond the first + * logical verb or the last verb in memory). + */ + +class SK_API SkPathRef final : public SkNVRefCnt { +public: + class Editor { + public: + Editor(sk_sp* pathRef, + int incReserveVerbs = 0, + int incReservePoints = 0); + + ~Editor() { SkDEBUGCODE(sk_atomic_dec(&fPathRef->fEditorsAttached);) } + + /** + * Returns the array of points. + */ + SkPoint* points() { return fPathRef->getPoints(); } + const SkPoint* points() const { return fPathRef->points(); } + + /** + * Gets the ith point. Shortcut for this->points() + i + */ + SkPoint* atPoint(int i) { + SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); + return this->points() + i; + } + const SkPoint* atPoint(int i) const { + SkASSERT((unsigned) i < (unsigned) fPathRef->fPointCnt); + return this->points() + i; + } + + /** + * Adds the verb and allocates space for the number of points indicated by the verb. The + * return value is a pointer to where the points for the verb should be written. + * 'weight' is only used if 'verb' is kConic_Verb + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight = 0) { + SkDEBUGCODE(fPathRef->validate();) + return fPathRef->growForVerb(verb, weight); + } + + /** + * Allocates space for multiple instances of a particular verb and the + * requisite points & weights. + * The return pointer points at the first new point (indexed normally []). + * If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * space for the conic weights (indexed normally). + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, + int numVbs, + SkScalar** weights = nullptr) { + return fPathRef->growForRepeatedVerb(verb, numVbs, weights); + } + + /** + * Resets the path ref to a new verb and point count. The new verbs and points are + * uninitialized. + */ + void resetToSize(int newVerbCnt, int newPointCnt, int newConicCount) { + fPathRef->resetToSize(newVerbCnt, newPointCnt, newConicCount); + } + + /** + * Gets the path ref that is wrapped in the Editor. + */ + SkPathRef* pathRef() { return fPathRef; } + + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fPathRef->setIsOval(isOval, isCCW, start); + } + + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fPathRef->setIsRRect(isRRect, isCCW, start); + } + + void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } + + private: + SkPathRef* fPathRef; + }; + + class SK_API Iter { + public: + Iter(); + Iter(const SkPathRef&); + + void setPathRef(const SkPathRef&); + + /** Return the next verb in this iteration of the path. When all + segments have been visited, return kDone_Verb. + + If any point in the path is non-finite, return kDone_Verb immediately. + + @param pts The points representing the current verb and/or segment + This must not be NULL. + @return The verb for the current segment + */ + uint8_t next(SkPoint pts[4]); + uint8_t peek() const; + + SkScalar conicWeight() const { return *fConicWeights; } + + private: + const SkPoint* fPts; + const uint8_t* fVerbs; + const uint8_t* fVerbStop; + const SkScalar* fConicWeights; + }; + +public: + /** + * Gets a path ref with no verbs or points. + */ + static SkPathRef* CreateEmpty(); + + /** + * Returns true if all of the points in this path are finite, meaning there + * are no infinities and no NaNs. + */ + bool isFinite() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return SkToBool(fIsFinite); + } + + /** + * Returns a mask, where each bit corresponding to a SegmentMask is + * set if the path contains 1 or more segments of that type. + * Returns 0 for an empty path (no segments). + */ + uint32_t getSegmentMasks() const { return fSegmentMask; } + + /** Returns true if the path is an oval. + * + * @param rect returns the bounding rect of this oval. It's a circle + * if the height and width are the same. + * @param isCCW is the oval CCW (or CW if false). + * @param start indicates where the contour starts on the oval (see + * SkPath::addOval for intepretation of the index). + * + * @return true if this path is an oval. + * Tracking whether a path is an oval is considered an + * optimization for performance and so some paths that are in + * fact ovals can report false. + */ + bool isOval(SkRect* rect, bool* isCCW, unsigned* start) const { + if (fIsOval) { + if (rect) { + *rect = this->getBounds(); + } + if (isCCW) { + *isCCW = SkToBool(fRRectOrOvalIsCCW); + } + if (start) { + *start = fRRectOrOvalStartIdx; + } + } + + return SkToBool(fIsOval); + } + + bool isRRect(SkRRect* rrect, bool* isCCW, unsigned* start) const { + if (fIsRRect) { + if (rrect) { + *rrect = this->getRRect(); + } + if (isCCW) { + *isCCW = SkToBool(fRRectOrOvalIsCCW); + } + if (start) { + *start = fRRectOrOvalStartIdx; + } + } + return SkToBool(fIsRRect); + } + + + bool hasComputedBounds() const { + return !fBoundsIsDirty; + } + + /** Returns the bounds of the path's points. If the path contains 0 or 1 + points, the bounds is set to (0,0,0,0), and isEmpty() will return true. + Note: this bounds may be larger than the actual shape, since curves + do not extend as far as their control points. + */ + const SkRect& getBounds() const { + if (fBoundsIsDirty) { + this->computeBounds(); + } + return fBounds; + } + + SkRRect getRRect() const; + + /** + * Transforms a path ref by a matrix, allocating a new one only if necessary. + */ + static void CreateTransformedCopy(sk_sp* dst, + const SkPathRef& src, + const SkMatrix& matrix); + + static SkPathRef* CreateFromBuffer(SkRBuffer* buffer); + + /** + * Rollsback a path ref to zero verbs and points with the assumption that the path ref will be + * repopulated with approximately the same number of verbs and points. A new path ref is created + * only if necessary. + */ + static void Rewind(sk_sp* pathRef); + + ~SkPathRef(); + int countPoints() const { return fPointCnt; } + int countVerbs() const { return fVerbCnt; } + int countWeights() const { return fConicWeights.count(); } + + /** + * Returns a pointer one beyond the first logical verb (last verb in memory order). + */ + const uint8_t* verbs() const { return fVerbs; } + + /** + * Returns a const pointer to the first verb in memory (which is the last logical verb). + */ + const uint8_t* verbsMemBegin() const { return this->verbs() - fVerbCnt; } + + /** + * Returns a const pointer to the first point. + */ + const SkPoint* points() const { return fPoints; } + + /** + * Shortcut for this->points() + this->countPoints() + */ + const SkPoint* pointsEnd() const { return this->points() + this->countPoints(); } + + const SkScalar* conicWeights() const { return fConicWeights.begin(); } + const SkScalar* conicWeightsEnd() const { return fConicWeights.end(); } + + /** + * Convenience methods for getting to a verb or point by index. + */ + uint8_t atVerb(int index) const { + SkASSERT((unsigned) index < (unsigned) fVerbCnt); + return this->verbs()[~index]; + } + const SkPoint& atPoint(int index) const { + SkASSERT((unsigned) index < (unsigned) fPointCnt); + return this->points()[index]; + } + + bool operator== (const SkPathRef& ref) const; + + /** + * Writes the path points and verbs to a buffer. + */ + void writeToBuffer(SkWBuffer* buffer) const; + + /** + * Gets the number of bytes that would be written in writeBuffer() + */ + uint32_t writeSize() const; + + void interpolate(const SkPathRef& ending, SkScalar weight, SkPathRef* out) const; + + /** + * Gets an ID that uniquely identifies the contents of the path ref. If two path refs have the + * same ID then they have the same verbs and points. However, two path refs may have the same + * contents but different genIDs. + */ + uint32_t genID() const; + + class GenIDChangeListener : public SkRefCnt { + public: + GenIDChangeListener() : fShouldUnregisterFromPath(false) {} + virtual ~GenIDChangeListener() {} + + virtual void onChange() = 0; + + // The caller can use this method to notify the path that it no longer needs to listen. Once + // called, the path will remove this listener from the list at some future point. + void markShouldUnregisterFromPath() { + fShouldUnregisterFromPath.store(true, std::memory_order_relaxed); + } + bool shouldUnregisterFromPath() { + return fShouldUnregisterFromPath.load(std::memory_order_acquire); + } + + private: + std::atomic fShouldUnregisterFromPath; + }; + + void addGenIDChangeListener(sk_sp); // Threadsafe. + + bool isValid() const; + SkDEBUGCODE(void validate() const { SkASSERT(this->isValid()); } ) + +private: + enum SerializationOffsets { + kLegacyRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits, ignored. + kLegacyRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit, ignored. + kLegacyIsRRect_SerializationShift = 26, // requires 1 bit, ignored. + kIsFinite_SerializationShift = 25, // requires 1 bit + kLegacyIsOval_SerializationShift = 24, // requires 1 bit, ignored. + kSegmentMask_SerializationShift = 0 // requires 4 bits (deprecated) + }; + + SkPathRef() { + fBoundsIsDirty = true; // this also invalidates fIsFinite + fPointCnt = 0; + fVerbCnt = 0; + fVerbs = nullptr; + fPoints = nullptr; + fFreeSpace = 0; + fGenerationID = kEmptyGenID; + fSegmentMask = 0; + fIsOval = false; + fIsRRect = false; + // The next two values don't matter unless fIsOval or fIsRRect are true. + fRRectOrOvalIsCCW = false; + fRRectOrOvalStartIdx = 0xAC; + SkDEBUGCODE(fEditorsAttached = 0;) + SkDEBUGCODE(this->validate();) + } + + void copy(const SkPathRef& ref, int additionalReserveVerbs, int additionalReservePoints); + + // Doesn't read fSegmentMask, but (re)computes it from the verbs array + unsigned computeSegmentMask() const; + + // Return true if the computed bounds are finite. + static bool ComputePtBounds(SkRect* bounds, const SkPathRef& ref) { + return bounds->setBoundsCheck(ref.points(), ref.countPoints()); + } + + // called, if dirty, by getBounds() + void computeBounds() const { + SkDEBUGCODE(this->validate();) + // TODO(mtklein): remove fBoundsIsDirty and fIsFinite, + // using an inverted rect instead of fBoundsIsDirty and always recalculating fIsFinite. + SkASSERT(fBoundsIsDirty); + + fIsFinite = ComputePtBounds(&fBounds, *this); + fBoundsIsDirty = false; + } + + void setBounds(const SkRect& rect) { + SkASSERT(rect.fLeft <= rect.fRight && rect.fTop <= rect.fBottom); + fBounds = rect; + fBoundsIsDirty = false; + fIsFinite = fBounds.isFinite(); + } + + /** Makes additional room but does not change the counts or change the genID */ + void incReserve(int additionalVerbs, int additionalPoints) { + SkDEBUGCODE(this->validate();) + size_t space = additionalVerbs * sizeof(uint8_t) + additionalPoints * sizeof (SkPoint); + this->makeSpace(space); + SkDEBUGCODE(this->validate();) + } + + /** Resets the path ref with verbCount verbs and pointCount points, all uninitialized. Also + * allocates space for reserveVerb additional verbs and reservePoints additional points.*/ + void resetToSize(int verbCount, int pointCount, int conicCount, + int reserveVerbs = 0, int reservePoints = 0) { + SkDEBUGCODE(this->validate();) + fBoundsIsDirty = true; // this also invalidates fIsFinite + fGenerationID = 0; + + fSegmentMask = 0; + fIsOval = false; + fIsRRect = false; + + size_t newSize = sizeof(uint8_t) * verbCount + sizeof(SkPoint) * pointCount; + size_t newReserve = sizeof(uint8_t) * reserveVerbs + sizeof(SkPoint) * reservePoints; + size_t minSize = newSize + newReserve; + + ptrdiff_t sizeDelta = this->currSize() - minSize; + + if (sizeDelta < 0 || static_cast(sizeDelta) >= 3 * minSize) { + sk_free(fPoints); + fPoints = nullptr; + fVerbs = nullptr; + fFreeSpace = 0; + fVerbCnt = 0; + fPointCnt = 0; + this->makeSpace(minSize, true); + fVerbCnt = verbCount; + fPointCnt = pointCount; + fFreeSpace -= newSize; + } else { + fPointCnt = pointCount; + fVerbCnt = verbCount; + fFreeSpace = this->currSize() - minSize; + } + fConicWeights.setCount(conicCount); + SkDEBUGCODE(this->validate();) + } + + /** + * Increases the verb count by numVbs and point count by the required amount. + * The new points are uninitialized. All the new verbs are set to the specified + * verb. If 'verb' is kConic_Verb, 'weights' will return a pointer to the + * uninitialized conic weights. + */ + SkPoint* growForRepeatedVerb(int /*SkPath::Verb*/ verb, int numVbs, SkScalar** weights); + + /** + * Increases the verb count 1, records the new verb, and creates room for the requisite number + * of additional points. A pointer to the first point is returned. Any new points are + * uninitialized. + */ + SkPoint* growForVerb(int /*SkPath::Verb*/ verb, SkScalar weight); + + /** + * Ensures that the free space available in the path ref is >= size. The verb and point counts + * are not changed. May allocate extra capacity, unless |exact| is true. + */ + void makeSpace(size_t size, bool exact = false) { + SkDEBUGCODE(this->validate();) + if (size <= fFreeSpace) { + return; + } + size_t growSize = size - fFreeSpace; + size_t oldSize = this->currSize(); + + if (!exact) { + // round to next multiple of 8 bytes + growSize = (growSize + 7) & ~static_cast(7); + // we always at least double the allocation + if (growSize < oldSize) { + growSize = oldSize; + } + if (growSize < kMinSize) { + growSize = kMinSize; + } + } + + constexpr size_t maxSize = std::numeric_limits::max(); + size_t newSize; + if (growSize <= maxSize - oldSize) { + newSize = oldSize + growSize; + } else { + SK_ABORT("Path too big."); + } + // Note that realloc could memcpy more than we need. It seems to be a win anyway. TODO: + // encapsulate this. + fPoints = reinterpret_cast(sk_realloc_throw(fPoints, newSize)); + size_t oldVerbSize = fVerbCnt * sizeof(uint8_t); + void* newVerbsDst = SkTAddOffset(fPoints, newSize - oldVerbSize); + void* oldVerbsSrc = SkTAddOffset(fPoints, oldSize - oldVerbSize); + memmove(newVerbsDst, oldVerbsSrc, oldVerbSize); + fVerbs = SkTAddOffset(fPoints, newSize); + fFreeSpace += growSize; + SkDEBUGCODE(this->validate();) + } + + /** + * Private, non-const-ptr version of the public function verbsMemBegin(). + */ + uint8_t* verbsMemWritable() { + SkDEBUGCODE(this->validate();) + return fVerbs - fVerbCnt; + } + + /** + * Gets the total amount of space allocated for verbs, points, and reserve. + */ + size_t currSize() const { + return reinterpret_cast(fVerbs) - reinterpret_cast(fPoints); + } + + /** + * Called the first time someone calls CreateEmpty to actually create the singleton. + */ + friend SkPathRef* sk_create_empty_pathref(); + + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fIsOval = isOval; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fIsRRect = isRRect; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = SkToU8(start); + } + + // called only by the editor. Note that this is not a const function. + SkPoint* getPoints() { + SkDEBUGCODE(this->validate();) + fIsOval = false; + fIsRRect = false; + return fPoints; + } + + const SkPoint* getPoints() const { + SkDEBUGCODE(this->validate();) + return fPoints; + } + + void callGenIDChangeListeners(); + + enum { + kMinSize = 256, + }; + + mutable SkRect fBounds; + + SkPoint* fPoints; // points to begining of the allocation + uint8_t* fVerbs; // points just past the end of the allocation (verbs grow backwards) + int fVerbCnt; + int fPointCnt; + size_t fFreeSpace; // redundant but saves computation + SkTDArray fConicWeights; + + enum { + kEmptyGenID = 1, // GenID reserved for path ref with zero points and zero verbs. + }; + mutable uint32_t fGenerationID; + SkDEBUGCODE(int32_t fEditorsAttached;) // assert that only one editor in use at any time. + + SkMutex fGenIDChangeListenersMutex; + SkTDArray fGenIDChangeListeners; // pointers are reffed + + mutable uint8_t fBoundsIsDirty; + mutable bool fIsFinite; // only meaningful if bounds are valid + + bool fIsOval; + bool fIsRRect; + // Both the circle and rrect special cases have a notion of direction and starting point + // The next two variables store that information for either. + bool fRRectOrOvalIsCCW; + uint8_t fRRectOrOvalStartIdx; + uint8_t fSegmentMask; + + friend class PathRefTest_Private; + friend class ForceIsRRect_Private; // unit test isRRect + friend class SkPath; +}; + +#endif diff --git a/skia/include/private/SkSafe32.h b/skia/include/private/SkSafe32.h new file mode 100644 index 00000000..7059d3b3 --- /dev/null +++ b/skia/include/private/SkSafe32.h @@ -0,0 +1,34 @@ +/* + * 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 SkSafe32_DEFINED +#define SkSafe32_DEFINED + +#include "SkTypes.h" + +static constexpr int32_t Sk64_pin_to_s32(int64_t x) { + return x < SK_MinS32 ? SK_MinS32 : (x > SK_MaxS32 ? SK_MaxS32 : (int32_t)x); +} + +static constexpr int32_t Sk32_sat_add(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a + (int64_t)b); +} + +static constexpr int32_t Sk32_sat_sub(int32_t a, int32_t b) { + return Sk64_pin_to_s32((int64_t)a - (int64_t)b); +} + +// To avoid UBSAN complaints about 2's compliment overflows +// +static constexpr int32_t Sk32_can_overflow_add(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a + (uint32_t)b); +} +static constexpr int32_t Sk32_can_overflow_sub(int32_t a, int32_t b) { + return (int32_t)((uint32_t)a - (uint32_t)b); +} + +#endif diff --git a/skia/include/private/SkSafe_math.h b/skia/include/private/SkSafe_math.h new file mode 100644 index 00000000..144b28a4 --- /dev/null +++ b/skia/include/private/SkSafe_math.h @@ -0,0 +1,52 @@ +/* + * 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 SkSafe_math_DEFINED +#define SkSafe_math_DEFINED + +// This file protects against known bugs in ucrt\math.h. +// Namely, that header defines inline methods without marking them static, +// which makes it very easy to cause ODR violations and ensuing chaos. +// +// TODO: other headers? Here are some potential problem headers: +// $ grep -R __inline * | grep -v static | cut -f 1 -d: | sort | uniq +// corecrt.h +// corecrt_stdio_config.h +// ctype.h +// fenv.h +// locale.h +// malloc.h +// math.h +// tchar.h +// wchar.h +// I took a quick look through other headers outside math.h. +// Nothing looks anywhere near as likely to be used by Skia as math.h. + +#if defined(_MSC_VER) && !defined(_INC_MATH) + // Our strategy here is to simply inject "static" into the headers + // where it should have been written, just before __inline. + // + // Most inline-but-not-static methods in math.h are 32-bit only, + // but not all of them (see frexpf, hypothf, ldexpf...). So to + // be safe, 32- and 64-bit builds both get this treatment. + + #define __inline static __inline + #include + #undef __inline + + #if !defined(_INC_MATH) + #error Hmm. Looks like math.h has changed its header guards. + #endif + + #define INC_MATH_IS_SAFE_NOW + +#else + #include + +#endif + +#endif//SkSafe_math_DEFINED diff --git a/skia/include/private/SkSemaphore.h b/skia/include/private/SkSemaphore.h new file mode 100644 index 00000000..aeca9729 --- /dev/null +++ b/skia/include/private/SkSemaphore.h @@ -0,0 +1,86 @@ +/* + * 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 SkSemaphore_DEFINED +#define SkSemaphore_DEFINED + +#include "../private/SkOnce.h" +#include "SkTypes.h" +#include + +class SkBaseSemaphore { +public: + constexpr SkBaseSemaphore(int count = 0) + : fCount(count), fOSSemaphore(nullptr) {} + + // Increment the counter n times. + // Generally it's better to call signal(n) instead of signal() n times. + void signal(int n = 1); + + // Decrement the counter by 1, + // then if the counter is < 0, sleep this thread until the counter is >= 0. + void wait(); + + // If the counter is positive, decrement it by 1 and return true, otherwise return false. + bool try_wait(); + + // SkBaseSemaphore has no destructor. Call this to clean it up. + void cleanup(); + +private: + // This implementation follows the general strategy of + // 'A Lightweight Semaphore with Partial Spinning' + // found here + // http://preshing.com/20150316/semaphores-are-surprisingly-versatile/ + // That article (and entire blog) are very much worth reading. + // + // We wrap an OS-provided semaphore with a user-space atomic counter that + // lets us avoid interacting with the OS semaphore unless strictly required: + // moving the count from >=0 to <0 or vice-versa, i.e. sleeping or waking threads. + struct OSSemaphore; + + void osSignal(int n); + void osWait(); + + std::atomic fCount; + SkOnce fOSSemaphoreOnce; + OSSemaphore* fOSSemaphore; +}; + +class SkSemaphore : public SkBaseSemaphore { +public: + using SkBaseSemaphore::SkBaseSemaphore; + ~SkSemaphore() { this->cleanup(); } +}; + +inline void SkBaseSemaphore::signal(int n) { + int prev = fCount.fetch_add(n, std::memory_order_release); + + // We only want to call the OS semaphore when our logical count crosses + // from <0 to >=0 (when we need to wake sleeping threads). + // + // This is easiest to think about with specific examples of prev and n. + // If n == 5 and prev == -3, there are 3 threads sleeping and we signal + // SkTMin(-(-3), 5) == 3 times on the OS semaphore, leaving the count at 2. + // + // If prev >= 0, no threads are waiting, SkTMin(-prev, n) is always <= 0, + // so we don't call the OS semaphore, leaving the count at (prev + n). + int toSignal = SkTMin(-prev, n); + if (toSignal > 0) { + this->osSignal(toSignal); + } +} + +inline void SkBaseSemaphore::wait() { + // Since this fetches the value before the subtract, zero and below means that there are no + // resources left, so the thread needs to wait. + if (fCount.fetch_sub(1, std::memory_order_acquire) <= 0) { + this->osWait(); + } +} + +#endif//SkSemaphore_DEFINED diff --git a/skia/include/private/SkShadowFlags.h b/skia/include/private/SkShadowFlags.h new file mode 100644 index 00000000..8caf6329 --- /dev/null +++ b/skia/include/private/SkShadowFlags.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 SkShadowFlags_DEFINED +#define SkShadowFlags_DEFINED + +// A set of flags shared between the SkAmbientShadowMaskFilter and the SkSpotShadowMaskFilter +enum SkShadowFlags { + kNone_ShadowFlag = 0x00, + /** The occluding object is not opaque. Knowing that the occluder is opaque allows + * us to cull shadow geometry behind it and improve performance. */ + kTransparentOccluder_ShadowFlag = 0x01, + /** Don't try to use analytic shadows. */ + kGeometricOnly_ShadowFlag = 0x02, + /** mask for all shadow flags */ + kAll_ShadowFlag = 0x03 +}; + +#endif diff --git a/skia/include/private/SkSpinlock.h b/skia/include/private/SkSpinlock.h new file mode 100644 index 00000000..669a926c --- /dev/null +++ b/skia/include/private/SkSpinlock.h @@ -0,0 +1,47 @@ +/* + * 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 SkSpinlock_DEFINED +#define SkSpinlock_DEFINED + +#include "SkTypes.h" +#include + +class SkSpinlock { +public: + constexpr SkSpinlock() = default; + + void acquire() { + // To act as a mutex, we need an acquire barrier when we acquire the lock. + if (fLocked.exchange(true, std::memory_order_acquire)) { + // Lock was contended. Fall back to an out-of-line spin loop. + this->contendedAcquire(); + } + } + + // Acquire the lock or fail (quickly). Lets the caller decide to do something other than wait. + bool tryAcquire() { + // To act as a mutex, we need an acquire barrier when we acquire the lock. + if (fLocked.exchange(true, std::memory_order_acquire)) { + // Lock was contended. Let the caller decide what to do. + return false; + } + return true; + } + + void release() { + // To act as a mutex, we need a release barrier when we release the lock. + fLocked.store(false, std::memory_order_release); + } + +private: + SK_API void contendedAcquire(); + + std::atomic fLocked{false}; +}; + +#endif//SkSpinlock_DEFINED diff --git a/skia/include/private/SkTArray.h b/skia/include/private/SkTArray.h new file mode 100644 index 00000000..a18d6e00 --- /dev/null +++ b/skia/include/private/SkTArray.h @@ -0,0 +1,637 @@ +/* + * 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 SkTArray_DEFINED +#define SkTArray_DEFINED + +#include "../private/SkSafe32.h" +#include "../private/SkTLogic.h" +#include "../private/SkTemplates.h" +#include "SkTypes.h" + +#include +#include + +/** When MEM_MOVE is true T will be bit copied when moved. + When MEM_MOVE is false, T will be copy constructed / destructed. + In all cases T will be default-initialized on allocation, + and its destructor will be called from this object's destructor. +*/ +template class SkTArray { +public: + /** + * Creates an empty array with no initial storage + */ + SkTArray() { this->init(); } + + /** + * Creates an empty array that will preallocate space for reserveCount + * elements. + */ + explicit SkTArray(int reserveCount) { this->init(0, reserveCount); } + + /** + * Copies one array to another. The new array will be heap allocated. + */ + SkTArray(const SkTArray& that) { + this->init(that.fCount); + this->copy(that.fItemArray); + } + + SkTArray(SkTArray&& that) { + // TODO: If 'that' owns its memory why don't we just steal the pointer? + this->init(that.fCount); + that.move(fMemArray); + that.fCount = 0; + } + + /** + * Creates a SkTArray by copying contents of a standard C array. The new + * array will be heap allocated. Be careful not to use this constructor + * when you really want the (void*, int) version. + */ + SkTArray(const T* array, int count) { + this->init(count); + this->copy(array); + } + + SkTArray& operator=(const SkTArray& that) { + if (this == &that) { + return *this; + } + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + fCount = 0; + this->checkRealloc(that.count()); + fCount = that.count(); + this->copy(that.fItemArray); + return *this; + } + SkTArray& operator=(SkTArray&& that) { + if (this == &that) { + return *this; + } + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + fCount = 0; + this->checkRealloc(that.count()); + fCount = that.count(); + that.move(fMemArray); + that.fCount = 0; + return *this; + } + + ~SkTArray() { + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + if (fOwnMemory) { + sk_free(fMemArray); + } + } + + /** + * Resets to count() == 0 and resets any reserve count. + */ + void reset() { + this->pop_back_n(fCount); + fReserved = false; + } + + /** + * Resets to count() = n newly constructed T objects and resets any reserve count. + */ + void reset(int n) { + SkASSERT(n >= 0); + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + // Set fCount to 0 before calling checkRealloc so that no elements are moved. + fCount = 0; + this->checkRealloc(n); + fCount = n; + for (int i = 0; i < fCount; ++i) { + new (fItemArray + i) T; + } + fReserved = false; + } + + /** + * Resets to a copy of a C array and resets any reserve count. + */ + void reset(const T* array, int count) { + for (int i = 0; i < fCount; ++i) { + fItemArray[i].~T(); + } + fCount = 0; + this->checkRealloc(count); + fCount = count; + this->copy(array); + fReserved = false; + } + + /** + * Ensures there is enough reserved space for n additional elements. The is guaranteed at least + * until the array size grows above n and subsequently shrinks below n, any version of reset() + * is called, or reserve() is called again. + */ + void reserve(int n) { + SkASSERT(n >= 0); + if (n > 0) { + this->checkRealloc(n); + fReserved = fOwnMemory; + } else { + fReserved = false; + } + } + + void removeShuffle(int n) { + SkASSERT(n < fCount); + int newCount = fCount - 1; + fCount = newCount; + fItemArray[n].~T(); + if (n != newCount) { + this->move(n, newCount); + } + } + + /** + * Number of elements in the array. + */ + int count() const { return fCount; } + + /** + * Is the array empty. + */ + bool empty() const { return !fCount; } + + /** + * Adds 1 new default-initialized T value and returns it by reference. Note + * the reference only remains valid until the next call that adds or removes + * elements. + */ + T& push_back() { + void* newT = this->push_back_raw(1); + return *new (newT) T; + } + + /** + * Version of above that uses a copy constructor to initialize the new item + */ + T& push_back(const T& t) { + void* newT = this->push_back_raw(1); + return *new (newT) T(t); + } + + /** + * Version of above that uses a move constructor to initialize the new item + */ + T& push_back(T&& t) { + void* newT = this->push_back_raw(1); + return *new (newT) T(std::move(t)); + } + + /** + * Construct a new T at the back of this array. + */ + template T& emplace_back(Args&&... args) { + void* newT = this->push_back_raw(1); + return *new (newT) T(std::forward(args)...); + } + + /** + * Allocates n more default-initialized T values, and returns the address of + * the start of that new range. Note: this address is only valid until the + * next API call made on the array that might add or remove elements. + */ + T* push_back_n(int n) { + SkASSERT(n >= 0); + void* newTs = this->push_back_raw(n); + for (int i = 0; i < n; ++i) { + new (static_cast(newTs) + i * sizeof(T)) T; + } + return static_cast(newTs); + } + + /** + * Version of above that uses a copy constructor to initialize all n items + * to the same T. + */ + T* push_back_n(int n, const T& t) { + SkASSERT(n >= 0); + void* newTs = this->push_back_raw(n); + for (int i = 0; i < n; ++i) { + new (static_cast(newTs) + i * sizeof(T)) T(t); + } + return static_cast(newTs); + } + + /** + * Version of above that uses a copy constructor to initialize the n items + * to separate T values. + */ + T* push_back_n(int n, const T t[]) { + SkASSERT(n >= 0); + this->checkRealloc(n); + for (int i = 0; i < n; ++i) { + new (fItemArray + fCount + i) T(t[i]); + } + fCount += n; + return fItemArray + fCount - n; + } + + /** + * Version of above that uses the move constructor to set n items. + */ + T* move_back_n(int n, T* t) { + SkASSERT(n >= 0); + this->checkRealloc(n); + for (int i = 0; i < n; ++i) { + new (fItemArray + fCount + i) T(std::move(t[i])); + } + fCount += n; + return fItemArray + fCount - n; + } + + /** + * Removes the last element. Not safe to call when count() == 0. + */ + void pop_back() { + SkASSERT(fCount > 0); + --fCount; + fItemArray[fCount].~T(); + this->checkRealloc(0); + } + + /** + * Removes the last n elements. Not safe to call when count() < n. + */ + void pop_back_n(int n) { + SkASSERT(n >= 0); + SkASSERT(fCount >= n); + fCount -= n; + for (int i = 0; i < n; ++i) { + fItemArray[fCount + i].~T(); + } + this->checkRealloc(0); + } + + /** + * Pushes or pops from the back to resize. Pushes will be default + * initialized. + */ + void resize_back(int newCount) { + SkASSERT(newCount >= 0); + + if (newCount > fCount) { + this->push_back_n(newCount - fCount); + } else if (newCount < fCount) { + this->pop_back_n(fCount - newCount); + } + } + + /** Swaps the contents of this array with that array. Does a pointer swap if possible, + otherwise copies the T values. */ + void swap(SkTArray& that) { + using std::swap; + if (this == &that) { + return; + } + if (fOwnMemory && that.fOwnMemory) { + swap(fItemArray, that.fItemArray); + swap(fCount, that.fCount); + swap(fAllocCount, that.fAllocCount); + } else { + // This could be more optimal... + SkTArray copy(std::move(that)); + that = std::move(*this); + *this = std::move(copy); + } + } + + T* begin() { + return fItemArray; + } + const T* begin() const { + return fItemArray; + } + T* end() { + return fItemArray ? fItemArray + fCount : nullptr; + } + const T* end() const { + return fItemArray ? fItemArray + fCount : nullptr; + } + T* data() { return fItemArray; } + const T* data() const { return fItemArray; } + size_t size() const { return (size_t)fCount; } + void resize(size_t count) { this->resize_back((int)count); } + + /** + * Get the i^th element. + */ + T& operator[] (int i) { + SkASSERT(i < fCount); + SkASSERT(i >= 0); + return fItemArray[i]; + } + + const T& operator[] (int i) const { + SkASSERT(i < fCount); + SkASSERT(i >= 0); + return fItemArray[i]; + } + + /** + * equivalent to operator[](0) + */ + T& front() { SkASSERT(fCount > 0); return fItemArray[0];} + + const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];} + + /** + * equivalent to operator[](count() - 1) + */ + T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];} + + const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1];} + + /** + * equivalent to operator[](count()-1-i) + */ + T& fromBack(int i) { + SkASSERT(i >= 0); + SkASSERT(i < fCount); + return fItemArray[fCount - i - 1]; + } + + const T& fromBack(int i) const { + SkASSERT(i >= 0); + SkASSERT(i < fCount); + return fItemArray[fCount - i - 1]; + } + + bool operator==(const SkTArray& right) const { + int leftCount = this->count(); + if (leftCount != right.count()) { + return false; + } + for (int index = 0; index < leftCount; ++index) { + if (fItemArray[index] != right.fItemArray[index]) { + return false; + } + } + return true; + } + + bool operator!=(const SkTArray& right) const { + return !(*this == right); + } + + inline int allocCntForTest() const; + +protected: + /** + * Creates an empty array that will use the passed storage block until it + * is insufficiently large to hold the entire array. + */ + template + SkTArray(SkAlignedSTStorage* storage) { + this->initWithPreallocatedStorage(0, storage->get(), N); + } + + /** + * Copy another array, using preallocated storage if preAllocCount >= + * array.count(). Otherwise storage will only be used when array shrinks + * to fit. + */ + template + SkTArray(const SkTArray& array, SkAlignedSTStorage* storage) { + this->initWithPreallocatedStorage(array.fCount, storage->get(), N); + this->copy(array.fItemArray); + } + + /** + * Move another array, using preallocated storage if preAllocCount >= + * array.count(). Otherwise storage will only be used when array shrinks + * to fit. + */ + template + SkTArray(SkTArray&& array, SkAlignedSTStorage* storage) { + this->initWithPreallocatedStorage(array.fCount, storage->get(), N); + array.move(fMemArray); + array.fCount = 0; + } + + /** + * Copy a C array, using preallocated storage if preAllocCount >= + * count. Otherwise storage will only be used when array shrinks + * to fit. + */ + template + SkTArray(const T* array, int count, SkAlignedSTStorage* storage) { + this->initWithPreallocatedStorage(count, storage->get(), N); + this->copy(array); + } + +private: + void init(int count = 0, int reserveCount = 0) { + SkASSERT(count >= 0); + SkASSERT(reserveCount >= 0); + fCount = count; + if (!count && !reserveCount) { + fAllocCount = 0; + fMemArray = nullptr; + fOwnMemory = true; + fReserved = false; + } else { + fAllocCount = SkTMax(count, SkTMax(kMinHeapAllocCount, reserveCount)); + fMemArray = sk_malloc_throw(fAllocCount, sizeof(T)); + fOwnMemory = true; + fReserved = reserveCount > 0; + } + } + + void initWithPreallocatedStorage(int count, void* preallocStorage, int preallocCount) { + SkASSERT(count >= 0); + SkASSERT(preallocCount > 0); + SkASSERT(preallocStorage); + fCount = count; + fMemArray = nullptr; + fReserved = false; + if (count > preallocCount) { + fAllocCount = SkTMax(count, kMinHeapAllocCount); + fMemArray = sk_malloc_throw(fAllocCount, sizeof(T)); + fOwnMemory = true; + } else { + fAllocCount = preallocCount; + fMemArray = preallocStorage; + fOwnMemory = false; + } + } + + /** In the following move and copy methods, 'dst' is assumed to be uninitialized raw storage. + * In the following move methods, 'src' is destroyed leaving behind uninitialized raw storage. + */ + void copy(const T* src) { + // Some types may be trivially copyable, in which case we *could* use memcopy; but + // MEM_MOVE == true implies that the type is trivially movable, and not necessarily + // trivially copyable (think sk_sp<>). So short of adding another template arg, we + // must be conservative and use copy construction. + for (int i = 0; i < fCount; ++i) { + new (fItemArray + i) T(src[i]); + } + } + + template SK_WHEN(E, void) move(int dst, int src) { + memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T)); + } + template SK_WHEN(E, void) move(void* dst) { + sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T)); + } + + template SK_WHEN(!E, void) move(int dst, int src) { + new (&fItemArray[dst]) T(std::move(fItemArray[src])); + fItemArray[src].~T(); + } + template SK_WHEN(!E, void) move(void* dst) { + for (int i = 0; i < fCount; ++i) { + new (static_cast(dst) + sizeof(T) * i) T(std::move(fItemArray[i])); + fItemArray[i].~T(); + } + } + + static constexpr int kMinHeapAllocCount = 8; + + // Helper function that makes space for n objects, adjusts the count, but does not initialize + // the new objects. + void* push_back_raw(int n) { + this->checkRealloc(n); + void* ptr = fItemArray + fCount; + fCount += n; + return ptr; + } + + void checkRealloc(int delta) { + SkASSERT(fCount >= 0); + SkASSERT(fAllocCount >= 0); + SkASSERT(-delta <= fCount); + + // Move into 64bit math temporarily, to avoid local overflows + int64_t newCount = fCount + delta; + + // We allow fAllocCount to be in the range [newCount, 3*newCount]. We also never shrink + // when we're currently using preallocated memory, would allocate less than + // kMinHeapAllocCount, or a reserve count was specified that has yet to be exceeded. + bool mustGrow = newCount > fAllocCount; + bool shouldShrink = fAllocCount > 3 * newCount && fOwnMemory && !fReserved; + if (!mustGrow && !shouldShrink) { + return; + } + + + // Whether we're growing or shrinking, we leave at least 50% extra space for future growth. + int64_t newAllocCount = newCount + ((newCount + 1) >> 1); + // Align the new allocation count to kMinHeapAllocCount. + static_assert(SkIsPow2(kMinHeapAllocCount), "min alloc count not power of two."); + newAllocCount = (newAllocCount + (kMinHeapAllocCount - 1)) & ~(kMinHeapAllocCount - 1); + // At small sizes the old and new alloc count can both be kMinHeapAllocCount. + if (newAllocCount == fAllocCount) { + return; + } + + fAllocCount = Sk64_pin_to_s32(newAllocCount); + SkASSERT(fAllocCount >= newCount); + void* newMemArray = sk_malloc_throw(fAllocCount, sizeof(T)); + this->move(newMemArray); + if (fOwnMemory) { + sk_free(fMemArray); + + } + fMemArray = newMemArray; + fOwnMemory = true; + fReserved = false; + } + + union { + T* fItemArray; + void* fMemArray; + }; + int fCount; + int fAllocCount; + bool fOwnMemory : 1; + bool fReserved : 1; +}; + +template static inline void swap(SkTArray& a, SkTArray& b) { + a.swap(b); +} + +template constexpr int SkTArray::kMinHeapAllocCount; + +/** + * Subclass of SkTArray that contains a preallocated memory block for the array. + */ +template +class SkSTArray : public SkTArray { +private: + typedef SkTArray INHERITED; + +public: + SkSTArray() : INHERITED(&fStorage) { + } + + SkSTArray(const SkSTArray& array) + : INHERITED(array, &fStorage) { + } + + SkSTArray(SkSTArray&& array) + : INHERITED(std::move(array), &fStorage) { + } + + explicit SkSTArray(const INHERITED& array) + : INHERITED(array, &fStorage) { + } + + explicit SkSTArray(INHERITED&& array) + : INHERITED(std::move(array), &fStorage) { + } + + explicit SkSTArray(int reserveCount) + : INHERITED(reserveCount) { + } + + SkSTArray(const T* array, int count) + : INHERITED(array, count, &fStorage) { + } + + SkSTArray& operator=(const SkSTArray& array) { + INHERITED::operator=(array); + return *this; + } + + SkSTArray& operator=(SkSTArray&& array) { + INHERITED::operator=(std::move(array)); + return *this; + } + + SkSTArray& operator=(const INHERITED& array) { + INHERITED::operator=(array); + return *this; + } + + SkSTArray& operator=(INHERITED&& array) { + INHERITED::operator=(std::move(array)); + return *this; + } + +private: + SkAlignedSTStorage fStorage; +}; + +#endif diff --git a/skia/include/private/SkTDArray.h b/skia/include/private/SkTDArray.h new file mode 100644 index 00000000..008559fc --- /dev/null +++ b/skia/include/private/SkTDArray.h @@ -0,0 +1,372 @@ +/* + * 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 SkTDArray_DEFINED +#define SkTDArray_DEFINED + +#include "SkMalloc.h" +#include "SkTo.h" +#include "SkTypes.h" + +#include +#include + +template class SkTDArray { +public: + SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {} + SkTDArray(const T src[], int count) { + SkASSERT(src || count == 0); + + fReserve = fCount = 0; + fArray = nullptr; + if (count) { + fArray = (T*)sk_malloc_throw(count * sizeof(T)); + memcpy(fArray, src, sizeof(T) * count); + fReserve = fCount = count; + } + } + SkTDArray(const std::initializer_list& list) : SkTDArray(list.begin(), list.size()) {} + SkTDArray(const SkTDArray& src) : fArray(nullptr), fReserve(0), fCount(0) { + SkTDArray tmp(src.fArray, src.fCount); + this->swap(tmp); + } + SkTDArray(SkTDArray&& src) : fArray(nullptr), fReserve(0), fCount(0) { + this->swap(src); + } + ~SkTDArray() { + sk_free(fArray); + } + + SkTDArray& operator=(const SkTDArray& src) { + if (this != &src) { + if (src.fCount > fReserve) { + SkTDArray tmp(src.fArray, src.fCount); + this->swap(tmp); + } else { + sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount); + fCount = src.fCount; + } + } + return *this; + } + SkTDArray& operator=(SkTDArray&& src) { + if (this != &src) { + this->swap(src); + src.reset(); + } + return *this; + } + + friend bool operator==(const SkTDArray& a, const SkTDArray& b) { + return a.fCount == b.fCount && + (a.fCount == 0 || + !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T))); + } + friend bool operator!=(const SkTDArray& a, const SkTDArray& b) { + return !(a == b); + } + + void swap(SkTDArray& that) { + using std::swap; + swap(fArray, that.fArray); + swap(fReserve, that.fReserve); + swap(fCount, that.fCount); + } + + bool isEmpty() const { return fCount == 0; } + bool empty() const { return this->isEmpty(); } + + /** + * Return the number of elements in the array + */ + int count() const { return fCount; } + size_t size() const { return fCount; } + + /** + * Return the total number of elements allocated. + * reserved() - count() gives you the number of elements you can add + * without causing an allocation. + */ + int reserved() const { return fReserve; } + + /** + * return the number of bytes in the array: count * sizeof(T) + */ + size_t bytes() const { return fCount * sizeof(T); } + + T* begin() { return fArray; } + const T* begin() const { return fArray; } + T* end() { return fArray ? fArray + fCount : nullptr; } + const T* end() const { return fArray ? fArray + fCount : nullptr; } + + T& operator[](int index) { + SkASSERT(index < fCount); + return fArray[index]; + } + const T& operator[](int index) const { + SkASSERT(index < fCount); + return fArray[index]; + } + + T& getAt(int index) { + return (*this)[index]; + } + + + void reset() { + if (fArray) { + sk_free(fArray); + fArray = nullptr; + fReserve = fCount = 0; + } else { + SkASSERT(fReserve == 0 && fCount == 0); + } + } + + void rewind() { + // same as setCount(0) + fCount = 0; + } + + /** + * Sets the number of elements in the array. + * If the array does not have space for count elements, it will increase + * the storage allocated to some amount greater than that required. + * It will never shrink the storage. + */ + void setCount(int count) { + SkASSERT(count >= 0); + if (count > fReserve) { + this->resizeStorageToAtLeast(count); + } + fCount = count; + } + + void setReserve(int reserve) { + SkASSERT(reserve >= 0); + if (reserve > fReserve) { + this->resizeStorageToAtLeast(reserve); + } + } + void reserve(size_t n) { + SkASSERT_RELEASE(SkTFitsIn(n)); + this->setReserve(SkToInt(n)); + } + + T* prepend() { + this->adjustCount(1); + memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T)); + return fArray; + } + + T* append() { + return this->append(1, nullptr); + } + T* append(int count, const T* src = nullptr) { + int oldCount = fCount; + if (count) { + SkASSERT(src == nullptr || fArray == nullptr || + src + count <= fArray || fArray + oldCount <= src); + + this->adjustCount(count); + if (src) { + memcpy(fArray + oldCount, src, sizeof(T) * count); + } + } + return fArray + oldCount; + } + + T* insert(int index) { + return this->insert(index, 1, nullptr); + } + T* insert(int index, int count, const T* src = nullptr) { + SkASSERT(count); + SkASSERT(index <= fCount); + size_t oldCount = fCount; + this->adjustCount(count); + T* dst = fArray + index; + memmove(dst + count, dst, sizeof(T) * (oldCount - index)); + if (src) { + memcpy(dst, src, sizeof(T) * count); + } + return dst; + } + + void remove(int index, int count = 1) { + SkASSERT(index + count <= fCount); + fCount = fCount - count; + memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index)); + } + + void removeShuffle(int index) { + SkASSERT(index < fCount); + int newCount = fCount - 1; + fCount = newCount; + if (index != newCount) { + memcpy(fArray + index, fArray + newCount, sizeof(T)); + } + } + + int find(const T& elem) const { + const T* iter = fArray; + const T* stop = fArray + fCount; + + for (; iter < stop; iter++) { + if (*iter == elem) { + return SkToInt(iter - fArray); + } + } + return -1; + } + + int rfind(const T& elem) const { + const T* iter = fArray + fCount; + const T* stop = fArray; + + while (iter > stop) { + if (*--iter == elem) { + return SkToInt(iter - stop); + } + } + return -1; + } + + /** + * Returns true iff the array contains this element. + */ + bool contains(const T& elem) const { + return (this->find(elem) >= 0); + } + + /** + * Copies up to max elements into dst. The number of items copied is + * capped by count - index. The actual number copied is returned. + */ + int copyRange(T* dst, int index, int max) const { + SkASSERT(max >= 0); + SkASSERT(!max || dst); + if (index >= fCount) { + return 0; + } + int count = SkMin32(max, fCount - index); + memcpy(dst, fArray + index, sizeof(T) * count); + return count; + } + + void copy(T* dst) const { + this->copyRange(dst, 0, fCount); + } + + // routines to treat the array like a stack + void push_back(const T& v) { *this->append() = v; } + T* push() { return this->append(); } + const T& top() const { return (*this)[fCount - 1]; } + T& top() { return (*this)[fCount - 1]; } + void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; } + void pop() { SkASSERT(fCount > 0); --fCount; } + + void deleteAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + delete *iter; + iter += 1; + } + this->reset(); + } + + void freeAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + sk_free(*iter); + iter += 1; + } + this->reset(); + } + + void unrefAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + (*iter)->unref(); + iter += 1; + } + this->reset(); + } + + void safeUnrefAll() { + T* iter = fArray; + T* stop = fArray + fCount; + while (iter < stop) { + SkSafeUnref(*iter); + iter += 1; + } + this->reset(); + } + +#ifdef SK_DEBUG + void validate() const { + SkASSERT((fReserve == 0 && fArray == nullptr) || + (fReserve > 0 && fArray != nullptr)); + SkASSERT(fCount <= fReserve); + } +#endif + + void shrinkToFit() { + fReserve = fCount; + fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); + } + +private: + T* fArray; + int fReserve; + int fCount; + + /** + * Adjusts the number of elements in the array. + * This is the same as calling setCount(count() + delta). + */ + void adjustCount(int delta) { + SkASSERT(delta > 0); + + // We take care to avoid overflow here. + // The sum of fCount and delta is at most 4294967294, which fits fine in uint32_t. + uint32_t count = (uint32_t)fCount + (uint32_t)delta; + SkASSERT_RELEASE( SkTFitsIn(count) ); + + this->setCount(SkTo(count)); + } + + /** + * Increase the storage allocation such that it can hold (fCount + extra) + * elements. + * It never shrinks the allocation, and it may increase the allocation by + * more than is strictly required, based on a private growth heuristic. + * + * note: does NOT modify fCount + */ + void resizeStorageToAtLeast(int count) { + SkASSERT(count > fReserve); + + // We take care to avoid overflow here. + // The maximum value we can get for reserve here is 2684354563, which fits in uint32_t. + uint32_t reserve = (uint32_t)count + 4; + reserve += reserve / 4; + SkASSERT_RELEASE( SkTFitsIn(reserve) ); + + fReserve = SkTo(reserve); + fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T)); + } +}; + +template static inline void swap(SkTDArray& a, SkTDArray& b) { + a.swap(b); +} + +#endif diff --git a/skia/include/private/SkTFitsIn.h b/skia/include/private/SkTFitsIn.h new file mode 100644 index 00000000..5fdf7438 --- /dev/null +++ b/skia/include/private/SkTFitsIn.h @@ -0,0 +1,74 @@ +/* + * 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 SkTFitsIn_DEFINED +#define SkTFitsIn_DEFINED + +#include +#include + +/** + * In C++ an unsigned to signed cast where the source value cannot be represented in the destination + * type results in an implementation defined destination value. Unlike C, C++ does not allow a trap. + * This makes "(S)(D)s == s" a possibly useful test. However, there are two cases where this is + * incorrect: + * + * when testing if a value of a smaller signed type can be represented in a larger unsigned type + * (int8_t)(uint16_t)-1 == -1 => (int8_t)0xFFFF == -1 => [implementation defined] == -1 + * + * when testing if a value of a larger unsigned type can be represented in a smaller signed type + * (uint16_t)(int8_t)0xFFFF == 0xFFFF => (uint16_t)-1 == 0xFFFF => 0xFFFF == 0xFFFF => true. + * + * Consider the cases: + * u = unsigned, less digits + * U = unsigned, more digits + * s = signed, less digits + * S = signed, more digits + * v is the value we're considering. + * + * u -> U: (u)(U)v == v, trivially true + * U -> u: (U)(u)v == v, both casts well defined, test works + * s -> S: (s)(S)v == v, trivially true + * S -> s: (S)(s)v == v, first cast implementation value, second cast defined, test works + * s -> U: (s)(U)v == v, *this is bad*, the second cast results in implementation defined value + * S -> u: (S)(u)v == v, the second cast is required to prevent promotion of rhs to unsigned + * u -> S: (u)(S)v == v, trivially true + * U -> s: (U)(s)v == v, *this is bad*, + * first cast results in implementation defined value, + * second cast is defined. However, this creates false positives + * uint16_t x = 0xFFFF + * (uint16_t)(int8_t)x == x + * => (uint16_t)-1 == x + * => 0xFFFF == x + * => true + * + * So for the eight cases three are trivially true, three more are valid casts, and two are special. + * The two 'full' checks which otherwise require two comparisons are valid cast checks. + * The two remaining checks s -> U [v >= 0] and U -> s [v <= max(s)] can be done with one op. + */ + +template +static constexpr inline +typename std::enable_if<(std::is_integral::value || std::is_enum::value) && + (std::is_integral::value || std::is_enum::value), bool>::type +/*bool*/ SkTFitsIn(S src) { + // SkTFitsIn() is used in public headers, so needs to be written targeting at most C++11. + return + + // E.g. (int8_t)(uint8_t) int8_t(-1) == -1, but the uint8_t == 255, not -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(S) <= sizeof(D)) ? + (S)0 <= src : + + // E.g. (uint8_t)(int8_t) uint8_t(255) == 255, but the int8_t == -1. + (std::is_signed::value && std::is_unsigned::value && sizeof(D) <= sizeof(S)) ? + src <= (S)std::numeric_limits::max() : + + // else + (S)(D)src == src; +} + +#endif diff --git a/skia/include/private/SkTHash.h b/skia/include/private/SkTHash.h new file mode 100644 index 00000000..43234c5f --- /dev/null +++ b/skia/include/private/SkTHash.h @@ -0,0 +1,350 @@ +/* + * 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 SkTHash_DEFINED +#define SkTHash_DEFINED + +#include "SkChecksum.h" +#include "SkTypes.h" +#include "SkTemplates.h" +#include + +// Before trying to use SkTHashTable, look below to see if SkTHashMap or SkTHashSet works for you. +// They're easier to use, usually perform the same, and have fewer sharp edges. + +// T and K are treated as ordinary copyable C++ types. +// Traits must have: +// - static K GetKey(T) +// - static uint32_t Hash(K) +// If the key is large and stored inside T, you may want to make K a const&. +// Similarly, if T is large you might want it to be a pointer. +template +class SkTHashTable { +public: + SkTHashTable() : fCount(0), fCapacity(0) {} + SkTHashTable(SkTHashTable&& other) + : fCount(other.fCount) + , fCapacity(other.fCapacity) + , fSlots(std::move(other.fSlots)) { other.fCount = other.fCapacity = 0; } + + SkTHashTable& operator=(SkTHashTable&& other) { + if (this != &other) { + this->~SkTHashTable(); + new (this) SkTHashTable(std::move(other)); + } + return *this; + } + + // Clear the table. + void reset() { *this = SkTHashTable(); } + + // How many entries are in the table? + int count() const { return fCount; } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fCapacity * sizeof(Slot); } + + // !!!!!!!!!!!!!!!!! CAUTION !!!!!!!!!!!!!!!!! + // set(), find() and foreach() all allow mutable access to table entries. + // If you change an entry so that it no longer has the same key, all hell + // will break loose. Do not do that! + // + // Please prefer to use SkTHashMap or SkTHashSet, which do not have this danger. + + // The pointers returned by set() and find() are valid only until the next call to set(). + // The pointers you receive in foreach() are only valid for its duration. + + // Copy val into the hash table, returning a pointer to the copy now in the table. + // If there already is an entry in the table with the same key, we overwrite it. + T* set(T val) { + if (4 * fCount >= 3 * fCapacity) { + this->resize(fCapacity > 0 ? fCapacity * 2 : 4); + } + return this->uncheckedSet(std::move(val)); + } + + // If there is an entry in the table with this key, return a pointer to it. If not, null. + T* find(const K& key) const { + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + if (s.empty()) { + return nullptr; + } + if (hash == s.hash && key == Traits::GetKey(s.val)) { + return &s.val; + } + index = this->next(index); + } + SkASSERT(fCapacity == 0); + return nullptr; + } + + // Remove the value with this key from the hash table. + void remove(const K& key) { + SkASSERT(this->find(key)); + + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + SkASSERT(!s.empty()); + if (hash == s.hash && key == Traits::GetKey(s.val)) { + fCount--; + break; + } + index = this->next(index); + } + + // Rearrange elements to restore the invariants for linear probing. + for (;;) { + Slot& emptySlot = fSlots[index]; + int emptyIndex = index; + int originalIndex; + // Look for an element that can be moved into the empty slot. + // If the empty slot is in between where an element landed, and its native slot, then + // move it to the empty slot. Don't move it if its native slot is in between where + // the element landed and the empty slot. + // [native] <= [empty] < [candidate] == GOOD, can move candidate to empty slot + // [empty] < [native] < [candidate] == BAD, need to leave candidate where it is + do { + index = this->next(index); + Slot& s = fSlots[index]; + if (s.empty()) { + // We're done shuffling elements around. Clear the last empty slot. + emptySlot = Slot(); + return; + } + originalIndex = s.hash & (fCapacity - 1); + } while ((index <= originalIndex && originalIndex < emptyIndex) + || (originalIndex < emptyIndex && emptyIndex < index) + || (emptyIndex < index && index <= originalIndex)); + // Move the element to the empty slot. + Slot& moveFrom = fSlots[index]; + emptySlot = std::move(moveFrom); + } + } + + // Call fn on every entry in the table. You may mutate the entries, but be very careful. + template // f(T*) + void foreach(Fn&& fn) { + for (int i = 0; i < fCapacity; i++) { + if (!fSlots[i].empty()) { + fn(&fSlots[i].val); + } + } + } + + // Call fn on every entry in the table. You may not mutate anything. + template // f(T) or f(const T&) + void foreach(Fn&& fn) const { + for (int i = 0; i < fCapacity; i++) { + if (!fSlots[i].empty()) { + fn(fSlots[i].val); + } + } + } + +private: + T* uncheckedSet(T&& val) { + const K& key = Traits::GetKey(val); + uint32_t hash = Hash(key); + int index = hash & (fCapacity-1); + for (int n = 0; n < fCapacity; n++) { + Slot& s = fSlots[index]; + if (s.empty()) { + // New entry. + s.val = std::move(val); + s.hash = hash; + fCount++; + return &s.val; + } + if (hash == s.hash && key == Traits::GetKey(s.val)) { + // Overwrite previous entry. + // Note: this triggers extra copies when adding the same value repeatedly. + s.val = std::move(val); + return &s.val; + } + + index = this->next(index); + } + SkASSERT(false); + return nullptr; + } + + void resize(int capacity) { + int oldCapacity = fCapacity; + SkDEBUGCODE(int oldCount = fCount); + + fCount = 0; + fCapacity = capacity; + SkAutoTArray oldSlots = std::move(fSlots); + fSlots = SkAutoTArray(capacity); + + for (int i = 0; i < oldCapacity; i++) { + Slot& s = oldSlots[i]; + if (!s.empty()) { + this->uncheckedSet(std::move(s.val)); + } + } + SkASSERT(fCount == oldCount); + } + + int next(int index) const { + index--; + if (index < 0) { index += fCapacity; } + return index; + } + + static uint32_t Hash(const K& key) { + uint32_t hash = Traits::Hash(key); + return hash ? hash : 1; // We reserve hash 0 to mark empty. + } + + struct Slot { + Slot() : hash(0) {} + Slot(T&& v, uint32_t h) : val(std::move(v)), hash(h) {} + Slot(Slot&& o) { *this = std::move(o); } + Slot& operator=(Slot&& o) { + val = std::move(o.val); + hash = o.hash; + return *this; + } + + bool empty() const { return this->hash == 0; } + + T val; + uint32_t hash; + }; + + int fCount, fCapacity; + SkAutoTArray fSlots; + + SkTHashTable(const SkTHashTable&) = delete; + SkTHashTable& operator=(const SkTHashTable&) = delete; +}; + +// Maps K->V. A more user-friendly wrapper around SkTHashTable, suitable for most use cases. +// K and V are treated as ordinary copyable C++ types, with no assumed relationship between the two. +template +class SkTHashMap { +public: + SkTHashMap() {} + SkTHashMap(SkTHashMap&&) = default; + SkTHashMap& operator=(SkTHashMap&&) = default; + + // Clear the map. + void reset() { fTable.reset(); } + + // How many key/value pairs are in the table? + int count() const { return fTable.count(); } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } + + // N.B. The pointers returned by set() and find() are valid only until the next call to set(). + + // Set key to val in the table, replacing any previous value with the same key. + // We copy both key and val, and return a pointer to the value copy now in the table. + V* set(K key, V val) { + Pair* out = fTable.set({std::move(key), std::move(val)}); + return &out->val; + } + + // If there is key/value entry in the table with this key, return a pointer to the value. + // If not, return null. + V* find(const K& key) const { + if (Pair* p = fTable.find(key)) { + return &p->val; + } + return nullptr; + } + + // Remove the key/value entry in the table with this key. + void remove(const K& key) { + SkASSERT(this->find(key)); + fTable.remove(key); + } + + // Call fn on every key/value pair in the table. You may mutate the value but not the key. + template // f(K, V*) or f(const K&, V*) + void foreach(Fn&& fn) { + fTable.foreach([&fn](Pair* p){ fn(p->key, &p->val); }); + } + + // Call fn on every key/value pair in the table. You may not mutate anything. + template // f(K, V), f(const K&, V), f(K, const V&) or f(const K&, const V&). + void foreach(Fn&& fn) const { + fTable.foreach([&fn](const Pair& p){ fn(p.key, p.val); }); + } + +private: + struct Pair { + K key; + V val; + static const K& GetKey(const Pair& p) { return p.key; } + static uint32_t Hash(const K& key) { return HashK()(key); } + }; + + SkTHashTable fTable; + + SkTHashMap(const SkTHashMap&) = delete; + SkTHashMap& operator=(const SkTHashMap&) = delete; +}; + +// A set of T. T is treated as an ordinary copyable C++ type. +template +class SkTHashSet { +public: + SkTHashSet() {} + SkTHashSet(SkTHashSet&&) = default; + SkTHashSet& operator=(SkTHashSet&&) = default; + + // Clear the set. + void reset() { fTable.reset(); } + + // How many items are in the set? + int count() const { return fTable.count(); } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fTable.approxBytesUsed(); } + + // Copy an item into the set. + void add(T item) { fTable.set(std::move(item)); } + + // Is this item in the set? + bool contains(const T& item) const { return SkToBool(this->find(item)); } + + // If an item equal to this is in the set, return a pointer to it, otherwise null. + // This pointer remains valid until the next call to add(). + const T* find(const T& item) const { return fTable.find(item); } + + // Remove the item in the set equal to this. + void remove(const T& item) { + SkASSERT(this->contains(item)); + fTable.remove(item); + } + + // Call fn on every item in the set. You may not mutate anything. + template // f(T), f(const T&) + void foreach (Fn&& fn) const { + fTable.foreach(fn); + } + +private: + struct Traits { + static const T& GetKey(const T& item) { return item; } + static uint32_t Hash(const T& item) { return HashT()(item); } + }; + SkTHashTable fTable; + + SkTHashSet(const SkTHashSet&) = delete; + SkTHashSet& operator=(const SkTHashSet&) = delete; +}; + +#endif//SkTHash_DEFINED diff --git a/skia/include/private/SkTInternalLList.h b/skia/include/private/SkTInternalLList.h new file mode 100644 index 00000000..547befe6 --- /dev/null +++ b/skia/include/private/SkTInternalLList.h @@ -0,0 +1,319 @@ +/* + * 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 SkTInternalLList_DEFINED +#define SkTInternalLList_DEFINED + +#include "../private/SkNoncopyable.h" +#include "SkTypes.h" + +/** + * Helper class to automatically initialize the doubly linked list created pointers. + */ +template class SkPtrWrapper { + public: + SkPtrWrapper() : fPtr(nullptr) {} + SkPtrWrapper& operator =(T* ptr) { fPtr = ptr; return *this; } + operator T*() const { return fPtr; } + T* operator->() { return fPtr; } + private: + T* fPtr; +}; + + +/** + * This macro creates the member variables required by the SkTInternalLList class. It should be + * placed in the private section of any class that will be stored in a double linked list. + */ +#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName) \ + friend class SkTInternalLList; \ + /* back pointer to the owning list - for debugging */ \ + SkDEBUGCODE(SkPtrWrapper > fList;) \ + SkPtrWrapper fPrev; \ + SkPtrWrapper fNext + +/** + * This class implements a templated internal doubly linked list data structure. + */ +template class SkTInternalLList : SkNoncopyable { +public: + SkTInternalLList() + : fHead(nullptr) + , fTail(nullptr) { + } + + void reset() { + fHead = nullptr; + fTail = nullptr; + } + + void remove(T* entry) { + SkASSERT(fHead && fTail); + SkASSERT(this->isInList(entry)); + + T* prev = entry->fPrev; + T* next = entry->fNext; + + if (prev) { + prev->fNext = next; + } else { + fHead = next; + } + if (next) { + next->fPrev = prev; + } else { + fTail = prev; + } + + entry->fPrev = nullptr; + entry->fNext = nullptr; + +#ifdef SK_DEBUG + entry->fList = nullptr; +#endif + } + + void addToHead(T* entry) { + SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); + SkASSERT(nullptr == entry->fList); + + entry->fPrev = nullptr; + entry->fNext = fHead; + if (fHead) { + fHead->fPrev = entry; + } + fHead = entry; + if (nullptr == fTail) { + fTail = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + void addToTail(T* entry) { + SkASSERT(nullptr == entry->fPrev && nullptr == entry->fNext); + SkASSERT(nullptr == entry->fList); + + entry->fPrev = fTail; + entry->fNext = nullptr; + if (fTail) { + fTail->fNext = entry; + } + fTail = entry; + if (nullptr == fHead) { + fHead = entry; + } + +#ifdef SK_DEBUG + entry->fList = this; +#endif + } + + /** + * Inserts a new list entry before an existing list entry. The new entry must not already be + * a member of this or any other list. If existingEntry is NULL then the new entry is added + * at the tail. + */ + void addBefore(T* newEntry, T* existingEntry) { + SkASSERT(newEntry); + + if (nullptr == existingEntry) { + this->addToTail(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fNext = existingEntry; + T* prev = existingEntry->fPrev; + existingEntry->fPrev = newEntry; + newEntry->fPrev = prev; + if (nullptr == prev) { + SkASSERT(fHead == existingEntry); + fHead = newEntry; + } else { + prev->fNext = newEntry; + } +#ifdef SK_DEBUG + newEntry->fList = this; +#endif + } + + /** + * Inserts a new list entry after an existing list entry. The new entry must not already be + * a member of this or any other list. If existingEntry is NULL then the new entry is added + * at the head. + */ + void addAfter(T* newEntry, T* existingEntry) { + SkASSERT(newEntry); + + if (nullptr == existingEntry) { + this->addToHead(newEntry); + return; + } + + SkASSERT(this->isInList(existingEntry)); + newEntry->fPrev = existingEntry; + T* next = existingEntry->fNext; + existingEntry->fNext = newEntry; + newEntry->fNext = next; + if (nullptr == next) { + SkASSERT(fTail == existingEntry); + fTail = newEntry; + } else { + next->fPrev = newEntry; + } +#ifdef SK_DEBUG + newEntry->fList = this; +#endif + } + + void concat(SkTInternalLList&& list) { + if (list.isEmpty()) { + return; + } + + list.fHead->fPrev = fTail; + if (!fHead) { + SkASSERT(!list.fHead->fPrev); + fHead = list.fHead; + } else { + SkASSERT(fTail); + fTail->fNext = list.fHead; + } + fTail = list.fTail; + +#ifdef SK_DEBUG + for (T* node = list.fHead; node; node = node->fNext) { + SkASSERT(node->fList == &list); + node->fList = this; + } +#endif + + list.fHead = list.fTail = nullptr; + } + + bool isEmpty() const { + SkASSERT(SkToBool(fHead) == SkToBool(fTail)); + return !fHead; + } + + T* head() { return fHead; } + T* tail() { return fTail; } + + class Iter { + public: + enum IterStart { + kHead_IterStart, + kTail_IterStart + }; + + Iter() : fCurr(nullptr) {} + Iter(const Iter& iter) : fCurr(iter.fCurr) {} + Iter& operator= (const Iter& iter) { fCurr = iter.fCurr; return *this; } + + T* init(const SkTInternalLList& list, IterStart startLoc) { + if (kHead_IterStart == startLoc) { + fCurr = list.fHead; + } else { + SkASSERT(kTail_IterStart == startLoc); + fCurr = list.fTail; + } + + return fCurr; + } + + T* get() { return fCurr; } + + /** + * Return the next/previous element in the list or NULL if at the end. + */ + T* next() { + if (nullptr == fCurr) { + return nullptr; + } + + fCurr = fCurr->fNext; + return fCurr; + } + + T* prev() { + if (nullptr == fCurr) { + return nullptr; + } + + fCurr = fCurr->fPrev; + return fCurr; + } + + /** + * C++11 range-for interface. + */ + bool operator!=(const Iter& that) { return fCurr != that.fCurr; } + T* operator*() { return this->get(); } + void operator++() { this->next(); } + + private: + T* fCurr; + }; + + Iter begin() const { + Iter iter; + iter.init(*this, Iter::kHead_IterStart); + return iter; + } + + Iter end() const { return Iter(); } + +#ifdef SK_DEBUG + void validate() const { + SkASSERT(!fHead == !fTail); + Iter iter; + for (T* item = iter.init(*this, Iter::kHead_IterStart); item; item = iter.next()) { + SkASSERT(this->isInList(item)); + if (nullptr == item->fPrev) { + SkASSERT(fHead == item); + } else { + SkASSERT(item->fPrev->fNext == item); + } + if (nullptr == item->fNext) { + SkASSERT(fTail == item); + } else { + SkASSERT(item->fNext->fPrev == item); + } + } + } + + /** + * Debugging-only method that uses the list back pointer to check if 'entry' is indeed in 'this' + * list. + */ + bool isInList(const T* entry) const { + return entry->fList == this; + } + + /** + * Debugging-only method that laboriously counts the list entries. + */ + int countEntries() const { + int count = 0; + for (T* entry = fHead; entry; entry = entry->fNext) { + ++count; + } + return count; + } +#endif // SK_DEBUG + +private: + T* fHead; + T* fTail; + + typedef SkNoncopyable INHERITED; +}; + +#endif diff --git a/skia/include/private/SkTLogic.h b/skia/include/private/SkTLogic.h new file mode 100644 index 00000000..9648f923 --- /dev/null +++ b/skia/include/private/SkTLogic.h @@ -0,0 +1,126 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * + * This header provides some of the helpers (like std::enable_if_t) which will + * become available with C++14 in the type_traits header (in the skstd + * namespace). This header also provides several Skia specific additions such + * as SK_WHEN and the sknonstd namespace. + */ + +#ifndef SkTLogic_DEFINED +#define SkTLogic_DEFINED + +#include +#include +#include +#include +#include + +namespace skstd { + +template using bool_constant = std::integral_constant; + +template using conditional_t = typename std::conditional::type; +template using enable_if_t = typename std::enable_if::type; + +template using remove_const_t = typename std::remove_const::type; +template using remove_volatile_t = typename std::remove_volatile::type; +template using remove_cv_t = typename std::remove_cv::type; +template using remove_pointer_t = typename std::remove_pointer::type; +template using remove_reference_t = typename std::remove_reference::type; +template using remove_extent_t = typename std::remove_extent::type; + +template using add_const_t = typename std::add_const::type; +template using add_volatile_t = typename std::add_volatile::type; +template using add_cv_t = typename std::add_cv::type; +template using add_pointer_t = typename std::add_pointer::type; +template using add_lvalue_reference_t = typename std::add_lvalue_reference::type; + +template using result_of_t = typename std::result_of::type; + +template using common_type_t = typename std::common_type::type; + +// Chromium currently requires gcc 4.8.2 or a recent clang compiler, but uses libstdc++4.6.4. +// Note that Precise actually uses libstdc++4.6.3. +// Unfortunately, libstdc++ STL before libstdc++4.7 do not define std::underlying_type. +// Newer gcc and clang compilers have __underlying_type which does not depend on runtime support. +// See https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html for __GLIBCXX__ values. +// Unfortunately __GLIBCXX__ is a date, but no updates to versions before 4.7 are now anticipated. +#define SK_GLIBCXX_4_7_0 20120322 +// Updates to versions before 4.7 but released after 4.7 was released. +#define SK_GLIBCXX_4_5_4 20120702 +#define SK_GLIBCXX_4_6_4 20121127 +#if defined(__GLIBCXX__) && (__GLIBCXX__ < SK_GLIBCXX_4_7_0 || \ + __GLIBCXX__ == SK_GLIBCXX_4_5_4 || \ + __GLIBCXX__ == SK_GLIBCXX_4_6_4) +template struct underlying_type { + using type = __underlying_type(T); +}; +#else +template using underlying_type = std::underlying_type; +#endif +template using underlying_type_t = typename skstd::underlying_type::type; + + +template struct index_sequence { + using type = index_sequence; + using value_type = size_t; + static constexpr std::size_t size() noexcept { return sizeof...(Ints); } +}; + +template struct make_index_sequence_combine; +template +struct make_index_sequence_combine, skstd::index_sequence> + : skstd::index_sequence +{ }; + +template struct make_index_sequence + : make_index_sequence_combine::type, + typename skstd::make_index_sequence::type>{}; +template<> struct make_index_sequence<0> : skstd::index_sequence< >{}; +template<> struct make_index_sequence<1> : skstd::index_sequence<0>{}; + +} // namespace skstd + +// The sknonstd namespace contains things we would like to be proposed and feel std-ish. +namespace sknonstd { + +// The name 'copy' here is fraught with peril. In this case it means 'append', not 'overwrite'. +// Alternate proposed names are 'propagate', 'augment', or 'append' (and 'add', but already taken). +// std::experimental::propagate_const already exists for other purposes in TSv2. +// These also follow the pattern used by boost. +template struct copy_const { + using type = skstd::conditional_t::value, skstd::add_const_t, D>; +}; +template using copy_const_t = typename copy_const::type; + +template struct copy_volatile { + using type = skstd::conditional_t::value, skstd::add_volatile_t, D>; +}; +template using copy_volatile_t = typename copy_volatile::type; + +template struct copy_cv { + using type = copy_volatile_t, S>; +}; +template using copy_cv_t = typename copy_cv::type; + +// The name 'same' here means 'overwrite'. +// Alternate proposed names are 'replace', 'transfer', or 'qualify_from'. +// same_xxx can be written as copy_xxx, S> +template using same_const = copy_const, S>; +template using same_const_t = typename same_const::type; +template using same_volatile =copy_volatile,S>; +template using same_volatile_t = typename same_volatile::type; +template using same_cv = copy_cv, S>; +template using same_cv_t = typename same_cv::type; + +} // namespace sknonstd + +// Just a pithier wrapper for enable_if_t. +#define SK_WHEN(condition, T) skstd::enable_if_t + +#endif diff --git a/skia/include/private/SkTSearch.h b/skia/include/private/SkTSearch.h new file mode 100644 index 00000000..16ef0d69 --- /dev/null +++ b/skia/include/private/SkTSearch.h @@ -0,0 +1,146 @@ + +/* + * 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 SkTSearch_DEFINED +#define SkTSearch_DEFINED + +#include "SkTypes.h" + +/** + * All of the SkTSearch variants want to return the index (0...N-1) of the + * found element, or the bit-not of where to insert the element. + * + * At a simple level, if the return value is negative, it was not found. + * + * For clients that want to insert the new element if it was not found, use + * the following logic: + * + * int index = SkTSearch(...); + * if (index >= 0) { + * // found at index + * } else { + * index = ~index; // now we are positive + * // insert at index + * } + */ + + +// The most general form of SkTSearch takes an array of T and a key of type K. A functor, less, is +// used to perform comparisons. It has two function operators: +// bool operator() (const T& t, const K& k) +// bool operator() (const K& t, const T& k) +template +int SkTSearch(const T base[], int count, const K& key, size_t elemSize, LESS& less) +{ + SkASSERT(count >= 0); + if (count <= 0) { + return ~0; + } + + SkASSERT(base != nullptr); // base may be nullptr if count is zero + + int lo = 0; + int hi = count - 1; + + while (lo < hi) { + int mid = lo + ((hi - lo) >> 1); + const T* elem = (const T*)((const char*)base + mid * elemSize); + + if (less(*elem, key)) + lo = mid + 1; + else + hi = mid; + } + + const T* elem = (const T*)((const char*)base + hi * elemSize); + if (less(*elem, key)) { + hi += 1; + hi = ~hi; + } else if (less(key, *elem)) { + hi = ~hi; + } + return hi; +} + +// Adapts a less-than function to a functor. +template struct SkTLessFunctionToFunctorAdaptor { + bool operator()(const T& a, const T& b) { return LESS(a, b); } +}; + +// Specialization for case when T==K and the caller wants to use a function rather than functor. +template +int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { + static SkTLessFunctionToFunctorAdaptor functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +// Adapts operator < to a functor. +template struct SkTLessFunctor { + bool operator()(const T& a, const T& b) { return a < b; } +}; + +// Specialization for T==K, compare using op <. +template +int SkTSearch(const T base[], int count, const T& target, size_t elemSize) { + static SkTLessFunctor functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +// Similar to SkLessFunctionToFunctorAdaptor but makes the functor interface take T* rather than T. +template struct SkTLessFunctionToPtrFunctorAdaptor { + bool operator() (const T* t, const T* k) { return LESS(*t, *k); } +}; + +// Specialization for case where domain is an array of T* and the key value is a T*, and you want +// to compare the T objects, not the pointers. +template +int SkTSearch(T* base[], int count, T* target, size_t elemSize) { + static SkTLessFunctionToPtrFunctorAdaptor functor; + return SkTSearch(base, count, target, elemSize, functor); +} + +int SkStrSearch(const char*const* base, int count, const char target[], + size_t target_len, size_t elemSize); +int SkStrSearch(const char*const* base, int count, const char target[], + size_t elemSize); + +/** Like SkStrSearch, but treats target as if it were all lower-case. Assumes that + base points to a table of lower-case strings. +*/ +int SkStrLCSearch(const char*const* base, int count, const char target[], + size_t target_len, size_t elemSize); +int SkStrLCSearch(const char*const* base, int count, const char target[], + size_t elemSize); + +/** Helper class to convert a string to lower-case, but only modifying the ascii + characters. This makes the routine very fast and never changes the string + length, but it is not suitable for linguistic purposes. Normally this is + used for buiding and searching string tables. +*/ +class SkAutoAsciiToLC { +public: + SkAutoAsciiToLC(const char str[], size_t len = (size_t)-1); + ~SkAutoAsciiToLC(); + + const char* lc() const { return fLC; } + size_t length() const { return fLength; } + +private: + char* fLC; // points to either the heap or fStorage + size_t fLength; + enum { + STORAGE = 64 + }; + char fStorage[STORAGE+1]; +}; + +// Helper when calling qsort with a compare proc that has typed its arguments +#define SkCastForQSort(compare) reinterpret_cast(compare) + +#endif diff --git a/skia/include/private/SkTemplates.h b/skia/include/private/SkTemplates.h new file mode 100644 index 00000000..567753a9 --- /dev/null +++ b/skia/include/private/SkTemplates.h @@ -0,0 +1,449 @@ + +/* + * 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 SkTemplates_DEFINED +#define SkTemplates_DEFINED + +#include "SkMath.h" +#include "SkMalloc.h" +#include "SkTLogic.h" +#include "SkTypes.h" +#include +#include +#include + +/** \file SkTemplates.h + + This file contains light-weight template classes for type-safe and exception-safe + resource management. +*/ + +/** + * Marks a local variable as known to be unused (to avoid warnings). + * Note that this does *not* prevent the local variable from being optimized away. + */ +template inline void sk_ignore_unused_variable(const T&) { } + +/** + * Returns a pointer to a D which comes immediately after S[count]. + */ +template static D* SkTAfter(S* ptr, size_t count = 1) { + return reinterpret_cast(ptr + count); +} + +/** + * Returns a pointer to a D which comes byteOffset bytes after S. + */ +template static D* SkTAddOffset(S* ptr, size_t byteOffset) { + // The intermediate char* has the same cv-ness as D as this produces better error messages. + // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. + return reinterpret_cast(reinterpret_cast*>(ptr) + byteOffset); +} + +template struct SkFunctionWrapper { + R operator()(T* t) { return P(t); } +}; + +/** \class SkAutoTCallVProc + + Call a function when this goes out of scope. The template uses two + parameters, the object, and a function that is to be called in the destructor. + If release() is called, the object reference is set to null. If the object + reference is null when the destructor is called, we do not call the + function. +*/ +template class SkAutoTCallVProc + : public std::unique_ptr> { +public: + SkAutoTCallVProc(T* obj): std::unique_ptr>(obj) {} + + operator T*() const { return this->get(); } +}; + +/** Allocate an array of T elements, and free the array in the destructor + */ +template class SkAutoTArray { +public: + SkAutoTArray() {} + /** Allocate count number of T elements + */ + explicit SkAutoTArray(int count) { + SkASSERT(count >= 0); + if (count) { + fArray.reset(new T[count]); + } + SkDEBUGCODE(fCount = count;) + } + + SkAutoTArray(SkAutoTArray&& other) : fArray(std::move(other.fArray)) { + SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;) + } + SkAutoTArray& operator=(SkAutoTArray&& other) { + if (this != &other) { + fArray = std::move(other.fArray); + SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;) + } + return *this; + } + + /** Reallocates given a new count. Reallocation occurs even if new count equals old count. + */ + void reset(int count) { *this = SkAutoTArray(count); } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray.get(); } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT((unsigned)index < (unsigned)fCount); + return fArray[index]; + } + +private: + std::unique_ptr fArray; + SkDEBUGCODE(int fCount = 0;) +}; + +/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated. + */ +template class SkAutoSTArray { +public: + SkAutoSTArray(SkAutoSTArray&&) = delete; + SkAutoSTArray(const SkAutoSTArray&) = delete; + SkAutoSTArray& operator=(SkAutoSTArray&&) = delete; + SkAutoSTArray& operator=(const SkAutoSTArray&) = delete; + + /** Initialize with no objects */ + SkAutoSTArray() { + fArray = nullptr; + fCount = 0; + } + + /** Allocate count number of T elements + */ + SkAutoSTArray(int count) { + fArray = nullptr; + fCount = 0; + this->reset(count); + } + + ~SkAutoSTArray() { + this->reset(0); + } + + /** Destroys previous objects in the array and default constructs count number of objects */ + void reset(int count) { + T* start = fArray; + T* iter = start + fCount; + while (iter > start) { + (--iter)->~T(); + } + + SkASSERT(count >= 0); + if (fCount != count) { + if (fCount > kCount) { + // 'fArray' was allocated last time so free it now + SkASSERT((T*) fStorage != fArray); + sk_free(fArray); + } + + if (count > kCount) { + fArray = (T*) sk_malloc_throw(count, sizeof(T)); + } else if (count > 0) { + fArray = (T*) fStorage; + } else { + fArray = nullptr; + } + + fCount = count; + } + + iter = fArray; + T* stop = fArray + count; + while (iter < stop) { + new (iter++) T; + } + } + + /** Return the number of T elements in the array + */ + int count() const { return fCount; } + + /** Return the array of T elements. Will be NULL if count == 0 + */ + T* get() const { return fArray; } + + T* begin() { return fArray; } + + const T* begin() const { return fArray; } + + T* end() { return fArray + fCount; } + + const T* end() const { return fArray + fCount; } + + /** Return the nth element in the array + */ + T& operator[](int index) const { + SkASSERT(index < fCount); + return fArray[index]; + } + +private: +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const int kMaxBytes = 4 * 1024; + static const int kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountRequested; +#else + static const int kCount = kCountRequested; +#endif + + int fCount; + T* fArray; + // since we come right after fArray, fStorage should be properly aligned + char fStorage[kCount * sizeof(T)]; +}; + +/** Manages an array of T elements, freeing the array in the destructor. + * Does NOT call any constructors/destructors on T (T must be POD). + */ +template class SkAutoTMalloc { +public: + /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ + explicit SkAutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {} + + /** Allocates space for 'count' Ts. */ + explicit SkAutoTMalloc(size_t count) + : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {} + + SkAutoTMalloc(SkAutoTMalloc&&) = default; + SkAutoTMalloc& operator=(SkAutoTMalloc&&) = default; + + /** Resize the memory area pointed to by the current ptr preserving contents. */ + void realloc(size_t count) { + fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr); + } + + /** Resize the memory area pointed to by the current ptr without preserving contents. */ + T* reset(size_t count = 0) { + fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr); + return this->get(); + } + + T* get() const { return fPtr.get(); } + + operator T*() { return fPtr.get(); } + + operator const T*() const { return fPtr.get(); } + + T& operator[](int index) { return fPtr.get()[index]; } + + const T& operator[](int index) const { return fPtr.get()[index]; } + + /** + * Transfer ownership of the ptr to the caller, setting the internal + * pointer to NULL. Note that this differs from get(), which also returns + * the pointer, but it does not transfer ownership. + */ + T* release() { return fPtr.release(); } + +private: + std::unique_ptr> fPtr; +}; + +template class SkAutoSTMalloc { +public: + SkAutoSTMalloc() : fPtr(fTStorage) {} + + SkAutoSTMalloc(size_t count) { + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + } + + SkAutoSTMalloc(SkAutoSTMalloc&&) = delete; + SkAutoSTMalloc(const SkAutoSTMalloc&) = delete; + SkAutoSTMalloc& operator=(SkAutoSTMalloc&&) = delete; + SkAutoSTMalloc& operator=(const SkAutoSTMalloc&) = delete; + + ~SkAutoSTMalloc() { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + } + + // doesn't preserve contents + T* reset(size_t count) { + if (fPtr != fTStorage) { + sk_free(fPtr); + } + if (count > kCount) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + } else if (count) { + fPtr = fTStorage; + } else { + fPtr = nullptr; + } + return fPtr; + } + + T* get() const { return fPtr; } + + operator T*() { + return fPtr; + } + + operator const T*() const { + return fPtr; + } + + T& operator[](int index) { + return fPtr[index]; + } + + const T& operator[](int index) const { + return fPtr[index]; + } + + // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent + void realloc(size_t count) { + if (count > kCount) { + if (fPtr == fTStorage) { + fPtr = (T*)sk_malloc_throw(count, sizeof(T)); + memcpy(fPtr, fTStorage, kCount * sizeof(T)); + } else { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else if (count) { + if (fPtr != fTStorage) { + fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T)); + } + } else { + this->reset(0); + } + } + +private: + // Since we use uint32_t storage, we might be able to get more elements for free. + static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T); +#if defined(SK_BUILD_FOR_GOOGLE3) + // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions + // have multiple large stack allocations. + static const size_t kMaxBytes = 4 * 1024; + static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes + ? kMaxBytes / sizeof(T) + : kCountWithPadding; +#else + static const size_t kCount = kCountWithPadding; +#endif + + T* fPtr; + union { + uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2]; + T fTStorage[1]; // do NOT want to invoke T::T() + }; +}; + +////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will + * safely destroy (and free if it was dynamically allocated) the object. + */ +template void SkInPlaceDeleteCheck(T* obj, void* storage) { + if (storage == obj) { + obj->~T(); + } else { + delete obj; + } +} + +/** + * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if + * storage is not large enough. + * + * obj = SkInPlaceNewCheck(storage, size); + * ... + * SkInPlaceDeleteCheck(obj, storage); + */ +template +T* SkInPlaceNewCheck(void* storage, size_t size, Args&&... args) { + return (sizeof(T) <= size) ? new (storage) T(std::forward(args)...) + : new T(std::forward(args)...); +} +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. + */ +template class SkAlignedSStorage { +public: + SkAlignedSStorage() {} + SkAlignedSStorage(SkAlignedSStorage&&) = delete; + SkAlignedSStorage(const SkAlignedSStorage&) = delete; + SkAlignedSStorage& operator=(SkAlignedSStorage&&) = delete; + SkAlignedSStorage& operator=(const SkAlignedSStorage&) = delete; + + size_t size() const { return N; } + void* get() { return fData; } + const void* get() const { return fData; } + +private: + union { + void* fPtr; + double fDouble; + char fData[N]; + }; +}; + +/** + * Reserves memory that is aligned on double and pointer boundaries. + * Hopefully this is sufficient for all practical purposes. Otherwise, + * we have to do some arcane trickery to determine alignment of non-POD + * types. Lifetime of the memory is the lifetime of the object. + */ +template class SkAlignedSTStorage { +public: + SkAlignedSTStorage() {} + SkAlignedSTStorage(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage(const SkAlignedSTStorage&) = delete; + SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete; + SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete; + + /** + * Returns void* because this object does not initialize the + * memory. Use placement new for types that require a cons. + */ + void* get() { return fStorage.get(); } + const void* get() const { return fStorage.get(); } +private: + SkAlignedSStorage fStorage; +}; + +using SkAutoFree = std::unique_ptr>; + +template +constexpr auto SkMakeArrayFromIndexSequence(C c, skstd::index_sequence) +-> std::array, sizeof...(Is)> { + return {{ c(Is)... }}; +} + +template constexpr auto SkMakeArray(C c) +-> std::array, N> { + return SkMakeArrayFromIndexSequence(c, skstd::make_index_sequence{}); +} + +#endif diff --git a/skia/include/private/SkThreadID.h b/skia/include/private/SkThreadID.h new file mode 100644 index 00000000..a210a929 --- /dev/null +++ b/skia/include/private/SkThreadID.h @@ -0,0 +1,19 @@ +/* + * 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 SkThreadID_DEFINED +#define SkThreadID_DEFINED + +#include "SkTypes.h" + +typedef int64_t SkThreadID; + +SkThreadID SkGetThreadID(); + +const SkThreadID kIllegalThreadID = 0; + +#endif // SkThreadID_DEFINED diff --git a/skia/include/private/SkTo.h b/skia/include/private/SkTo.h new file mode 100644 index 00000000..9b5b7fd1 --- /dev/null +++ b/skia/include/private/SkTo.h @@ -0,0 +1,28 @@ +/* + * 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 SkTo_DEFINED +#define SkTo_DEFINED + +#include "SkTypes.h" +#include "SkTFitsIn.h" + +template constexpr D SkTo(S s) { + return SkASSERT(SkTFitsIn(s)), + static_cast(s); +} + +template constexpr int8_t SkToS8(S x) { return SkTo(x); } +template constexpr uint8_t SkToU8(S x) { return SkTo(x); } +template constexpr int16_t SkToS16(S x) { return SkTo(x); } +template constexpr uint16_t SkToU16(S x) { return SkTo(x); } +template constexpr int32_t SkToS32(S x) { return SkTo(x); } +template constexpr uint32_t SkToU32(S x) { return SkTo(x); } +template constexpr int SkToInt(S x) { return SkTo(x); } +template constexpr unsigned SkToUInt(S x) { return SkTo(x); } +template constexpr size_t SkToSizeT(S x) { return SkTo(x); } + +#endif // SkTo_DEFINED diff --git a/skia/include/private/SkWeakRefCnt.h b/skia/include/private/SkWeakRefCnt.h new file mode 100644 index 00000000..bbc0cb61 --- /dev/null +++ b/skia/include/private/SkWeakRefCnt.h @@ -0,0 +1,170 @@ +/* + * 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 SkWeakRefCnt_DEFINED +#define SkWeakRefCnt_DEFINED + +#include "SkRefCnt.h" +#include + +/** \class SkWeakRefCnt + + SkWeakRefCnt is the base class for objects that may be shared by multiple + objects. When an existing strong owner wants to share a reference, it calls + ref(). When a strong owner wants to release its reference, it calls + unref(). When the shared object's strong reference count goes to zero as + the result of an unref() call, its (virtual) weak_dispose method is called. + It is an error for the destructor to be called explicitly (or via the + object going out of scope on the stack or calling delete) if + getRefCnt() > 1. + + In addition to strong ownership, an owner may instead obtain a weak + reference by calling weak_ref(). A call to weak_ref() must be balanced by a + call to weak_unref(). To obtain a strong reference from a weak reference, + call try_ref(). If try_ref() returns true, the owner's pointer is now also + a strong reference on which unref() must be called. Note that this does not + affect the original weak reference, weak_unref() must still be called. When + the weak reference count goes to zero, the object is deleted. While the + weak reference count is positive and the strong reference count is zero the + object still exists, but will be in the disposed state. It is up to the + object to define what this means. + + Note that a strong reference implicitly implies a weak reference. As a + result, it is allowable for the owner of a strong ref to call try_ref(). + This will have the same effect as calling ref(), but may be more expensive. + + Example: + + SkWeakRefCnt myRef = strongRef.weak_ref(); + ... // strongRef.unref() may or may not be called + if (myRef.try_ref()) { + ... // use myRef + myRef.unref(); + } else { + // myRef is in the disposed state + } + myRef.weak_unref(); +*/ +class SK_API SkWeakRefCnt : public SkRefCnt { +public: + /** Default construct, initializing the reference counts to 1. + The strong references collectively hold one weak reference. When the + strong reference count goes to zero, the collectively held weak + reference is released. + */ + SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} + + /** Destruct, asserting that the weak reference count is 1. + */ + ~SkWeakRefCnt() override { +#ifdef SK_DEBUG + SkASSERT(getWeakCnt() == 1); + fWeakCnt.store(0, std::memory_order_relaxed); +#endif + } + +#ifdef SK_DEBUG + /** Return the weak reference count. */ + int32_t getWeakCnt() const { + return fWeakCnt.load(std::memory_order_relaxed); + } +#endif + +private: + /** If fRefCnt is 0, returns 0. + * Otherwise increments fRefCnt, acquires, and returns the old value. + */ + int32_t atomic_conditional_acquire_strong_ref() const { + int32_t prev = fRefCnt.load(std::memory_order_relaxed); + do { + if (0 == prev) { + break; + } + } while(!fRefCnt.compare_exchange_weak(prev, prev+1, std::memory_order_acquire, + std::memory_order_relaxed)); + return prev; + } + +public: + /** Creates a strong reference from a weak reference, if possible. The + caller must already be an owner. If try_ref() returns true the owner + is in posession of an additional strong reference. Both the original + reference and new reference must be properly unreferenced. If try_ref() + returns false, no strong reference could be created and the owner's + reference is in the same state as before the call. + */ + bool SK_WARN_UNUSED_RESULT try_ref() const { + if (atomic_conditional_acquire_strong_ref() != 0) { + // Acquire barrier (L/SL), if not provided above. + // Prevents subsequent code from happening before the increment. + return true; + } + return false; + } + + /** Increment the weak reference count. Must be balanced by a call to + weak_unref(). + */ + void weak_ref() const { + SkASSERT(getRefCnt() > 0); + SkASSERT(getWeakCnt() > 0); + // No barrier required. + (void)fWeakCnt.fetch_add(+1, std::memory_order_relaxed); + } + + /** Decrement the weak reference count. If the weak reference count is 1 + before the decrement, then call delete on the object. Note that if this + is the case, then the object needs to have been allocated via new, and + not on the stack. + */ + void weak_unref() const { + SkASSERT(getWeakCnt() > 0); + // A release here acts in place of all releases we "should" have been doing in ref(). + if (1 == fWeakCnt.fetch_add(-1, std::memory_order_acq_rel)) { + // Like try_ref(), the acquire is only needed on success, to make sure + // code in internal_dispose() doesn't happen before the decrement. +#ifdef SK_DEBUG + // so our destructor won't complain + fWeakCnt.store(1, std::memory_order_relaxed); +#endif + this->INHERITED::internal_dispose(); + } + } + + /** Returns true if there are no strong references to the object. When this + is the case all future calls to try_ref() will return false. + */ + bool weak_expired() const { + return fRefCnt.load(std::memory_order_relaxed) == 0; + } + +protected: + /** Called when the strong reference count goes to zero. This allows the + object to free any resources it may be holding. Weak references may + still exist and their level of allowed access to the object is defined + by the object's class. + */ + virtual void weak_dispose() const { + } + +private: + /** Called when the strong reference count goes to zero. Calls weak_dispose + on the object and releases the implicit weak reference held + collectively by the strong references. + */ + void internal_dispose() const override { + weak_dispose(); + weak_unref(); + } + + /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ + mutable std::atomic fWeakCnt; + + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/skia/include/svg/SkSVGCanvas.h b/skia/include/svg/SkSVGCanvas.h new file mode 100644 index 00000000..1cc091a5 --- /dev/null +++ b/skia/include/svg/SkSVGCanvas.h @@ -0,0 +1,35 @@ +/* + * 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 SkSVGCanvas_DEFINED +#define SkSVGCanvas_DEFINED + +#include "SkCanvas.h" + +class SkWStream; +class SkXMLWriter; + +class SK_API SkSVGCanvas { +public: + /** + * Returns a new canvas that will generate SVG commands from its draw calls, and send + * them to the provided xmlwriter. Ownership of the xmlwriter is not transfered to the canvas, + * but it must stay valid during the lifetime of the returned canvas. + * + * The canvas may buffer some drawing calls, so the output is not guaranteed to be valid + * or complete until the canvas instance is deleted. + * + * The 'bounds' parameter defines an initial SVG viewport (viewBox attribute on the root + * SVG element). + */ + static std::unique_ptr Make(const SkRect& bounds, SkWStream*); + + // Internal only. + static std::unique_ptr Make(const SkRect& bounds, SkXMLWriter*); +}; + +#endif diff --git a/skia/include/utils/Sk3D.h b/skia/include/utils/Sk3D.h new file mode 100644 index 00000000..f1828118 --- /dev/null +++ b/skia/include/utils/Sk3D.h @@ -0,0 +1,19 @@ +/* + * 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 Sk3D_DEFINED +#define Sk3D_DEFINED + +#include "SkPoint3.h" +#include "SkMatrix44.h" + +SK_API void Sk3LookAt(SkMatrix44* dst, const SkPoint3& eye, const SkPoint3& center, const SkPoint3& up); +SK_API bool Sk3Perspective(SkMatrix44* dst, float near, float far, float angle); +SK_API void Sk3MapPts(SkPoint dst[], const SkMatrix44& m4, const SkPoint3 src[], int count); + +#endif + diff --git a/skia/include/utils/SkAnimCodecPlayer.h b/skia/include/utils/SkAnimCodecPlayer.h new file mode 100644 index 00000000..4b885569 --- /dev/null +++ b/skia/include/utils/SkAnimCodecPlayer.h @@ -0,0 +1,60 @@ +/* + * 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 SkAnimCodecPlayer_DEFINED +#define SkAnimCodecPlayer_DEFINED + +#include "SkCodec.h" + +class SkImage; + +class SkAnimCodecPlayer { +public: + SkAnimCodecPlayer(std::unique_ptr codec); + ~SkAnimCodecPlayer(); + + /** + * Returns the current frame of the animation. This defaults to the first frame for + * animated codecs (i.e. msec = 0). Calling this multiple times (without calling seek()) + * will always return the same image object (or null if there was an error). + */ + sk_sp getFrame(); + + /** + * Return the size of the image(s) that will be returned by getFrame(). + */ + SkISize dimensions(); + + /** + * Returns the total duration of the animation in milliseconds. Returns 0 for a single-frame + * image. + */ + uint32_t duration() { return fTotalDuration; } + + /** + * Finds the closest frame associated with the time code (in milliseconds) and sets that + * to be the current frame (call getFrame() to retrieve that image). + * Returns true iff this call to seek() changed the "current frame" for the animation. + * Thus if seek() returns false, then getFrame() will return the same image as it did + * before this call to seek(). + */ + bool seek(uint32_t msec); + + +private: + std::unique_ptr fCodec; + SkImageInfo fImageInfo; + std::vector fFrameInfos; + std::vector > fImages; + int fCurrIndex = 0; + uint32_t fTotalDuration; + + sk_sp getFrameAt(int index); +}; + +#endif + diff --git a/skia/include/utils/SkBase64.h b/skia/include/utils/SkBase64.h new file mode 100644 index 00000000..13350b7b --- /dev/null +++ b/skia/include/utils/SkBase64.h @@ -0,0 +1,39 @@ +/* + * 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 SkBase64_DEFINED +#define SkBase64_DEFINED + +#include "SkTypes.h" + +struct SkBase64 { +public: + enum Error { + kNoError, + kPadError, + kBadCharError + }; + + SkBase64(); + Error decode(const char* src, size_t length); + char* getData() { return fData; } + /** + Base64 encodes src into dst. encode is a pointer to at least 65 chars. + encode[64] will be used as the pad character. Encodings other than the + default encoding cannot be decoded. + */ + static size_t Encode(const void* src, size_t length, void* dest, const char* encode = nullptr); + +private: + Error decode(const void* srcPtr, size_t length, bool writeDestination); + + size_t fLength; + char* fData; + friend class SkImageBaseBitmap; +}; + +#endif // SkBase64_DEFINED diff --git a/skia/include/utils/SkCamera.h b/skia/include/utils/SkCamera.h new file mode 100644 index 00000000..26848c50 --- /dev/null +++ b/skia/include/utils/SkCamera.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +// Inspired by Rob Johnson's most excellent QuickDraw GX sample code + +#ifndef SkCamera_DEFINED +#define SkCamera_DEFINED + +#include "../private/SkNoncopyable.h" +#include "SkMatrix.h" + +class SkCanvas; + +struct SkUnit3D { + SkScalar fX, fY, fZ; + + void set(SkScalar x, SkScalar y, SkScalar z) { + fX = x; fY = y; fZ = z; + } + static SkScalar Dot(const SkUnit3D&, const SkUnit3D&); + static void Cross(const SkUnit3D&, const SkUnit3D&, SkUnit3D* cross); +}; + +struct SkPoint3D { + SkScalar fX, fY, fZ; + + void set(SkScalar x, SkScalar y, SkScalar z) { + fX = x; fY = y; fZ = z; + } + SkScalar normalize(SkUnit3D*) const; +}; +typedef SkPoint3D SkVector3D; + +struct SkMatrix3D { + SkScalar fMat[3][4]; + + void reset(); + + void setRow(int row, SkScalar a, SkScalar b, SkScalar c, SkScalar d = 0) { + SkASSERT((unsigned)row < 3); + fMat[row][0] = a; + fMat[row][1] = b; + fMat[row][2] = c; + fMat[row][3] = d; + } + + void setRotateX(SkScalar deg); + void setRotateY(SkScalar deg); + void setRotateZ(SkScalar deg); + void setTranslate(SkScalar x, SkScalar y, SkScalar z); + + void preRotateX(SkScalar deg); + void preRotateY(SkScalar deg); + void preRotateZ(SkScalar deg); + void preTranslate(SkScalar x, SkScalar y, SkScalar z); + + void setConcat(const SkMatrix3D& a, const SkMatrix3D& b); + void mapPoint(const SkPoint3D& src, SkPoint3D* dst) const; + void mapVector(const SkVector3D& src, SkVector3D* dst) const; + + void mapPoint(SkPoint3D* v) const { + this->mapPoint(*v, v); + } + + void mapVector(SkVector3D* v) const { + this->mapVector(*v, v); + } +}; + +class SkPatch3D { +public: + SkPatch3D(); + + void reset(); + void transform(const SkMatrix3D&, SkPatch3D* dst = nullptr) const; + + // dot a unit vector with the patch's normal + SkScalar dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const; + SkScalar dotWith(const SkVector3D& v) const { + return this->dotWith(v.fX, v.fY, v.fZ); + } + + // deprecated, but still here for animator (for now) + void rotate(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + void rotateDegrees(SkScalar /*x*/, SkScalar /*y*/, SkScalar /*z*/) {} + +private: +public: // make public for SkDraw3D for now + SkVector3D fU, fV; + SkPoint3D fOrigin; + + friend class SkCamera3D; +}; + +class SkCamera3D { +public: + SkCamera3D(); + + void reset(); + void update(); + void patchToMatrix(const SkPatch3D&, SkMatrix* matrix) const; + + SkPoint3D fLocation; // origin of the camera's space + SkPoint3D fAxis; // view direction + SkPoint3D fZenith; // up direction + SkPoint3D fObserver; // eye position (may not be the same as the origin) + +private: + mutable SkMatrix fOrientation; + mutable bool fNeedToUpdate; + + void doUpdate() const; +}; + +class SK_API Sk3DView : SkNoncopyable { +public: + Sk3DView(); + ~Sk3DView(); + + void save(); + void restore(); + + void translate(SkScalar x, SkScalar y, SkScalar z); + void rotateX(SkScalar deg); + void rotateY(SkScalar deg); + void rotateZ(SkScalar deg); + +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + void setCameraLocation(SkScalar x, SkScalar y, SkScalar z); + SkScalar getCameraLocationX() const; + SkScalar getCameraLocationY() const; + SkScalar getCameraLocationZ() const; +#endif + + void getMatrix(SkMatrix*) const; + void applyToCanvas(SkCanvas*) const; + + SkScalar dotWithNormal(SkScalar dx, SkScalar dy, SkScalar dz) const; + +private: + struct Rec { + Rec* fNext; + SkMatrix3D fMatrix; + }; + Rec* fRec; + Rec fInitialRec; + SkCamera3D fCamera; +}; + +#endif diff --git a/skia/include/utils/SkCanvasStateUtils.h b/skia/include/utils/SkCanvasStateUtils.h new file mode 100644 index 00000000..23cada8e --- /dev/null +++ b/skia/include/utils/SkCanvasStateUtils.h @@ -0,0 +1,78 @@ +/* + * 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 SkCanvasStateUtils_DEFINED +#define SkCanvasStateUtils_DEFINED + +#include "SkCanvas.h" + +class SkCanvasState; + +/** + * A set of functions that are useful for copying the state of an SkCanvas + * across a library boundary where the Skia library on the other side of the + * boundary may be newer. The expected usage is outline below... + * + * Lib Boundary + * CaptureCanvasState(...) ||| + * SkCanvas --> SkCanvasState ||| + * ||| CreateFromCanvasState(...) + * ||| SkCanvasState --> SkCanvas` + * ||| Draw into SkCanvas` + * ||| Unref SkCanvas` + * ReleaseCanvasState(...) ||| + * + */ +class SK_API SkCanvasStateUtils { +public: + /** + * Captures the current state of the canvas into an opaque ptr that is safe + * to pass to a different instance of Skia (which may be the same version, + * or may be newer). The function will return NULL in the event that one of the + * following conditions are true. + * 1) the canvas device type is not supported (currently only raster is supported) + * 2) the canvas clip type is not supported (currently only non-AA clips are supported) + * + * It is recommended that the original canvas also not be used until all + * canvases that have been created using its captured state have been dereferenced. + * + * Finally, it is important to note that any draw filters attached to the + * canvas are NOT currently captured. + * + * @param canvas The canvas you wish to capture the current state of. + * @return NULL or an opaque ptr that can be passed to CreateFromCanvasState + * to reconstruct the canvas. The caller is responsible for calling + * ReleaseCanvasState to free the memory associated with this state. + */ + static SkCanvasState* CaptureCanvasState(SkCanvas* canvas); + + /** + * Create a new SkCanvas from the captured state of another SkCanvas. The + * function will return NULL in the event that one of the + * following conditions are true. + * 1) the captured state is in an unrecognized format + * 2) the captured canvas device type is not supported + * + * @param state Opaque object created by CaptureCanvasState. + * @return NULL or an SkCanvas* whose devices and matrix/clip state are + * identical to the captured canvas. The caller is responsible for + * calling unref on the SkCanvas. + */ + static std::unique_ptr MakeFromCanvasState(const SkCanvasState* state); + + /** + * Free the memory associated with the captured canvas state. The state + * should not be released until all SkCanvas objects created using that + * state have been dereferenced. Must be called from the same library + * instance that created the state via CaptureCanvasState. + * + * @param state The captured state you wish to dispose of. + */ + static void ReleaseCanvasState(SkCanvasState* state); +}; + +#endif diff --git a/skia/include/utils/SkEventTracer.h b/skia/include/utils/SkEventTracer.h new file mode 100644 index 00000000..d3cc04dc --- /dev/null +++ b/skia/include/utils/SkEventTracer.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 Google Inc. All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEventTracer_DEFINED +#define SkEventTracer_DEFINED + +// The class in this header defines the interface between Skia's internal +// tracing macros and an external entity (e.g., Chrome) that will consume them. +// Such an entity should subclass SkEventTracer and provide an instance of +// that event to SkEventTracer::SetInstance. + +// If you're looking for the tracing macros to instrument Skia itself, those +// live in src/core/SkTraceEvent.h + +#include "SkTypes.h" + +class SK_API SkEventTracer { +public: + + typedef uint64_t Handle; + + /** + * If this is the first call to SetInstance or GetInstance then the passed instance is + * installed and true is returned. Otherwise, false is returned. In either case ownership of the + * tracer is transferred and it will be deleted when no longer needed. + */ + static bool SetInstance(SkEventTracer*); + + /** + * Gets the event tracer. If this is the first call to SetInstance or GetIntance then a default + * event tracer is installed and returned. + */ + static SkEventTracer* GetInstance(); + + virtual ~SkEventTracer() { } + + // The pointer returned from GetCategoryGroupEnabled() points to a + // value with zero or more of the following bits. Used in this class only. + // The TRACE_EVENT macros should only use the value as a bool. + // These values must be in sync with macro values in trace_event.h in chromium. + enum CategoryGroupEnabledFlags { + // Category group enabled for the recording mode. + kEnabledForRecording_CategoryGroupEnabledFlags = 1 << 0, + // Category group enabled for the monitoring mode. + kEnabledForMonitoring_CategoryGroupEnabledFlags = 1 << 1, + // Category group enabled by SetEventCallbackEnabled(). + kEnabledForEventCallback_CategoryGroupEnabledFlags = 1 << 2, + }; + + virtual const uint8_t* getCategoryGroupEnabled(const char* name) = 0; + virtual const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) = 0; + + virtual SkEventTracer::Handle + addTraceEvent(char phase, + const uint8_t* categoryEnabledFlag, + const char* name, + uint64_t id, + int32_t numArgs, + const char** argNames, + const uint8_t* argTypes, + const uint64_t* argValues, + uint8_t flags) = 0; + + virtual void + updateTraceEventDuration(const uint8_t* categoryEnabledFlag, + const char* name, + SkEventTracer::Handle handle) = 0; +}; + +#endif // SkEventTracer_DEFINED diff --git a/skia/include/utils/SkFrontBufferedStream.h b/skia/include/utils/SkFrontBufferedStream.h new file mode 100644 index 00000000..e504dc5d --- /dev/null +++ b/skia/include/utils/SkFrontBufferedStream.h @@ -0,0 +1,39 @@ +/* + * 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 SkFrontBufferedStream_DEFINED +#define SkFrontBufferedStream_DEFINED + +#include "SkStream.h" + +/** + * Specialized stream that buffers the first X bytes of a stream, + * where X is passed in by the user. Note that unlike some buffered + * stream APIs, once more bytes than can fit in the buffer are read, + * no more buffering is done. This stream is designed for a use case + * where the caller knows that rewind will only be called from within + * X bytes (inclusive), and the wrapped stream is not necessarily + * able to rewind at all. + */ +class SK_API SkFrontBufferedStream { +public: + /** + * Creates a new stream that wraps and buffers an SkStream. + * @param stream SkStream to buffer. If stream is NULL, NULL is + * returned. When this call succeeds (i.e. returns non NULL), + * SkFrontBufferedStream is expected to be the only owner of + * stream, so it should no be longer used directly. + * SkFrontBufferedStream will delete stream upon deletion. + * @param minBufferSize Minimum size of buffer required. + * @return An SkStream that can buffer at least minBufferSize, or + * NULL on failure. The caller is required to delete when finished with + * this object. + */ + static std::unique_ptr Make(std::unique_ptr stream, + size_t minBufferSize); +}; +#endif // SkFrontBufferedStream_DEFINED diff --git a/skia/include/utils/SkInterpolator.h b/skia/include/utils/SkInterpolator.h new file mode 100644 index 00000000..7eedb4f2 --- /dev/null +++ b/skia/include/utils/SkInterpolator.h @@ -0,0 +1,138 @@ +/* + * 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 SkInterpolator_DEFINED +#define SkInterpolator_DEFINED + +#include "../private/SkNoncopyable.h" +#include "../private/SkTo.h" +#include "SkScalar.h" + +class SK_API SkInterpolatorBase : SkNoncopyable { +public: + enum Result { + kNormal_Result, + kFreezeStart_Result, + kFreezeEnd_Result + }; +protected: + SkInterpolatorBase(); + ~SkInterpolatorBase(); +public: + void reset(int elemCount, int frameCount); + + /** Return the start and end time for this interpolator. + If there are no key frames, return false. + @param startTime If not null, returns the time (in milliseconds) of the + first keyframe. If there are no keyframes, this param + is ignored (left unchanged). + @param endTime If not null, returns the time (in milliseconds) of the + last keyframe. If there are no keyframes, this parameter + is ignored (left unchanged). + @return True if there are key frames, or false if there are none. + */ + bool getDuration(SkMSec* startTime, SkMSec* endTime) const; + + + /** Set the whether the repeat is mirrored. + @param mirror If true, the odd repeats interpolate from the last key + frame and the first. + */ + void setMirror(bool mirror) { + fFlags = SkToU8((fFlags & ~kMirror) | (int)mirror); + } + + /** Set the repeat count. The repeat count may be fractional. + @param repeatCount Multiplies the total time by this scalar. + */ + void setRepeatCount(SkScalar repeatCount) { fRepeat = repeatCount; } + + /** Set the whether the repeat is mirrored. + @param reset If true, the odd repeats interpolate from the last key + frame and the first. + */ + void setReset(bool reset) { + fFlags = SkToU8((fFlags & ~kReset) | (int)reset); + } + + Result timeToT(SkMSec time, SkScalar* T, int* index, bool* exact) const; + +protected: + enum Flags { + kMirror = 1, + kReset = 2, + kHasBlend = 4 + }; + static SkScalar ComputeRelativeT(SkMSec time, SkMSec prevTime, SkMSec nextTime, + const SkScalar blend[4] = nullptr); + int16_t fFrameCount; + uint8_t fElemCount; + uint8_t fFlags; + SkScalar fRepeat; + struct SkTimeCode { + SkMSec fTime; + SkScalar fBlend[4]; + }; + SkTimeCode* fTimes; // pointer into fStorage + void* fStorage; +#ifdef SK_DEBUG + SkTimeCode(* fTimesArray)[10]; +#endif +}; + +class SK_API SkInterpolator : public SkInterpolatorBase { +public: + SkInterpolator(); + SkInterpolator(int elemCount, int frameCount); + void reset(int elemCount, int frameCount); + + /** Add or replace a key frame, copying the values[] data into the + interpolator. + @param index The index of this frame (frames must be ordered by time) + @param time The millisecond time for this frame + @param values The array of values [elemCount] for this frame. The data + is copied into the interpolator. + @param blend A positive scalar specifying how to blend between this + and the next key frame. [0...1) is a cubic lag/log/lag + blend (slow to change at the beginning and end) + 1 is a linear blend (default) + */ + bool setKeyFrame(int index, SkMSec time, const SkScalar values[], + const SkScalar blend[4] = nullptr); + + /** Return the computed values given the specified time. Return whether + those values are the result of pinning to either the first + (kFreezeStart) or last (kFreezeEnd), or from interpolated the two + nearest key values (kNormal). + @param time The time to sample (in milliseconds) + @param (may be null) where to write the computed values. + */ + Result timeToValues(SkMSec time, SkScalar values[] = nullptr) const; + +private: + SkScalar* fValues; // pointer into fStorage +#ifdef SK_DEBUG + SkScalar(* fScalarsArray)[10]; +#endif + typedef SkInterpolatorBase INHERITED; +}; + +/** Interpolate a cubic curve, typically to provide an ease-in ease-out transition. + All the parameters are in the range of [0...1]. + The input value is treated as the x-coordinate of the cubic. + The output value is the y-coordinate on the cubic at the x-coordinate. + + @param value The x-coordinate pinned between [0..1]. + @param bx,by,cx,cy The cubic control points where the cubic is specified + as (0,0) (bx,by) (cx,cy) (1,1) + @return the corresponding y-coordinate value, from [0..1]. +*/ +SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by, + SkScalar cx, SkScalar cy); + +#endif diff --git a/skia/include/utils/SkLua.h b/skia/include/utils/SkLua.h new file mode 100644 index 00000000..651c4a71 --- /dev/null +++ b/skia/include/utils/SkLua.h @@ -0,0 +1,69 @@ +/* + * 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 SkLua_DEFINED +#define SkLua_DEFINED + +#include "SkColor.h" +#include "SkPathEffect.h" +#include "SkScalar.h" +#include "SkString.h" + +struct lua_State; + +class SkCanvas; +class SkMatrix; +class SkPaint; +class SkPath; +struct SkRect; +class SkRRect; +class SkTextBlob; + +#define SkScalarToLua(x) SkScalarToDouble(x) +#define SkLuaToScalar(x) SkDoubleToScalar(x) + +class SkLua { +public: + static void Load(lua_State*); + + SkLua(const char termCode[] = nullptr); // creates a new L, will close it + SkLua(lua_State*); // uses L, will not close it + ~SkLua(); + + lua_State* get() const { return fL; } + lua_State* operator*() const { return fL; } + lua_State* operator->() const { return fL; } + + bool runCode(const char code[]); + bool runCode(const void* code, size_t size); + + void pushBool(bool, const char tableKey[] = nullptr); + void pushString(const char[], const char tableKey[] = nullptr); + void pushString(const char[], size_t len, const char tableKey[] = nullptr); + void pushString(const SkString&, const char tableKey[] = nullptr); + void pushArrayU16(const uint16_t[], int count, const char tableKey[] = nullptr); + void pushArrayPoint(const SkPoint[], int count, const char key[] = nullptr); + void pushArrayScalar(const SkScalar[], int count, const char key[] = nullptr); + void pushColor(SkColor, const char tableKey[] = nullptr); + void pushU32(uint32_t, const char tableKey[] = nullptr); + void pushScalar(SkScalar, const char tableKey[] = nullptr); + void pushRect(const SkRect&, const char tableKey[] = nullptr); + void pushRRect(const SkRRect&, const char tableKey[] = nullptr); + void pushDash(const SkPathEffect::DashInfo&, const char tableKey[] = nullptr); + void pushMatrix(const SkMatrix&, const char tableKey[] = nullptr); + void pushPaint(const SkPaint&, const char tableKey[] = nullptr); + void pushPath(const SkPath&, const char tableKey[] = nullptr); + void pushCanvas(SkCanvas*, const char tableKey[] = nullptr); + void pushTextBlob(const SkTextBlob*, const char tableKey[] = nullptr); + +private: + lua_State* fL; + SkString fTermCode; + bool fWeOwnL; +}; + +#endif diff --git a/skia/include/utils/SkLuaCanvas.h b/skia/include/utils/SkLuaCanvas.h new file mode 100644 index 00000000..aa984c76 --- /dev/null +++ b/skia/include/utils/SkLuaCanvas.h @@ -0,0 +1,79 @@ +/* + * 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 SkLuaCanvas_DEFINED +#define SkLuaCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkString.h" +#include "SkVertices.h" + +struct lua_State; + +class SkLuaCanvas : public SkCanvas { +public: + void pushThis(); + + SkLuaCanvas(int width, int height, lua_State*, const char function[]); + ~SkLuaCanvas() override; + +protected: + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) override; + virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, + SrcRectConstraint) override; + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + +private: + lua_State* fL; + SkString fFunc; + + void sendverb(const char verb[]); + + typedef SkCanvas INHERITED; +}; + +#endif diff --git a/skia/include/utils/SkNWayCanvas.h b/skia/include/utils/SkNWayCanvas.h new file mode 100644 index 00000000..6d77ea63 --- /dev/null +++ b/skia/include/utils/SkNWayCanvas.h @@ -0,0 +1,97 @@ + +/* + * 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 SkNWayCanvas_DEFINED +#define SkNWayCanvas_DEFINED + +#include "../private/SkTDArray.h" +#include "SkCanvasVirtualEnforcer.h" +#include "SkNoDrawCanvas.h" + +class SK_API SkNWayCanvas : public SkCanvasVirtualEnforcer { +public: + SkNWayCanvas(int width, int height); + ~SkNWayCanvas() override; + + virtual void addCanvas(SkCanvas*); + virtual void removeCanvas(SkCanvas*); + virtual void removeAll(); + +protected: + SkTDArray fList; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + virtual void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) override; + virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, + const SkPaint& paint) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], 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 onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, + SrcRectConstraint) override; + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, SkFilterQuality, + SkBlendMode) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + 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 onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + void onFlush() override; + + class Iter; + +private: + typedef SkCanvasVirtualEnforcer INHERITED; +}; + + +#endif diff --git a/skia/include/utils/SkNoDrawCanvas.h b/skia/include/utils/SkNoDrawCanvas.h new file mode 100644 index 00000000..f8c197b9 --- /dev/null +++ b/skia/include/utils/SkNoDrawCanvas.h @@ -0,0 +1,89 @@ +/* + * 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 SkNoDrawCanvas_DEFINED +#define SkNoDrawCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkCanvasVirtualEnforcer.h" +#include "SkVertices.h" + +struct SkIRect; + +// SkNoDrawCanvas is a helper for SkCanvas subclasses which do not need to +// actually rasterize (e.g., analysis of the draw calls). +// +// It provides the following simplifications: +// +// * not backed by any device/pixels +// * conservative clipping (clipping calls only use rectangles) +// +class SK_API SkNoDrawCanvas : public SkCanvasVirtualEnforcer { +public: + SkNoDrawCanvas(int width, int height); + + // TODO: investigate the users of this ctor. + SkNoDrawCanvas(const SkIRect&); + + explicit SkNoDrawCanvas(sk_sp device); + + // Optimization to reset state to be the same as after construction. + void resetCanvas(int width, int height) { + resetForNextPicture(SkIRect::MakeWH(width, height)); + } + +protected: + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override; + + // No-op overrides for aborting rasterization earlier than SkNullBlitter. + void onDrawAnnotation(const SkRect&, const char[], SkData*) override {} + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override {} + void onDrawDrawable(SkDrawable*, const SkMatrix*) override {} + 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 onDrawPoints(PointMode, size_t, const SkPoint[], 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 onDrawRRect(const SkRRect&, const SkPaint&) override {} + void onDrawPath(const SkPath&, const SkPaint&) override {} + void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override {} + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) 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 onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, + const SkPaint*) override {} + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, + const SkPaint*) override {} + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int, SkFilterQuality, + SkBlendMode) override {} + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override {} + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone[], int, SkBlendMode, + const SkPaint&) override {} + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int, SkBlendMode, const SkRect*, const SkPaint*) override {} + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override {} + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override {} + +private: + typedef SkCanvasVirtualEnforcer INHERITED; +}; + +#endif // SkNoDrawCanvas_DEFINED diff --git a/skia/include/utils/SkNullCanvas.h b/skia/include/utils/SkNullCanvas.h new file mode 100644 index 00000000..8e5e0acd --- /dev/null +++ b/skia/include/utils/SkNullCanvas.h @@ -0,0 +1,18 @@ +/* + * 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 SkNullCanvas_DEFINED +#define SkNullCanvas_DEFINED + +#include "SkCanvas.h" + +/** + * Creates a canvas that draws nothing. This is useful for performance testing. + */ +SK_API std::unique_ptr SkMakeNullCanvas(); + +#endif diff --git a/skia/include/utils/SkPaintFilterCanvas.h b/skia/include/utils/SkPaintFilterCanvas.h new file mode 100644 index 00000000..c57cffe1 --- /dev/null +++ b/skia/include/utils/SkPaintFilterCanvas.h @@ -0,0 +1,129 @@ +/* + * 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 SkPaintFilterCanvas_DEFINED +#define SkPaintFilterCanvas_DEFINED + +#include "SkCanvasVirtualEnforcer.h" +#include "SkNWayCanvas.h" +#include "SkTLazy.h" + +/** \class SkPaintFilterCanvas + + A utility proxy base class for implementing draw/paint filters. +*/ +class SK_API SkPaintFilterCanvas : public SkCanvasVirtualEnforcer { +public: + /** + * The new SkPaintFilterCanvas is configured for forwarding to the + * specified canvas. Also copies the target canvas matrix and clip bounds. + */ + SkPaintFilterCanvas(SkCanvas* canvas); + + enum Type { + kPaint_Type, + kPoint_Type, + kArc_Type, + kBitmap_Type, + kRect_Type, + kRRect_Type, + kDRRect_Type, + kOval_Type, + kPath_Type, + kPicture_Type, + kDrawable_Type, + kText_Type, + kTextBlob_Type, + kVertices_Type, + kPatch_Type, + + kTypeCount + }; + + // Forwarded to the wrapped canvas. + SkISize getBaseLayerSize() const override { return proxy()->getBaseLayerSize(); } + GrContext* getGrContext() override { return proxy()->getGrContext(); } + GrRenderTargetContext* internal_private_accessTopLayerRenderTargetContext() override { + return proxy()->internal_private_accessTopLayerRenderTargetContext(); + } + +protected: + /** + * Called with the paint that will be used to draw the specified type. + * The implementation may modify the paint as they wish (using SkTCopyOnFirstWrite::writable). + * + * The result bool is used to determine whether the draw op is to be + * executed (true) or skipped (false). + * + * Note: The base implementation calls onFilter() for top-level/explicit paints only. + * To also filter encapsulated paints (e.g. SkPicture, SkTextBlob), clients may need to + * override the relevant methods (i.e. drawPicture, drawTextBlob). + */ + virtual bool onFilter(SkTCopyOnFirstWrite* paint, Type type) const = 0; + + void onDrawPaint(const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, 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 onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, + SrcRectConstraint) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, + const SkPaint*, SrcRectConstraint) override; + void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawImageSet(const SkCanvas::ImageSetEntry[], int count, SkFilterQuality, + SkBlendMode) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkBlendMode, + const SkPaint& paint) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + + void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, + const SkPaint&) override; + void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], + const SkPaint&) override; + void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], + SkScalar constY, const SkPaint&) override; + void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) override; + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int, SkBlendMode, const SkRect*, const SkPaint*) override; + void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override; + void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override; + + // Forwarded to the wrapped canvas. + sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + bool onPeekPixels(SkPixmap* pixmap) override; + bool onAccessTopLayerPixels(SkPixmap* pixmap) override; + SkImageInfo onImageInfo() const override; + bool onGetProps(SkSurfaceProps* props) const override; + +private: + class AutoPaintFilter; + + SkCanvas* proxy() const { SkASSERT(fList.count() == 1); return fList[0]; } +}; + +#endif diff --git a/skia/include/utils/SkParse.h b/skia/include/utils/SkParse.h new file mode 100644 index 00000000..6260175e --- /dev/null +++ b/skia/include/utils/SkParse.h @@ -0,0 +1,32 @@ + +/* + * 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 SkParse_DEFINED +#define SkParse_DEFINED + +#include "SkColor.h" + +class SK_API SkParse { +public: + static int Count(const char str[]); // number of scalars or int values + static int Count(const char str[], char separator); + static const char* FindColor(const char str[], SkColor* value); + static const char* FindHex(const char str[], uint32_t* value); + static const char* FindMSec(const char str[], SkMSec* value); + static const char* FindNamedColor(const char str[], size_t len, SkColor* color); + static const char* FindS32(const char str[], int32_t* value); + static const char* FindScalar(const char str[], SkScalar* value); + static const char* FindScalars(const char str[], SkScalar value[], int count); + + static bool FindBool(const char str[], bool* value); + // return the index of str in list[], or -1 if not found + static int FindList(const char str[], const char list[]); +}; + +#endif diff --git a/skia/include/utils/SkParsePath.h b/skia/include/utils/SkParsePath.h new file mode 100644 index 00000000..c52b3c0b --- /dev/null +++ b/skia/include/utils/SkParsePath.h @@ -0,0 +1,23 @@ + +/* + * 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 SkParsePath_DEFINED +#define SkParsePath_DEFINED + +#include "SkPath.h" + +class SkString; + +class SkParsePath { +public: + static bool FromSVGString(const char str[], SkPath*); + static void ToSVGString(const SkPath&, SkString*); +}; + +#endif diff --git a/skia/include/utils/SkRandom.h b/skia/include/utils/SkRandom.h new file mode 100644 index 00000000..f3f2abf2 --- /dev/null +++ b/skia/include/utils/SkRandom.h @@ -0,0 +1,169 @@ +/* + * 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 SkRandom_DEFINED +#define SkRandom_DEFINED + +#include "../private/SkFixed.h" +#include "../private/SkFloatBits.h" +#include "SkScalar.h" + +/** \class SkRandom + + Utility class that implements pseudo random 32bit numbers using Marsaglia's + multiply-with-carry "mother of all" algorithm. Unlike rand(), this class holds + its own state, so that multiple instances can be used with no side-effects. + + Has a large period and all bits are well-randomized. + */ +class SkRandom { +public: + SkRandom() { init(0); } + SkRandom(uint32_t seed) { init(seed); } + SkRandom(const SkRandom& rand) : fK(rand.fK), fJ(rand.fJ) {} + + SkRandom& operator=(const SkRandom& rand) { + fK = rand.fK; + fJ = rand.fJ; + + return *this; + } + + /** Return the next pseudo random number as an unsigned 32bit value. + */ + uint32_t nextU() { + fK = kKMul*(fK & 0xffff) + (fK >> 16); + fJ = kJMul*(fJ & 0xffff) + (fJ >> 16); + return (((fK << 16) | (fK >> 16)) + fJ); + } + + /** Return the next pseudo random number as a signed 32bit value. + */ + int32_t nextS() { return (int32_t)this->nextU(); } + + /** + * Returns value [0...1) as an IEEE float + */ + float nextF() { + unsigned int floatint = 0x3f800000 | (this->nextU() >> 9); + float f = SkBits2Float(floatint) - 1.0f; + return f; + } + + /** + * Returns value [min...max) as a float + */ + float nextRangeF(float min, float max) { + return min + this->nextF() * (max - min); + } + + /** Return the next pseudo random number, as an unsigned value of + at most bitCount bits. + @param bitCount The maximum number of bits to be returned + */ + uint32_t nextBits(unsigned bitCount) { + SkASSERT(bitCount > 0 && bitCount <= 32); + return this->nextU() >> (32 - bitCount); + } + + /** Return the next pseudo random unsigned number, mapped to lie within + [min, max] inclusive. + */ + uint32_t nextRangeU(uint32_t min, uint32_t max) { + SkASSERT(min <= max); + uint32_t range = max - min + 1; + if (0 == range) { + return this->nextU(); + } else { + return min + this->nextU() % range; + } + } + + /** Return the next pseudo random unsigned number, mapped to lie within + [0, count). + */ + uint32_t nextULessThan(uint32_t count) { + SkASSERT(count > 0); + return this->nextRangeU(0, count - 1); + } + + /** Return the next pseudo random number expressed as a SkScalar + in the range [0..SK_Scalar1). + */ + SkScalar nextUScalar1() { return SkFixedToScalar(this->nextUFixed1()); } + + /** Return the next pseudo random number expressed as a SkScalar + in the range [min..max). + */ + SkScalar nextRangeScalar(SkScalar min, SkScalar max) { + return this->nextUScalar1() * (max - min) + min; + } + + /** Return the next pseudo random number expressed as a SkScalar + in the range [-SK_Scalar1..SK_Scalar1). + */ + SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); } + + /** Return the next pseudo random number as a bool. + */ + bool nextBool() { return this->nextU() >= 0x80000000; } + + /** A biased version of nextBool(). + */ + bool nextBiasedBool(SkScalar fractionTrue) { + SkASSERT(fractionTrue >= 0 && fractionTrue <= SK_Scalar1); + return this->nextUScalar1() <= fractionTrue; + } + + /** Reset the random object. + */ + void setSeed(uint32_t seed) { init(seed); } + +private: + // Initialize state variables with LCG. + // We must ensure that both J and K are non-zero, otherwise the + // multiply-with-carry step will forevermore return zero. + void init(uint32_t seed) { + fK = NextLCG(seed); + if (0 == fK) { + fK = NextLCG(fK); + } + fJ = NextLCG(fK); + if (0 == fJ) { + fJ = NextLCG(fJ); + } + SkASSERT(0 != fK && 0 != fJ); + } + static uint32_t NextLCG(uint32_t seed) { return kMul*seed + kAdd; } + + /** Return the next pseudo random number expressed as an unsigned SkFixed + in the range [0..SK_Fixed1). + */ + SkFixed nextUFixed1() { return this->nextU() >> 16; } + + /** Return the next pseudo random number expressed as a signed SkFixed + in the range [-SK_Fixed1..SK_Fixed1). + */ + SkFixed nextSFixed1() { return this->nextS() >> 15; } + + // See "Numerical Recipes in C", 1992 page 284 for these constants + // For the LCG that sets the initial state from a seed + enum { + kMul = 1664525, + kAdd = 1013904223 + }; + // Constants for the multiply-with-carry steps + enum { + kKMul = 30345, + kJMul = 18000, + }; + + uint32_t fK; + uint32_t fJ; +}; + +#endif diff --git a/skia/include/utils/SkShadowUtils.h b/skia/include/utils/SkShadowUtils.h new file mode 100644 index 00000000..7beee855 --- /dev/null +++ b/skia/include/utils/SkShadowUtils.h @@ -0,0 +1,56 @@ + +/* + * 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 SkShadowUtils_DEFINED +#define SkShadowUtils_DEFINED + +#include "SkColor.h" +#include "SkPoint3.h" +#include "SkScalar.h" +#include "../private/SkShadowFlags.h" + +class SkCanvas; +class SkPath; +class SkResourceCache; + +class SK_API SkShadowUtils { +public: + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. The shadow may be cached, depending on the path type and canvas matrix. If the + * matrix is perspective or the path is volatile, it will not be cached. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos The 3D position of the light relative to the canvas plane. This is + * independent of the canvas's current matrix. + * @param lightRadius The radius of the disc light. + * @param ambientColor The color of the ambient shadow. + * @param spotColor The color of the spot shadow. + * @param flags Options controlling opaque occluder optimizations and shadow appearance. See + * SkShadowFlags. + */ + static void DrawShadow(SkCanvas* canvas, const SkPath& path, const SkPoint3& zPlaneParams, + const SkPoint3& lightPos, SkScalar lightRadius, + SkColor ambientColor, SkColor spotColor, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + /** + * Helper routine to compute color values for one-pass tonal alpha. + * + * @param inAmbientColor Original ambient color + * @param inSpotColor Original spot color + * @param outAmbientColor Modified ambient color + * @param outSpotColor Modified spot color + */ + static void ComputeTonalColors(SkColor inAmbientColor, SkColor inSpotColor, + SkColor* outAmbientColor, SkColor* outSpotColor); +}; + +#endif diff --git a/skia/include/utils/SkTextUtils.h b/skia/include/utils/SkTextUtils.h new file mode 100644 index 00000000..30a66a7c --- /dev/null +++ b/skia/include/utils/SkTextUtils.h @@ -0,0 +1,37 @@ +/* + * 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 SkTextUtils_DEFINED +#define SkTextUtils_DEFINED + +#include "SkCanvas.h" +#include "SkPaint.h" +#include "SkFont.h" +#include "SkString.h" + +class SkTextUtils { +public: + enum Align { + kLeft_Align, + kCenter_Align, + kRight_Align, + }; + + static void DrawText(SkCanvas*, const void* text, size_t size, SkScalar x, SkScalar y, + const SkPaint&, Align = kLeft_Align); + + static void DrawString(SkCanvas* canvas, const char text[], SkScalar x, SkScalar y, + const SkPaint& paint, Align align = kLeft_Align) { + DrawText(canvas, text, strlen(text), x, y, paint, align); + } + static void DrawString(SkCanvas* canvas, const SkString& str, SkScalar x, SkScalar y, + const SkPaint& paint, Align align = kLeft_Align) { + DrawText(canvas, str.c_str(), str.size(), x, y, paint, align); + } +}; + +#endif diff --git a/skia/include/utils/SkTraceEventPhase.h b/skia/include/utils/SkTraceEventPhase.h new file mode 100644 index 00000000..38457be2 --- /dev/null +++ b/skia/include/utils/SkTraceEventPhase.h @@ -0,0 +1,19 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef SkTraceEventPhase_DEFINED +#define SkTraceEventPhase_DEFINED + +// Phase indicates the nature of an event entry. E.g. part of a begin/end pair. +#define TRACE_EVENT_PHASE_BEGIN ('B') +#define TRACE_EVENT_PHASE_END ('E') +#define TRACE_EVENT_PHASE_COMPLETE ('X') +#define TRACE_EVENT_PHASE_INSTANT ('I') +#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S') +#define TRACE_EVENT_PHASE_ASYNC_END ('F') +#define TRACE_EVENT_PHASE_COUNTER ('C') +#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N') +#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O') +#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D') + +#endif // SkTraceEventPhase_DEFINED diff --git a/skia/include/utils/mac/SkCGUtils.h b/skia/include/utils/mac/SkCGUtils.h new file mode 100644 index 00000000..06995c3e --- /dev/null +++ b/skia/include/utils/mac/SkCGUtils.h @@ -0,0 +1,86 @@ + +/* + * 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 SkCGUtils_DEFINED +#define SkCGUtils_DEFINED + +#include "SkSize.h" +#include "SkImageInfo.h" +#include "SkImage.h" +#include "SkPixmap.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#include +#endif + +#ifdef SK_BUILD_FOR_IOS +#include +#endif + +class SkBitmap; +class SkData; +class SkPixmap; +class SkStreamRewindable; + +SK_API CGContextRef SkCreateCGContext(const SkPixmap&); + +/** + * Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not + * null, use it to determine the size of the bitmap, and scale the image to fill the bitmap. + * Otherwise use the image's width/height. + * + * On failure, return false, and leave bitmap unchanged. + */ +SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src); + +SK_API sk_sp SkMakeImageFromCGImage(CGImageRef); + +/** + * Copy the pixels from src into the memory specified by info/rowBytes/dstPixels. On failure, + * return false (e.g. ImageInfo incompatible with src). + */ +SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels, + CGImageRef src); +static inline bool SkCopyPixelsFromCGImage(const SkPixmap& dst, CGImageRef src) { + return SkCopyPixelsFromCGImage(dst.info(), dst.rowBytes(), dst.writable_addr(), src); +} + +/** + * Create an imageref from the specified bitmap using the specified colorspace. + * If space is NULL, then CGColorSpaceCreateDeviceRGB() is used. + */ +SK_API CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm, + CGColorSpaceRef space); + +/** + * Create an imageref from the specified bitmap using the colorspace returned + * by CGColorSpaceCreateDeviceRGB() + */ +static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) { + return SkCreateCGImageRefWithColorspace(bm, NULL); +} + +/** + * Draw the bitmap into the specified CG context. The bitmap will be converted + * to a CGImage using the generic RGB colorspace. (x,y) specifies the position + * of the top-left corner of the bitmap. The bitmap is converted using the + * colorspace returned by CGColorSpaceCreateDeviceRGB() + */ +void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y); + +/** + * Return a provider that wraps the specified stream. + * When the provider is finally deleted, it will delete the stream. + */ +CGDataProviderRef SkCreateDataProviderFromStream(std::unique_ptr); + +CGDataProviderRef SkCreateDataProviderFromData(sk_sp); + +#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +#endif // SkCGUtils_DEFINED