From 97e509997ebb3961be4bab0ee328eed5d43f41f9 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Mon, 24 Oct 2016 15:22:26 -0400 Subject: [PATCH] Bug 1299435 - part 4 - update Skia source to m55. r=mchang MozReview-Commit-ID: 8TA6Lovdc28 --HG-- rename : gfx/skia/skia/src/animator/SkCondensedDebug.cpp => gfx/skia/skia/src/animator/SkCondensedDebug.inc rename : gfx/skia/skia/src/animator/SkCondensedRelease.cpp => gfx/skia/skia/src/animator/SkCondensedRelease.inc --- .../include/android/SkBitmapRegionDecoder.h | 4 +- gfx/skia/skia/include/c/sk_types.h | 16 +- gfx/skia/skia/include/codec/SkAndroidCodec.h | 7 +- gfx/skia/skia/include/codec/SkCodec.h | 169 +- gfx/skia/skia/include/codec/SkEncodedInfo.h | 199 ++ gfx/skia/skia/include/config/SkUserConfig.h | 15 +- gfx/skia/skia/include/core/SkBBHFactory.h | 2 +- gfx/skia/skia/include/core/SkBitmap.h | 14 +- gfx/skia/skia/include/core/SkBitmapDevice.h | 19 +- gfx/skia/skia/include/core/SkBlendMode.h | 51 + gfx/skia/skia/include/core/SkCanvas.h | 465 ++- gfx/skia/skia/include/core/SkChunkAlloc.h | 11 + gfx/skia/skia/include/core/SkClipOp.h | 26 + gfx/skia/skia/include/core/SkClipStack.h | 102 +- gfx/skia/skia/include/core/SkColor.h | 14 +- gfx/skia/skia/include/core/SkColorFilter.h | 15 +- gfx/skia/skia/include/core/SkColorSpace.h | 106 + gfx/skia/skia/include/core/SkColorTable.h | 6 +- gfx/skia/skia/include/core/SkData.h | 48 +- gfx/skia/skia/include/core/SkDataTable.h | 15 +- gfx/skia/skia/include/core/SkDevice.h | 156 +- gfx/skia/skia/include/core/SkDocument.h | 137 +- gfx/skia/skia/include/core/SkDraw.h | 16 +- gfx/skia/skia/include/core/SkDrawable.h | 8 +- gfx/skia/skia/include/core/SkFilterQuality.h | 4 +- gfx/skia/skia/include/core/SkFlattenable.h | 14 +- gfx/skia/skia/include/core/SkFont.h | 29 +- gfx/skia/skia/include/core/SkFontHost.h | 95 - gfx/skia/skia/include/core/SkFontLCDConfig.h | 2 +- gfx/skia/skia/include/core/SkFontStyle.h | 31 +- gfx/skia/skia/include/core/SkImage.h | 103 +- .../skia/include/core/SkImageDeserializer.h | 36 + gfx/skia/skia/include/core/SkImageEncoder.h | 11 +- gfx/skia/skia/include/core/SkImageFilter.h | 243 +- gfx/skia/skia/include/core/SkImageGenerator.h | 6 +- gfx/skia/skia/include/core/SkImageInfo.h | 132 +- gfx/skia/skia/include/core/SkLights.h | 199 ++ gfx/skia/skia/include/core/SkMaskFilter.h | 20 +- gfx/skia/skia/include/core/SkMath.h | 62 +- gfx/skia/skia/include/core/SkMatrix.h | 67 +- .../skia/include/{utils => core}/SkMatrix44.h | 30 +- gfx/skia/skia/include/core/SkMilestone.h | 2 +- gfx/skia/skia/include/core/SkPaint.h | 98 +- gfx/skia/skia/include/core/SkPath.h | 44 +- gfx/skia/skia/include/core/SkPathEffect.h | 10 +- gfx/skia/skia/include/core/SkPathMeasure.h | 3 +- gfx/skia/skia/include/core/SkPathRef.h | 78 +- gfx/skia/skia/include/core/SkPicture.h | 61 +- .../skia/include/core/SkPictureAnalyzer.h | 66 + .../skia/include/core/SkPictureRecorder.h | 18 +- gfx/skia/skia/include/core/SkPixelRef.h | 19 +- gfx/skia/skia/include/core/SkPixmap.h | 8 +- gfx/skia/skia/include/core/SkPoint.h | 4 + gfx/skia/skia/include/core/SkPostConfig.h | 72 +- gfx/skia/skia/include/core/SkPreConfig.h | 56 +- gfx/skia/skia/include/core/SkRRect.h | 32 +- gfx/skia/skia/include/core/SkRWBuffer.h | 26 +- gfx/skia/skia/include/core/SkRect.h | 19 +- gfx/skia/skia/include/core/SkRefCnt.h | 90 +- gfx/skia/skia/include/core/SkRegion.h | 10 +- gfx/skia/skia/include/core/SkScalar.h | 1 + gfx/skia/skia/include/core/SkShader.h | 61 +- gfx/skia/skia/include/core/SkStream.h | 33 +- gfx/skia/skia/include/core/SkStrokeRec.h | 16 + gfx/skia/skia/include/core/SkSurface.h | 76 +- gfx/skia/skia/include/core/SkSurfaceProps.h | 18 +- gfx/skia/skia/include/core/SkTLazy.h | 38 +- gfx/skia/skia/include/core/SkTextBlob.h | 84 +- gfx/skia/skia/include/core/SkTime.h | 2 +- gfx/skia/skia/include/core/SkTypeface.h | 125 +- gfx/skia/skia/include/core/SkTypes.h | 73 +- gfx/skia/skia/include/core/SkWriteBuffer.h | 147 +- gfx/skia/skia/include/core/SkWriter32.h | 6 - gfx/skia/skia/include/core/SkXfermode.h | 77 +- .../include/effects/SkAlphaThresholdFilter.h | 6 +- .../skia/include/effects/SkArithmeticMode.h | 4 + .../skia/include/effects/SkBlurImageFilter.h | 41 +- .../skia/include/effects/SkBlurMaskFilter.h | 38 +- .../skia/include/effects/SkColorCubeFilter.h | 7 +- .../effects/SkColorFilterImageFilter.h | 5 +- .../include/effects/SkComposeImageFilter.h | 13 +- .../include/effects/SkDisplacementMapEffect.h | 43 +- .../include/effects/SkDropShadowImageFilter.h | 7 +- .../skia/include/effects/SkGammaColorFilter.h | 48 + .../include/effects/SkGaussianEdgeShader.h | 27 + .../skia/include/effects/SkGradientShader.h | 102 +- gfx/skia/skia/include/effects/SkImageSource.h | 18 +- .../include/effects/SkLightingImageFilter.h | 78 +- .../skia/include/effects/SkLumaColorFilter.h | 3 +- .../include/effects/SkMagnifierImageFilter.h | 17 +- .../effects/SkMatrixConvolutionImageFilter.h | 41 +- .../skia/include/effects/SkMergeImageFilter.h | 12 +- .../include/effects/SkMorphologyImageFilter.h | 18 +- .../include/effects/SkOffsetImageFilter.h | 8 +- .../skia/include/effects/SkPaintImageFilter.h | 4 +- .../include/effects/SkPerlinNoiseShader.h | 3 +- .../include/effects/SkPictureImageFilter.h | 29 +- .../effects/SkRRectsGaussianEdgeShader.h | 37 + .../skia/include/effects/SkTestImageFilters.h | 52 - .../skia/include/effects/SkTileImageFilter.h | 23 +- .../include/effects/SkXfermodeImageFilter.h | 67 +- gfx/skia/skia/{src => include}/gpu/GrBuffer.h | 67 +- gfx/skia/skia/include/gpu/GrBufferAccess.h | 55 + gfx/skia/skia/include/gpu/GrCaps.h | 58 +- gfx/skia/skia/include/gpu/GrClip.h | 280 +- gfx/skia/skia/include/gpu/GrColor.h | 59 + gfx/skia/skia/include/gpu/GrColorSpaceXform.h | 45 + gfx/skia/skia/include/gpu/GrConfig.h | 4 +- gfx/skia/skia/include/gpu/GrContext.h | 98 +- gfx/skia/skia/include/gpu/GrContextOptions.h | 71 +- gfx/skia/skia/include/gpu/GrCoordTransform.h | 61 +- gfx/skia/skia/include/gpu/GrDrawContext.h | 221 +- .../skia/include/gpu/GrFragmentProcessor.h | 146 +- gfx/skia/skia/include/gpu/GrGpuResource.h | 92 +- gfx/skia/skia/include/gpu/GrInvariantOutput.h | 12 + gfx/skia/skia/include/gpu/GrPaint.h | 119 +- gfx/skia/skia/include/gpu/GrProcessor.h | 23 +- .../skia/include/gpu/GrProcessorUnitTest.h | 38 +- gfx/skia/skia/include/gpu/GrRenderTarget.h | 80 +- gfx/skia/skia/include/gpu/GrResourceKey.h | 17 +- gfx/skia/skia/include/gpu/GrShaderVar.h | 5 - gfx/skia/skia/include/gpu/GrSurface.h | 19 +- gfx/skia/skia/include/gpu/GrTestUtils.h | 39 +- gfx/skia/skia/include/gpu/GrTexture.h | 10 +- gfx/skia/skia/include/gpu/GrTextureAccess.h | 14 +- gfx/skia/skia/include/gpu/GrTextureParams.h | 31 +- gfx/skia/skia/include/gpu/GrTextureProvider.h | 1 - gfx/skia/skia/include/gpu/GrTypes.h | 108 +- gfx/skia/skia/include/gpu/GrTypesPriv.h | 161 +- gfx/skia/skia/include/gpu/GrXferProcessor.h | 11 +- gfx/skia/skia/include/gpu/SkGr.h | 23 +- gfx/skia/skia/include/gpu/SkGrPixelRef.h | 62 - .../skia/include/gpu/SkGrTexturePixelRef.h | 19 - .../gpu/effects/GrConstColorProcessor.h | 4 +- .../include/gpu/effects/GrCoverageSetOpXP.h | 6 +- .../include/gpu/effects/GrCustomXfermode.h | 2 +- .../gpu/effects/GrPorterDuffXferProcessor.h | 13 +- .../gpu/effects/GrXfermodeFragmentProcessor.h | 14 +- gfx/skia/skia/include/gpu/gl/GrGLConfig.h | 6 +- gfx/skia/skia/include/gpu/gl/GrGLFunctions.h | 16 +- gfx/skia/skia/include/gpu/gl/GrGLInterface.h | 18 +- gfx/skia/skia/include/gpu/gl/GrGLTypes.h | 1 + .../skia/include/gpu/vk/GrVkBackendContext.h | 16 +- gfx/skia/skia/include/gpu/vk/GrVkDefines.h | 10 +- gfx/skia/skia/include/gpu/vk/GrVkInterface.h | 28 +- gfx/skia/skia/include/gpu/vk/GrVkTypes.h | 38 +- gfx/skia/skia/include/images/SkForceLinking.h | 2 + .../skia/include/ports/SkAtomics_atomic.h | 59 - gfx/skia/skia/include/ports/SkAtomics_std.h | 71 - gfx/skia/skia/include/ports/SkAtomics_sync.h | 73 - .../include/ports/SkFontConfigInterface.h | 25 +- gfx/skia/skia/include/ports/SkFontMgr.h | 13 +- .../ports/SkFontMgr_FontConfigInterface.h | 20 + .../skia/include/ports/SkFontMgr_indirect.h | 29 +- .../skia/include/ports/SkRemotableFontMgr.h | 4 +- gfx/skia/skia/include/ports/SkTypeface_win.h | 5 + .../include/private/GrInstancedPipelineInfo.h | 49 + .../include/private/GrRenderTargetProxy.h | 97 + .../skia/include/private/GrSurfaceProxy.h | 92 + .../skia/include/private/GrTextureProxy.h | 46 + .../private}/GrTextureStripAtlas.h | 4 +- gfx/skia/skia/include/private/SkAtomics.h | 110 +- gfx/skia/skia/include/private/SkBitmaskEnum.h | 34 + gfx/skia/skia/include/private/SkChecksum.h | 21 +- gfx/skia/skia/include/private/SkFixed.h | 35 +- gfx/skia/skia/include/private/SkFloatBits.h | 40 +- .../skia/include/private/SkFloatingPoint.h | 31 +- .../skia/include/private/SkGpuFenceSync.h | 29 - gfx/skia/skia/include/private/SkLeanWindows.h | 34 + .../skia/include/private/SkMiniRecorder.h | 6 +- gfx/skia/skia/include/private/SkMutex.h | 110 +- gfx/skia/skia/include/private/SkOnce.h | 149 +- gfx/skia/skia/include/private/SkOncePtr.h | 106 - gfx/skia/skia/include/private/SkRecords.h | 206 +- gfx/skia/skia/include/private/SkSemaphore.h | 103 +- .../skia/include/private/SkShadowParams.h | 48 + gfx/skia/skia/include/private/SkSpinlock.h | 10 +- gfx/skia/skia/include/private/SkTArray.h | 128 +- gfx/skia/skia/include/private/SkTDArray.h | 31 +- gfx/skia/skia/include/private/SkTFitsIn.h | 1 + gfx/skia/skia/include/private/SkTLogic.h | 133 +- gfx/skia/skia/include/private/SkTemplates.h | 33 +- gfx/skia/skia/include/private/SkWeakRefCnt.h | 60 +- .../skia/include/svg/parser/SkSVGAttribute.h | 43 - gfx/skia/skia/include/svg/parser/SkSVGBase.h | 25 - .../skia/include/svg/parser/SkSVGPaintState.h | 89 - .../skia/include/svg/parser/SkSVGParser.h | 73 - gfx/skia/skia/include/svg/parser/SkSVGTypes.h | 40 - gfx/skia/skia/include/utils/SkDumpCanvas.h | 18 +- gfx/skia/skia/include/utils/SkJSONCPP.h | 33 - gfx/skia/skia/include/utils/SkLuaCanvas.h | 11 +- gfx/skia/skia/include/utils/SkNWayCanvas.h | 11 +- gfx/skia/skia/include/utils/SkNinePatch.h | 33 - .../skia/include/utils/SkPaintFilterCanvas.h | 4 + gfx/skia/skia/include/utils/SkRTConf.h | 193 -- gfx/skia/skia/include/utils/SkTextBox.h | 2 +- gfx/skia/skia/include/utils/mac/SkCGUtils.h | 16 +- gfx/skia/skia/include/views/SkEvent.h | 2 + .../skia/include/views/SkOSWindow_Android.h | 52 - gfx/skia/skia/include/views/SkOSWindow_Mac.h | 6 +- gfx/skia/skia/include/views/SkOSWindow_SDL.h | 5 +- gfx/skia/skia/include/views/SkOSWindow_Unix.h | 5 +- gfx/skia/skia/include/views/SkOSWindow_Win.h | 19 +- gfx/skia/skia/include/views/SkOSWindow_iOS.h | 3 +- gfx/skia/skia/include/views/SkTouchGesture.h | 6 + gfx/skia/skia/include/views/SkWindow.h | 16 +- gfx/skia/skia/include/xml/SkBML_WXMLParser.h | 46 - gfx/skia/skia/include/xml/SkBML_XMLParser.h | 31 - gfx/skia/skia/include/xml/SkDOM.h | 12 +- gfx/skia/skia/include/xml/SkXMLParser.h | 76 +- .../skia/src/android/SkBitmapRegionCanvas.cpp | 139 - .../skia/src/android/SkBitmapRegionCanvas.h | 49 - .../skia/src/android/SkBitmapRegionCodec.cpp | 48 +- .../src/android/SkBitmapRegionDecoder.cpp | 29 +- gfx/skia/skia/src/animator/SkAnimateMaker.cpp | 6 +- gfx/skia/skia/src/animator/SkAnimator.cpp | 6 +- .../src/animator/SkBuildCondensedInfo.cpp | 4 +- ...ondensedDebug.cpp => SkCondensedDebug.inc} | 0 ...nsedRelease.cpp => SkCondensedRelease.inc} | 0 gfx/skia/skia/src/animator/SkDrawBitmap.cpp | 2 +- gfx/skia/skia/src/animator/SkDrawPaint.cpp | 2 +- .../skia/src/animator/SkGetCondensedInfo.cpp | 6 +- gfx/skia/skia/src/animator/SkPaintPart.h | 3 +- gfx/skia/skia/src/animator/SkSnapshot.cpp | 2 - gfx/skia/skia/src/c/sk_paint.cpp | 63 +- gfx/skia/skia/src/codec/SkAndroidCodec.cpp | 10 +- gfx/skia/skia/src/codec/SkBmpCodec.cpp | 86 +- gfx/skia/skia/src/codec/SkBmpCodec.h | 4 +- gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp | 6 +- gfx/skia/skia/src/codec/SkBmpMaskCodec.h | 4 +- gfx/skia/skia/src/codec/SkBmpRLECodec.cpp | 29 +- gfx/skia/skia/src/codec/SkBmpRLECodec.h | 6 +- .../skia/src/codec/SkBmpStandardCodec.cpp | 72 +- gfx/skia/skia/src/codec/SkBmpStandardCodec.h | 8 +- gfx/skia/skia/src/codec/SkCodec.cpp | 191 +- .../skia/src/codec/SkCodecImageGenerator.cpp | 33 +- .../skia/src/codec/SkCodecImageGenerator.h | 13 +- gfx/skia/skia/src/codec/SkCodecPriv.h | 200 +- gfx/skia/skia/src/codec/SkGifCodec.cpp | 51 +- gfx/skia/skia/src/codec/SkGifCodec.h | 8 +- gfx/skia/skia/src/codec/SkIcoCodec.cpp | 94 +- gfx/skia/skia/src/codec/SkIcoCodec.h | 16 +- gfx/skia/skia/src/codec/SkJpegCodec.cpp | 388 +-- gfx/skia/skia/src/codec/SkJpegCodec.h | 46 +- gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp | 19 +- gfx/skia/skia/src/codec/SkJpegDecoderMgr.h | 5 +- gfx/skia/skia/src/codec/SkMaskSwizzler.cpp | 267 +- gfx/skia/skia/src/codec/SkMaskSwizzler.h | 2 +- gfx/skia/skia/src/codec/SkPngCodec.cpp | 1423 ++++++--- gfx/skia/skia/src/codec/SkPngCodec.h | 120 +- gfx/skia/skia/src/codec/SkRawCodec.cpp | 50 +- gfx/skia/skia/src/codec/SkSampledCodec.cpp | 173 +- gfx/skia/skia/src/codec/SkSampler.cpp | 56 +- gfx/skia/skia/src/codec/SkSampler.h | 34 +- gfx/skia/skia/src/codec/SkSwizzler.cpp | 729 +++-- gfx/skia/skia/src/codec/SkSwizzler.h | 87 +- gfx/skia/skia/src/codec/SkWbmpCodec.cpp | 27 +- gfx/skia/skia/src/codec/SkWbmpCodec.h | 2 +- gfx/skia/skia/src/codec/SkWebpCodec.cpp | 254 +- gfx/skia/skia/src/codec/SkWebpCodec.h | 13 +- gfx/skia/skia/src/core/SkAAClip.cpp | 1 + .../src/core/SkAdvancedTypefaceMetrics.cpp | 314 -- .../skia/src/core/SkAdvancedTypefaceMetrics.h | 140 +- gfx/skia/skia/src/core/SkBigPicture.cpp | 15 +- gfx/skia/skia/src/core/SkBigPicture.h | 15 +- gfx/skia/skia/src/core/SkBitmap.cpp | 169 +- gfx/skia/skia/src/core/SkBitmapCache.cpp | 21 +- gfx/skia/skia/src/core/SkBitmapCache.h | 8 +- gfx/skia/skia/src/core/SkBitmapController.cpp | 15 +- gfx/skia/skia/src/core/SkBitmapController.h | 7 +- gfx/skia/skia/src/core/SkBitmapDevice.cpp | 146 +- gfx/skia/skia/src/core/SkBitmapHeap.cpp | 391 --- gfx/skia/skia/src/core/SkBitmapHeap.h | 299 -- gfx/skia/skia/src/core/SkBitmapProcShader.cpp | 345 +-- gfx/skia/skia/src/core/SkBitmapProcShader.h | 43 +- gfx/skia/skia/src/core/SkBitmapProcState.cpp | 14 +- gfx/skia/skia/src/core/SkBitmapProcState.h | 17 +- .../core/SkBitmapProcState_matrixProcs.cpp | 6 +- gfx/skia/skia/src/core/SkBitmapProvider.cpp | 11 +- gfx/skia/skia/src/core/SkBitmapScaler.cpp | 5 +- gfx/skia/skia/src/core/SkBlendModePriv.h | 19 + gfx/skia/skia/src/core/SkBlitter.cpp | 32 +- gfx/skia/skia/src/core/SkBlitter.h | 22 +- gfx/skia/skia/src/core/SkBlitter_A8.cpp | 9 +- gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp | 30 +- gfx/skia/skia/src/core/SkBlitter_PM4f.cpp | 43 +- gfx/skia/skia/src/core/SkBlitter_RGB16.cpp | 22 +- gfx/skia/skia/src/core/SkBlitter_Sprite.cpp | 156 +- .../{effects => core}/SkBlurImageFilter.cpp | 124 +- gfx/skia/skia/src/core/SkCanvas.cpp | 1242 +++++--- gfx/skia/skia/src/core/SkChecksum.cpp | 47 - gfx/skia/skia/src/core/SkChunkAlloc.cpp | 17 +- gfx/skia/skia/src/core/SkClipStack.cpp | 198 +- gfx/skia/skia/src/core/SkColor.cpp | 42 +- gfx/skia/skia/src/core/SkColorFilter.cpp | 31 +- .../skia/src/core/SkColorFilterShader.cpp | 20 +- gfx/skia/skia/src/core/SkColorFilterShader.h | 5 +- .../core/SkColorMatrixFilterRowMajor255.cpp | 23 +- .../src/core/SkColorMatrixFilterRowMajor255.h | 4 +- gfx/skia/skia/src/core/SkColorShader.cpp | 303 ++ gfx/skia/skia/src/core/SkColorShader.h | 58 +- gfx/skia/skia/src/core/SkColorSpace.cpp | 862 +++--- gfx/skia/skia/src/core/SkColorSpace.h | 88 - gfx/skia/skia/src/core/SkColorSpacePriv.h | 12 + gfx/skia/skia/src/core/SkColorSpaceXform.cpp | 1440 +++++++++ gfx/skia/skia/src/core/SkColorSpaceXform.h | 102 + gfx/skia/skia/src/core/SkColorSpace_Base.h | 240 ++ gfx/skia/skia/src/core/SkColorSpace_ICC.cpp | 1338 +++++++++ gfx/skia/skia/src/core/SkColorTable.cpp | 10 +- gfx/skia/skia/src/core/SkComposeShader.cpp | 26 +- gfx/skia/skia/src/core/SkComposeShader.h | 5 +- gfx/skia/skia/src/core/SkConfig8888.cpp | 64 + gfx/skia/skia/src/core/SkCoreBlitters.h | 14 +- gfx/skia/skia/src/core/SkCpu.cpp | 114 + gfx/skia/skia/src/core/SkCpu.h | 96 + gfx/skia/skia/src/core/SkCubicClipper.h | 4 +- gfx/skia/skia/src/core/SkData.cpp | 12 +- gfx/skia/skia/src/core/SkDataTable.cpp | 46 +- gfx/skia/skia/src/core/SkDeduper.h | 39 + gfx/skia/skia/src/core/SkDescriptor.h | 7 +- gfx/skia/skia/src/core/SkDevice.cpp | 218 +- gfx/skia/skia/src/core/SkDistanceFieldGen.cpp | 3 +- gfx/skia/skia/src/core/SkDocument.cpp | 8 +- gfx/skia/skia/src/core/SkDraw.cpp | 241 +- gfx/skia/skia/src/core/SkEdge.cpp | 2 +- gfx/skia/skia/src/core/SkEdgeClipper.cpp | 20 +- gfx/skia/skia/src/core/SkEndian.h | 2 +- gfx/skia/skia/src/core/SkExchange.h | 25 + gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h | 4 +- .../src/core/SkFlattenableSerialization.cpp | 2 +- gfx/skia/skia/src/core/SkFloatBits.cpp | 205 -- gfx/skia/skia/src/core/SkFont.cpp | 51 +- gfx/skia/skia/src/core/SkFontDescriptor.cpp | 26 +- gfx/skia/skia/src/core/SkFontDescriptor.h | 29 +- .../{SkFontHost.cpp => SkFontLCDConfig.cpp} | 21 - gfx/skia/skia/src/core/SkFontMgr.cpp | 87 +- gfx/skia/skia/src/core/SkFontStyle.cpp | 19 +- gfx/skia/skia/src/core/SkFuzzLogging.h | 23 + gfx/skia/skia/src/core/SkGeometry.cpp | 93 +- gfx/skia/skia/src/core/SkGeometry.h | 6 +- .../src/core/SkGlobalInitialization_core.cpp | 15 +- gfx/skia/skia/src/core/SkGlyphCache.cpp | 77 +- gfx/skia/skia/src/core/SkGlyphCache.h | 29 +- gfx/skia/skia/src/core/SkGlyphCache_Globals.h | 17 +- gfx/skia/skia/src/core/SkGpuBlurUtils.cpp | 383 +++ gfx/skia/skia/src/core/SkGpuBlurUtils.h | 46 + gfx/skia/skia/src/core/SkGraphics.cpp | 12 +- gfx/skia/skia/src/core/SkHalf.h | 118 +- gfx/skia/skia/src/core/SkImageCacherator.cpp | 27 +- gfx/skia/skia/src/core/SkImageCacherator.h | 5 +- gfx/skia/skia/src/core/SkImageFilter.cpp | 584 +--- gfx/skia/skia/src/core/SkImageFilterCache.cpp | 134 + gfx/skia/skia/src/core/SkImageFilterCache.h | 64 + .../skia/src/core/SkImageFilterCacheKey.h | 41 - gfx/skia/skia/src/core/SkImageGenerator.cpp | 4 +- gfx/skia/skia/src/core/SkImageInfo.cpp | 44 +- gfx/skia/skia/src/core/SkImagePriv.h | 103 + gfx/skia/skia/src/core/SkLatticeIter.cpp | 288 ++ gfx/skia/skia/src/core/SkLatticeIter.h | 62 + gfx/skia/skia/src/core/SkLayerInfo.h | 87 - gfx/skia/skia/src/core/SkLight.h | 55 - gfx/skia/skia/src/core/SkLightingShader.cpp | 675 ++--- gfx/skia/skia/src/core/SkLightingShader.h | 83 +- gfx/skia/skia/src/core/SkLights.cpp | 88 + gfx/skia/skia/src/core/SkLineClipper.cpp | 26 - .../skia/src/core/SkLinearBitmapPipeline.cpp | 735 +++-- .../skia/src/core/SkLinearBitmapPipeline.h | 145 +- .../src/core/SkLinearBitmapPipeline_core.h | 84 +- .../src/core/SkLinearBitmapPipeline_sample.h | 1496 ++++++---- .../src/core/SkLinearBitmapPipeline_tile.h | 23 +- gfx/skia/skia/src/core/SkLiteDL.cpp | 815 +++++ gfx/skia/skia/src/core/SkLiteDL.h | 109 + gfx/skia/skia/src/core/SkLiteRecorder.cpp | 209 ++ gfx/skia/skia/src/core/SkLiteRecorder.h | 96 + .../src/core/SkLocalMatrixImageFilter.cpp | 17 +- .../skia/src/core/SkLocalMatrixImageFilter.h | 13 +- .../skia/src/core/SkLocalMatrixShader.cpp | 16 + gfx/skia/skia/src/core/SkLocalMatrixShader.h | 18 +- gfx/skia/skia/src/{utils => core}/SkMD5.cpp | 14 +- gfx/skia/skia/src/core/SkMD5.h | 41 + gfx/skia/skia/src/core/SkMakeUnique.h | 23 + gfx/skia/skia/src/core/SkMaskCache.cpp | 13 +- gfx/skia/skia/src/core/SkMaskFilter.cpp | 17 +- gfx/skia/skia/src/core/SkMath.cpp | 70 - gfx/skia/skia/src/core/SkMathPriv.h | 66 + gfx/skia/skia/src/core/SkMatrix.cpp | 147 +- .../skia/src/{utils => core}/SkMatrix44.cpp | 24 +- .../skia/src/core/SkMatrixImageFilter.cpp | 7 +- gfx/skia/skia/src/core/SkMatrixPriv.h | 102 + gfx/skia/skia/src/core/SkMessageBus.h | 8 +- gfx/skia/skia/src/core/SkMiniRecorder.cpp | 30 +- gfx/skia/skia/src/core/SkMipMap.cpp | 113 +- gfx/skia/skia/src/core/SkMipMap.h | 39 +- gfx/skia/skia/src/core/SkModeColorFilter.cpp | 12 +- gfx/skia/skia/src/core/SkModeColorFilter.h | 4 +- gfx/skia/skia/src/core/SkMultiPictureDraw.cpp | 98 +- gfx/skia/skia/src/core/SkNinePatchIter.cpp | 72 - gfx/skia/skia/src/core/SkNinePatchIter.h | 41 - .../skia/src/core/SkNormalBevelSource.cpp | 310 ++ gfx/skia/skia/src/core/SkNormalBevelSource.h | 57 + gfx/skia/skia/src/core/SkNormalFlatSource.cpp | 107 + gfx/skia/skia/src/core/SkNormalFlatSource.h | 48 + gfx/skia/skia/src/core/SkNormalMapSource.cpp | 267 ++ gfx/skia/skia/src/core/SkNormalMapSource.h | 62 + gfx/skia/skia/src/core/SkNormalSource.cpp | 24 + gfx/skia/skia/src/core/SkNormalSource.h | 127 + gfx/skia/skia/src/core/SkNormalSourcePriv.h | 57 + gfx/skia/skia/src/core/SkNx.h | 60 +- gfx/skia/skia/src/core/SkOpts.cpp | 294 +- gfx/skia/skia/src/core/SkOpts.h | 20 +- gfx/skia/skia/src/core/SkPM4f.h | 7 + gfx/skia/skia/src/core/SkPM4fPriv.h | 73 +- gfx/skia/skia/src/core/SkPaint.cpp | 430 +-- gfx/skia/skia/src/core/SkPaintPriv.cpp | 2 +- gfx/skia/skia/src/core/SkPath.cpp | 165 +- gfx/skia/skia/src/core/SkPathMeasure.cpp | 207 +- gfx/skia/skia/src/core/SkPathMeasurePriv.h | 29 + gfx/skia/skia/src/core/SkPathPriv.h | 38 + gfx/skia/skia/src/core/SkPathRef.cpp | 136 +- gfx/skia/skia/src/core/SkPicture.cpp | 83 +- gfx/skia/skia/src/core/SkPictureAnalyzer.cpp | 65 + gfx/skia/skia/src/core/SkPictureCommon.h | 31 +- gfx/skia/skia/src/core/SkPictureData.cpp | 100 +- gfx/skia/skia/src/core/SkPictureData.h | 77 +- gfx/skia/skia/src/core/SkPictureFlat.cpp | 32 - gfx/skia/skia/src/core/SkPictureFlat.h | 443 +-- gfx/skia/skia/src/core/SkPicturePlayback.cpp | 358 ++- gfx/skia/skia/src/core/SkPicturePlayback.h | 9 +- gfx/skia/skia/src/core/SkPictureRecord.cpp | 303 +- gfx/skia/skia/src/core/SkPictureRecord.h | 78 +- gfx/skia/skia/src/core/SkPictureRecorder.cpp | 100 +- gfx/skia/skia/src/core/SkPictureShader.cpp | 17 +- gfx/skia/skia/src/core/SkPictureShader.h | 5 +- gfx/skia/skia/src/core/SkPipe.h | 92 + gfx/skia/skia/src/core/SkPixmap.cpp | 11 +- gfx/skia/skia/src/core/SkPoint.cpp | 10 +- gfx/skia/skia/src/core/SkRRect.cpp | 69 +- gfx/skia/skia/src/core/SkRWBuffer.cpp | 112 +- .../skia/src/core/SkRadialShadowMapShader.cpp | 431 +++ .../skia/src/core/SkRadialShadowMapShader.h | 31 + gfx/skia/skia/src/core/SkRasterClip.cpp | 80 +- gfx/skia/skia/src/core/SkRasterClip.h | 23 +- gfx/skia/skia/src/core/SkRasterPipeline.cpp | 59 + gfx/skia/skia/src/core/SkRasterPipeline.h | 157 + .../skia/src/core/SkRasterPipelineBlitter.cpp | 215 ++ gfx/skia/skia/src/core/SkRasterizer.cpp | 3 +- gfx/skia/skia/src/core/SkReadBuffer.cpp | 248 +- gfx/skia/skia/src/core/SkReadBuffer.h | 101 +- gfx/skia/skia/src/core/SkRecordDraw.cpp | 358 +-- gfx/skia/skia/src/core/SkRecordOpts.cpp | 63 +- gfx/skia/skia/src/core/SkRecordedDrawable.cpp | 94 + gfx/skia/skia/src/core/SkRecordedDrawable.h | 41 + gfx/skia/skia/src/core/SkRecorder.cpp | 134 +- gfx/skia/skia/src/core/SkRecorder.h | 39 +- gfx/skia/skia/src/core/SkRecords.cpp | 9 - gfx/skia/skia/src/core/SkRegion.cpp | 3 +- gfx/skia/skia/src/core/SkRegion_path.cpp | 3 + gfx/skia/skia/src/core/SkResourceCache.cpp | 18 +- gfx/skia/skia/src/core/SkResourceCache.h | 2 +- gfx/skia/skia/src/core/SkSRGB.cpp | 75 + gfx/skia/skia/src/core/SkSRGB.h | 84 + gfx/skia/skia/src/core/SkScalerContext.cpp | 62 +- gfx/skia/skia/src/core/SkScalerContext.h | 45 +- gfx/skia/skia/src/core/SkScan_AntiPath.cpp | 1 - gfx/skia/skia/src/core/SkScan_Hairline.cpp | 101 +- gfx/skia/skia/src/core/SkSemaphore.cpp | 44 +- gfx/skia/skia/src/core/SkShader.cpp | 178 +- gfx/skia/skia/src/core/SkShadowShader.cpp | 957 ++++++ gfx/skia/skia/src/core/SkShadowShader.h | 40 + gfx/skia/skia/src/core/SkSharedMutex.cpp | 98 +- .../src/{pdf => core}/SkSinglyLinkedList.h | 2 + gfx/skia/skia/src/core/SkSmallAllocator.h | 10 +- gfx/skia/skia/src/core/SkSpanProcs.cpp | 8 +- gfx/skia/skia/src/core/SkSpecialImage.cpp | 565 ++-- gfx/skia/skia/src/core/SkSpecialImage.h | 87 +- gfx/skia/skia/src/core/SkSpecialSurface.cpp | 120 +- gfx/skia/skia/src/core/SkSpecialSurface.h | 30 +- gfx/skia/skia/src/core/SkSpinlock.cpp | 2 +- gfx/skia/skia/src/core/SkSpriteBlitter.h | 12 +- gfx/skia/skia/src/core/SkSpriteBlitter4f.cpp | 10 +- .../skia/src/core/SkSpriteBlitter_ARGB32.cpp | 10 +- .../skia/src/core/SkSpriteBlitter_RGB16.cpp | 2 +- gfx/skia/skia/src/core/SkStream.cpp | 48 +- gfx/skia/skia/src/core/SkString.cpp | 63 +- gfx/skia/skia/src/core/SkStroke.cpp | 108 +- gfx/skia/skia/src/core/SkStrokeRec.cpp | 28 + gfx/skia/skia/src/core/SkTLList.h | 47 +- gfx/skia/skia/src/core/SkTMultiMap.h | 45 + gfx/skia/skia/src/core/SkTSort.h | 2 +- gfx/skia/skia/src/core/SkTaskGroup.cpp | 25 +- gfx/skia/skia/src/core/SkTaskGroup.h | 3 - gfx/skia/skia/src/core/SkTextBlob.cpp | 219 +- .../skia/src/core/SkTextBlobRunIterator.h | 4 + gfx/skia/skia/src/core/SkThreadID.cpp | 2 +- gfx/skia/skia/src/core/SkTime.cpp | 58 +- gfx/skia/skia/src/core/SkTraceEventCommon.h | 11 +- gfx/skia/skia/src/core/SkTypeface.cpp | 164 +- gfx/skia/skia/src/core/SkTypefaceCache.cpp | 55 +- gfx/skia/skia/src/core/SkTypefaceCache.h | 23 +- gfx/skia/skia/src/core/SkTypefacePriv.h | 10 +- gfx/skia/skia/src/core/SkUtilsArm.cpp | 145 +- gfx/skia/skia/src/core/SkUtilsArm.h | 73 +- .../skia/src/core/SkValidatingReadBuffer.cpp | 122 +- .../skia/src/core/SkValidatingReadBuffer.h | 18 +- gfx/skia/skia/src/core/SkWriteBuffer.cpp | 269 +- gfx/skia/skia/src/core/SkXfermode.cpp | 160 +- gfx/skia/skia/src/core/SkXfermode4f.cpp | 187 +- gfx/skia/skia/src/core/SkXfermodeF16.cpp | 178 ++ .../src/core/SkXfermodeInterpretation.cpp | 25 +- gfx/skia/skia/src/core/SkXfermodeU64.cpp | 248 -- gfx/skia/skia/src/core/SkXfermode_proccoeff.h | 8 +- .../GrAlphaThresholdFragmentProcessor.cpp | 198 ++ .../GrAlphaThresholdFragmentProcessor.h | 68 + .../effects/GrCircleBlurFragmentProcessor.cpp | 345 ++- .../effects/GrCircleBlurFragmentProcessor.h | 50 +- gfx/skia/skia/src/effects/Sk2DPathEffect.cpp | 3 +- .../src/effects/SkAlphaThresholdFilter.cpp | 428 +-- .../skia/src/effects/SkArithmeticMode.cpp | 45 +- .../skia/src/effects/SkArithmeticModePriv.h | 47 + .../skia/src/effects/SkArithmeticMode_gpu.cpp | 16 +- .../skia/src/effects/SkArithmeticMode_gpu.h | 19 +- .../skia/src/effects/SkBlurMaskFilter.cpp | 552 +++- .../skia/src/effects/SkColorCubeFilter.cpp | 20 +- .../src/effects/SkColorFilterImageFilter.cpp | 65 +- .../skia/src/effects/SkColorMatrixFilter.cpp | 7 + .../skia/src/effects/SkComposeImageFilter.cpp | 15 +- .../skia/src/effects/SkDashPathEffect.cpp | 2 +- .../src/effects/SkDisplacementMapEffect.cpp | 454 +-- .../src/effects/SkDropShadowImageFilter.cpp | 21 +- .../skia/src/effects/SkGammaColorFilter.cpp | 56 + .../skia/src/effects/SkGaussianEdgeShader.cpp | 169 ++ gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp | 411 --- gfx/skia/skia/src/effects/SkGpuBlurUtils.h | 50 - gfx/skia/skia/src/effects/SkImageSource.cpp | 35 +- .../skia/src/effects/SkLayerDrawLooper.cpp | 2 +- .../skia/src/effects/SkLayerRasterizer.cpp | 4 +- .../src/effects/SkLightingImageFilter.cpp | 719 ++--- .../skia/src/effects/SkLumaColorFilter.cpp | 9 +- .../src/effects/SkMagnifierImageFilter.cpp | 237 +- .../SkMatrixConvolutionImageFilter.cpp | 237 +- .../skia/src/effects/SkMergeImageFilter.cpp | 23 +- .../src/effects/SkMorphologyImageFilter.cpp | 169 +- .../skia/src/effects/SkOffsetImageFilter.cpp | 16 +- .../skia/src/effects/SkPaintImageFilter.cpp | 10 +- .../skia/src/effects/SkPerlinNoiseShader.cpp | 95 +- .../skia/src/effects/SkPictureImageFilter.cpp | 114 +- .../effects/SkRRectsGaussianEdgeShader.cpp | 433 +++ .../skia/src/effects/SkTableColorFilter.cpp | 31 +- .../skia/src/effects/SkTestImageFilters.cpp | 98 - .../skia/src/effects/SkTileImageFilter.cpp | 135 +- .../src/effects/SkXfermodeImageFilter.cpp | 577 +++- .../effects/gradients/Sk4fGradientBase.cpp | 61 +- .../src/effects/gradients/Sk4fGradientBase.h | 7 +- .../src/effects/gradients/Sk4fGradientPriv.h | 14 +- .../effects/gradients/Sk4fLinearGradient.cpp | 18 +- .../src/effects/gradients/SkClampRange.cpp | 2 +- .../effects/gradients/SkGradientShader.cpp | 1370 ++++++--- .../effects/gradients/SkGradientShaderPriv.h | 231 +- .../effects/gradients/SkLinearGradient.cpp | 142 +- .../src/effects/gradients/SkLinearGradient.h | 5 +- .../effects/gradients/SkRadialGradient.cpp | 116 +- .../src/effects/gradients/SkRadialGradient.h | 5 +- .../src/effects/gradients/SkSweepGradient.cpp | 117 +- .../src/effects/gradients/SkSweepGradient.h | 5 +- .../gradients/SkTwoPointConicalGradient.cpp | 27 +- .../gradients/SkTwoPointConicalGradient.h | 5 +- .../SkTwoPointConicalGradient_gpu.cpp | 340 ++- .../gradients/SkTwoPointConicalGradient_gpu.h | 3 +- .../skia/src/fonts/SkFontMgr_fontconfig.cpp | 331 --- .../skia/src/fonts/SkFontMgr_indirect.cpp | 16 +- gfx/skia/skia/src/fonts/SkGScalerContext.cpp | 89 +- gfx/skia/skia/src/fonts/SkGScalerContext.h | 12 +- .../skia/src/fonts/SkRandomScalerContext.cpp | 27 +- .../skia/src/fonts/SkRandomScalerContext.h | 14 +- .../skia/src/fonts/SkRemotableFontMgr.cpp | 8 +- .../skia/src/fonts/SkTestScalerContext.cpp | 31 +- gfx/skia/skia/src/fonts/SkTestScalerContext.h | 5 +- gfx/skia/skia/src/gpu/GrAllocator.h | 2 +- gfx/skia/skia/src/gpu/GrAppliedClip.h | 75 + gfx/skia/skia/src/gpu/GrBatchAtlas.cpp | 15 +- gfx/skia/skia/src/gpu/GrBatchAtlas.h | 2 + gfx/skia/skia/src/gpu/GrBatchFlushState.cpp | 1 + gfx/skia/skia/src/gpu/GrBatchFlushState.h | 6 + gfx/skia/skia/src/gpu/GrBatchTest.cpp | 2 + gfx/skia/skia/src/gpu/GrBlurUtils.cpp | 267 +- gfx/skia/skia/src/gpu/GrBlurUtils.h | 5 +- gfx/skia/skia/src/gpu/GrBuffer.cpp | 72 + gfx/skia/skia/src/gpu/GrBufferAllocPool.cpp | 7 +- gfx/skia/skia/src/gpu/GrCaps.cpp | 43 +- gfx/skia/skia/src/gpu/GrClip.cpp | 53 - gfx/skia/skia/src/gpu/GrClipMaskManager.cpp | 1163 -------- gfx/skia/skia/src/gpu/GrClipMaskManager.h | 178 -- gfx/skia/skia/src/gpu/GrClipStackClip.cpp | 486 +++ gfx/skia/skia/src/gpu/GrClipStackClip.h | 71 + gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp | 78 + gfx/skia/skia/src/gpu/GrContext.cpp | 317 +- gfx/skia/skia/src/gpu/GrContextPriv.h | 59 + gfx/skia/skia/src/gpu/GrCoordTransform.cpp | 8 +- .../skia/src/gpu/GrDefaultGeoProcFactory.cpp | 116 +- .../skia/src/gpu/GrDefaultGeoProcFactory.h | 24 +- gfx/skia/skia/src/gpu/GrDrawContext.cpp | 1068 ++++--- gfx/skia/skia/src/gpu/GrDrawContextPriv.h | 41 +- gfx/skia/skia/src/gpu/GrDrawTarget.cpp | 523 ++-- gfx/skia/skia/src/gpu/GrDrawTarget.h | 133 +- gfx/skia/skia/src/gpu/GrDrawingManager.cpp | 104 +- gfx/skia/skia/src/gpu/GrDrawingManager.h | 54 +- gfx/skia/skia/src/gpu/GrFixedClip.cpp | 72 + gfx/skia/skia/src/gpu/GrFixedClip.h | 55 + gfx/skia/skia/src/gpu/GrFragmentProcessor.cpp | 234 +- gfx/skia/skia/src/gpu/GrGeometryProcessor.h | 11 +- gfx/skia/skia/src/gpu/GrGpu.cpp | 181 +- gfx/skia/skia/src/gpu/GrGpu.h | 150 +- gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp | 49 + gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h | 98 + gfx/skia/skia/src/gpu/GrGpuResource.cpp | 48 +- .../skia/src/gpu/GrGpuResourceCacheAccess.h | 26 +- gfx/skia/skia/src/gpu/GrGpuResourcePriv.h | 4 +- .../skia/src/gpu/GrImageIDTextureAdjuster.cpp | 83 +- .../skia/src/gpu/GrImageIDTextureAdjuster.h | 42 +- gfx/skia/skia/src/gpu/GrLayerAtlas.cpp | 168 -- gfx/skia/skia/src/gpu/GrLayerAtlas.h | 157 - gfx/skia/skia/src/gpu/GrLayerCache.cpp | 557 ---- gfx/skia/skia/src/gpu/GrLayerCache.h | 432 --- gfx/skia/skia/src/gpu/GrLayerHoister.cpp | 398 --- gfx/skia/skia/src/gpu/GrLayerHoister.h | 124 - gfx/skia/skia/src/gpu/GrMemoryPool.cpp | 2 +- gfx/skia/skia/src/gpu/GrNonAtomicRef.h | 2 + gfx/skia/skia/src/gpu/GrOvalRenderer.cpp | 1772 ++++++----- gfx/skia/skia/src/gpu/GrOvalRenderer.h | 28 +- gfx/skia/skia/src/gpu/GrPaint.cpp | 43 +- gfx/skia/skia/src/gpu/GrPath.cpp | 222 +- gfx/skia/skia/src/gpu/GrPath.h | 17 +- gfx/skia/skia/src/gpu/GrPathProcessor.cpp | 81 +- gfx/skia/skia/src/gpu/GrPathProcessor.h | 2 - gfx/skia/skia/src/gpu/GrPathRange.cpp | 4 +- gfx/skia/skia/src/gpu/GrPathRenderer.h | 167 +- gfx/skia/skia/src/gpu/GrPathRendererChain.cpp | 60 +- gfx/skia/skia/src/gpu/GrPathRendererChain.h | 7 +- gfx/skia/skia/src/gpu/GrPathRendering.cpp | 54 +- gfx/skia/skia/src/gpu/GrPathRendering.h | 37 +- .../src/gpu/GrPathRenderingDrawContext.cpp | 11 +- .../skia/src/gpu/GrPathRenderingDrawContext.h | 8 +- gfx/skia/skia/src/gpu/GrPathUtils.cpp | 10 +- gfx/skia/skia/src/gpu/GrPathUtils.h | 2 +- .../skia/src/gpu/GrPendingProgramElement.h | 2 +- gfx/skia/skia/src/gpu/GrPipeline.cpp | 137 +- gfx/skia/skia/src/gpu/GrPipeline.h | 37 +- gfx/skia/skia/src/gpu/GrPipelineBuilder.cpp | 44 +- gfx/skia/skia/src/gpu/GrPipelineBuilder.h | 169 +- .../skia/src/gpu/GrPrimitiveProcessor.cpp | 6 +- gfx/skia/skia/src/gpu/GrPrimitiveProcessor.h | 15 +- gfx/skia/skia/src/gpu/GrProcessor.cpp | 24 +- gfx/skia/skia/src/gpu/GrProcessorUnitTest.cpp | 8 +- .../GrGLProgramDesc.cpp => GrProgramDesc.cpp} | 110 +- gfx/skia/skia/src/gpu/GrProgramDesc.h | 85 +- gfx/skia/skia/src/gpu/GrProgramElement.cpp | 1 + gfx/skia/skia/src/gpu/GrQuad.h | 4 +- gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp | 226 -- gfx/skia/skia/src/gpu/GrRecordReplaceDraw.h | 26 - gfx/skia/skia/src/gpu/GrRectanizer_pow2.h | 1 + gfx/skia/skia/src/gpu/GrReducedClip.cpp | 839 ++++-- gfx/skia/skia/src/gpu/GrReducedClip.h | 100 +- gfx/skia/skia/src/gpu/GrRenderTarget.cpp | 25 +- gfx/skia/skia/src/gpu/GrRenderTargetPriv.h | 8 + gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp | 98 + gfx/skia/skia/src/gpu/GrResourceCache.cpp | 212 +- gfx/skia/skia/src/gpu/GrResourceCache.h | 77 +- gfx/skia/skia/src/gpu/GrResourceHandle.h | 36 + gfx/skia/skia/src/gpu/GrResourceProvider.cpp | 68 +- gfx/skia/skia/src/gpu/GrResourceProvider.h | 20 +- gfx/skia/skia/src/gpu/GrSWMaskHelper.cpp | 313 +- gfx/skia/skia/src/gpu/GrSWMaskHelper.h | 112 +- gfx/skia/skia/src/gpu/GrScissorState.h | 40 + gfx/skia/skia/src/gpu/GrShape.cpp | 540 ++++ gfx/skia/skia/src/gpu/GrShape.h | 463 +++ .../skia/src/gpu/GrSoftwarePathRenderer.cpp | 235 +- .../skia/src/gpu/GrSoftwarePathRenderer.h | 28 +- gfx/skia/skia/src/gpu/GrStencil.cpp | 403 --- gfx/skia/skia/src/gpu/GrStencil.h | 402 --- gfx/skia/skia/src/gpu/GrStencilAttachment.h | 17 +- gfx/skia/skia/src/gpu/GrStencilSettings.cpp | 489 +++ gfx/skia/skia/src/gpu/GrStencilSettings.h | 121 + gfx/skia/skia/src/gpu/GrStrokeInfo.cpp | 93 - gfx/skia/skia/src/gpu/GrStrokeInfo.h | 191 -- gfx/skia/skia/src/gpu/GrStyle.cpp | 199 ++ gfx/skia/skia/src/gpu/GrStyle.h | 213 ++ gfx/skia/skia/src/gpu/GrSurface.cpp | 21 +- gfx/skia/skia/src/gpu/GrSurfacePriv.h | 5 - ...TexturePixelRef.cpp => GrSurfaceProxy.cpp} | 5 +- gfx/skia/skia/src/gpu/GrTessellator.cpp | 705 +++-- gfx/skia/skia/src/gpu/GrTessellator.h | 12 +- gfx/skia/skia/src/gpu/GrTestUtils.cpp | 110 +- gfx/skia/skia/src/gpu/GrTexture.cpp | 25 +- gfx/skia/skia/src/gpu/GrTextureAccess.cpp | 13 +- .../skia/src/gpu/GrTextureParamsAdjuster.cpp | 163 +- .../skia/src/gpu/GrTextureParamsAdjuster.h | 48 +- gfx/skia/skia/src/gpu/GrTexturePriv.h | 9 +- gfx/skia/skia/src/gpu/GrTextureProvider.cpp | 8 +- gfx/skia/skia/src/gpu/GrTextureProxy.cpp | 51 + .../skia/src/gpu/GrTextureToYUVPlanes.cpp | 173 +- gfx/skia/skia/src/gpu/GrTraceMarker.h | 2 +- gfx/skia/skia/src/gpu/GrUserStencilSettings.h | 239 ++ gfx/skia/skia/src/gpu/GrWindowRectangles.h | 101 + gfx/skia/skia/src/gpu/GrWindowRectsState.h | 60 + gfx/skia/skia/src/gpu/GrXferProcessor.cpp | 14 +- gfx/skia/skia/src/gpu/GrYUVProvider.cpp | 66 +- gfx/skia/skia/src/gpu/GrYUVProvider.h | 2 +- gfx/skia/skia/src/gpu/SkGpuDevice.cpp | 1352 ++++----- gfx/skia/skia/src/gpu/SkGpuDevice.h | 200 +- .../skia/src/gpu/SkGpuDevice_drawTexture.cpp | 49 +- gfx/skia/skia/src/gpu/SkGr.cpp | 312 +- gfx/skia/skia/src/gpu/SkGrPixelRef.cpp | 215 -- gfx/skia/skia/src/gpu/SkGrPriv.h | 38 +- .../gpu/batches/GrAAConvexPathRenderer.cpp | 126 +- .../src/gpu/batches/GrAAConvexTessellator.cpp | 162 +- .../src/gpu/batches/GrAAConvexTessellator.h | 78 +- .../batches/GrAADistanceFieldPathRenderer.cpp | 385 ++- .../batches/GrAADistanceFieldPathRenderer.h | 68 +- .../src/gpu/batches/GrAAFillRectBatch.cpp | 357 ++- .../skia/src/gpu/batches/GrAAFillRectBatch.h | 13 - .../gpu/batches/GrAAHairLinePathRenderer.cpp | 142 +- .../GrAALinearizingConvexPathRenderer.cpp | 177 +- .../src/gpu/batches/GrAAStrokeRectBatch.cpp | 282 +- .../src/gpu/batches/GrAAStrokeRectBatch.h | 8 +- .../src/gpu/batches/GrAnalyticRectBatch.cpp | 409 +++ .../src/gpu/batches/GrAnalyticRectBatch.h | 36 + .../skia/src/gpu/batches/GrAtlasTextBatch.cpp | 112 +- .../skia/src/gpu/batches/GrAtlasTextBatch.h | 24 +- gfx/skia/skia/src/gpu/batches/GrBatch.cpp | 10 +- gfx/skia/skia/src/gpu/batches/GrBatch.h | 93 +- gfx/skia/skia/src/gpu/batches/GrClearBatch.h | 111 +- .../src/gpu/batches/GrClearStencilClipBatch.h | 64 + .../skia/src/gpu/batches/GrCopySurfaceBatch.h | 18 +- .../gpu/batches/GrDashLinePathRenderer.cpp | 38 +- .../src/gpu/batches/GrDashLinePathRenderer.h | 2 +- .../src/gpu/batches/GrDefaultPathRenderer.cpp | 346 +-- .../src/gpu/batches/GrDefaultPathRenderer.h | 13 +- .../skia/src/gpu/batches/GrDiscardBatch.h | 12 +- .../skia/src/gpu/batches/GrDrawAtlasBatch.cpp | 39 +- .../skia/src/gpu/batches/GrDrawAtlasBatch.h | 23 +- gfx/skia/skia/src/gpu/batches/GrDrawBatch.h | 16 +- .../skia/src/gpu/batches/GrDrawPathBatch.cpp | 25 +- .../skia/src/gpu/batches/GrDrawPathBatch.h | 40 +- .../src/gpu/batches/GrDrawVerticesBatch.cpp | 92 +- .../src/gpu/batches/GrDrawVerticesBatch.h | 39 +- .../src/gpu/batches/GrMSAAPathRenderer.cpp | 716 +++++ .../skia/src/gpu/batches/GrMSAAPathRenderer.h | 35 + gfx/skia/skia/src/gpu/batches/GrNinePatch.cpp | 105 +- gfx/skia/skia/src/gpu/batches/GrNinePatch.h | 4 +- .../src/gpu/batches/GrNonAAFillRectBatch.cpp | 340 +-- .../src/gpu/batches/GrNonAAFillRectBatch.h | 6 - .../GrNonAAFillRectPerspectiveBatch.cpp | 270 ++ .../gpu/batches/GrNonAAStrokeRectBatch.cpp | 193 +- .../src/gpu/batches/GrNonAAStrokeRectBatch.h | 11 +- .../src/gpu/batches/GrPLSPathRenderer.cpp | 365 +-- .../src/gpu/batches/GrPathStencilSettings.h | 160 + .../skia/src/gpu/batches/GrRectBatchFactory.h | 16 +- .../skia/src/gpu/batches/GrRegionBatch.cpp | 167 ++ gfx/skia/skia/src/gpu/batches/GrRegionBatch.h | 25 + .../batches/GrStencilAndCoverPathRenderer.cpp | 155 +- .../batches/GrStencilAndCoverPathRenderer.h | 2 +- .../skia/src/gpu/batches/GrStencilPathBatch.h | 18 +- .../skia/src/gpu/batches/GrTInstanceBatch.h | 151 - .../batches/GrTessellatingPathRenderer.cpp | 309 +- .../gpu/batches/GrTessellatingPathRenderer.h | 2 +- gfx/skia/skia/src/gpu/batches/GrTestBatch.h | 3 +- .../skia/src/gpu/batches/GrVertexBatch.cpp | 4 +- .../skia/src/gpu/effects/Gr1DKernelEffect.h | 4 +- .../skia/src/gpu/effects/GrBezierEffect.cpp | 91 +- .../skia/src/gpu/effects/GrBezierEffect.h | 79 +- .../skia/src/gpu/effects/GrBicubicEffect.cpp | 44 +- .../skia/src/gpu/effects/GrBicubicEffect.h | 55 +- .../src/gpu/effects/GrBitmapTextGeoProc.cpp | 39 +- .../src/gpu/effects/GrBitmapTextGeoProc.h | 5 +- .../gpu/effects/GrConfigConversionEffect.cpp | 151 +- .../gpu/effects/GrConfigConversionEffect.h | 4 +- .../src/gpu/effects/GrConstColorProcessor.cpp | 6 +- .../src/gpu/effects/GrConvexPolyEffect.cpp | 73 +- .../skia/src/gpu/effects/GrConvexPolyEffect.h | 12 +- .../src/gpu/effects/GrConvolutionEffect.cpp | 18 +- .../src/gpu/effects/GrConvolutionEffect.h | 30 +- .../src/gpu/effects/GrCoverageSetOpXP.cpp | 37 +- .../skia/src/gpu/effects/GrCustomXfermode.cpp | 15 +- .../skia/src/gpu/effects/GrDashingEffect.cpp | 266 +- .../skia/src/gpu/effects/GrDashingEffect.h | 16 +- .../skia/src/gpu/effects/GrDisableColorXP.cpp | 6 +- .../skia/src/gpu/effects/GrDisableColorXP.h | 7 +- .../gpu/effects/GrDistanceFieldGeoProc.cpp | 197 +- .../src/gpu/effects/GrDistanceFieldGeoProc.h | 68 +- .../skia/src/gpu/effects/GrDitherEffect.cpp | 12 +- .../skia/src/gpu/effects/GrDitherEffect.h | 3 +- .../skia/src/gpu/effects/GrGammaEffect.cpp | 148 + gfx/skia/skia/src/gpu/effects/GrGammaEffect.h | 47 + .../gpu/effects/GrMatrixConvolutionEffect.cpp | 55 +- .../gpu/effects/GrMatrixConvolutionEffect.h | 43 +- .../skia/src/gpu/effects/GrOvalEffect.cpp | 41 +- gfx/skia/skia/src/gpu/effects/GrOvalEffect.h | 3 +- .../gpu/effects/GrPorterDuffXferProcessor.cpp | 63 +- .../skia/src/gpu/effects/GrRRectEffect.cpp | 55 +- gfx/skia/skia/src/gpu/effects/GrRRectEffect.h | 3 +- .../src/gpu/effects/GrSimpleTextureEffect.cpp | 40 +- .../src/gpu/effects/GrSimpleTextureEffect.h | 49 +- .../src/gpu/effects/GrSingleTextureEffect.cpp | 27 +- .../src/gpu/effects/GrSingleTextureEffect.h | 16 +- .../skia/src/gpu/effects/GrTextureDomain.cpp | 240 +- .../skia/src/gpu/effects/GrTextureDomain.h | 69 +- .../src/gpu/effects/GrTextureStripAtlas.cpp | 4 + .../effects/GrXfermodeFragmentProcessor.cpp | 64 +- gfx/skia/skia/src/gpu/effects/GrYUVEffect.cpp | 117 +- gfx/skia/skia/src/gpu/effects/GrYUVEffect.h | 20 +- .../skia/src/gpu/gl/GrGLAssembleInterface.cpp | 61 +- gfx/skia/skia/src/gpu/gl/GrGLBuffer.cpp | 110 +- gfx/skia/skia/src/gpu/gl/GrGLBuffer.h | 19 +- gfx/skia/skia/src/gpu/gl/GrGLCaps.cpp | 195 +- gfx/skia/skia/src/gpu/gl/GrGLCaps.h | 22 +- .../src/gpu/gl/GrGLCreateNullInterface.cpp | 625 ++-- gfx/skia/skia/src/gpu/gl/GrGLDefines.h | 13 + gfx/skia/skia/src/gpu/gl/GrGLGpu.cpp | 1140 ++++--- gfx/skia/skia/src/gpu/gl/GrGLGpu.h | 174 +- .../skia/src/gpu/gl/GrGLGpuCommandBuffer.h | 58 + .../skia/src/gpu/gl/GrGLGpuProgramCache.cpp | 14 +- gfx/skia/skia/src/gpu/gl/GrGLIRect.h | 21 +- gfx/skia/skia/src/gpu/gl/GrGLInterface.cpp | 55 +- gfx/skia/skia/src/gpu/gl/GrGLPath.cpp | 46 +- gfx/skia/skia/src/gpu/gl/GrGLPath.h | 5 +- gfx/skia/skia/src/gpu/gl/GrGLPathRange.cpp | 59 +- gfx/skia/skia/src/gpu/gl/GrGLPathRange.h | 8 +- .../skia/src/gpu/gl/GrGLPathRendering.cpp | 65 +- gfx/skia/skia/src/gpu/gl/GrGLPathRendering.h | 7 +- gfx/skia/skia/src/gpu/gl/GrGLProgram.cpp | 101 +- gfx/skia/skia/src/gpu/gl/GrGLProgram.h | 30 +- .../src/gpu/gl/GrGLProgramDataManager.cpp | 57 +- .../skia/src/gpu/gl/GrGLProgramDataManager.h | 12 +- gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h | 64 - gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.cpp | 66 +- gfx/skia/skia/src/gpu/gl/GrGLRenderTarget.h | 32 +- gfx/skia/skia/src/gpu/gl/GrGLSampler.h | 45 + .../skia/src/gpu/gl/GrGLStencilAttachment.cpp | 2 +- .../skia/src/gpu/gl/GrGLStencilAttachment.h | 15 +- .../skia/src/gpu/gl/GrGLTestInterface.cpp | 4 + gfx/skia/skia/src/gpu/gl/GrGLTestInterface.h | 8 +- gfx/skia/skia/src/gpu/gl/GrGLTexture.cpp | 55 +- gfx/skia/skia/src/gpu/gl/GrGLTexture.h | 26 +- .../src/gpu/gl/GrGLTextureRenderTarget.cpp | 15 +- .../skia/src/gpu/gl/GrGLTextureRenderTarget.h | 25 +- .../skia/src/gpu/gl/GrGLUniformHandler.cpp | 36 +- gfx/skia/skia/src/gpu/gl/GrGLUniformHandler.h | 14 + gfx/skia/skia/src/gpu/gl/GrGLUtil.cpp | 51 +- gfx/skia/skia/src/gpu/gl/GrGLUtil.h | 7 +- gfx/skia/skia/src/gpu/gl/GrGLVertexArray.cpp | 20 +- gfx/skia/skia/src/gpu/gl/GrGLVertexArray.h | 6 +- .../gpu/gl/builders/GrGLProgramBuilder.cpp | 13 +- .../src/gpu/gl/builders/GrGLProgramBuilder.h | 6 +- .../gl/builders/GrGLShaderStringBuilder.cpp | 24 +- .../gl/glx/GrGLCreateNativeInterface_glx.cpp | 6 + .../gl/win/GrGLCreateNativeInterface_win.cpp | 4 +- gfx/skia/skia/src/gpu/glsl/GrGLSL.h | 36 +- gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.cpp | 64 +- gfx/skia/skia/src/gpu/glsl/GrGLSLCaps.h | 33 +- .../gpu/glsl/GrGLSLColorSpaceXformHelper.h | 40 + .../src/gpu/glsl/GrGLSLFragmentProcessor.cpp | 70 +- .../src/gpu/glsl/GrGLSLFragmentProcessor.h | 122 +- .../gpu/glsl/GrGLSLFragmentShaderBuilder.cpp | 35 +- .../gpu/glsl/GrGLSLFragmentShaderBuilder.h | 19 +- .../src/gpu/glsl/GrGLSLGeometryProcessor.cpp | 122 +- .../src/gpu/glsl/GrGLSLGeometryProcessor.h | 57 +- .../src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp | 20 +- .../src/gpu/glsl/GrGLSLPrimitiveProcessor.h | 99 +- .../skia/src/gpu/glsl/GrGLSLProcessorTypes.h | 20 - .../src/gpu/glsl/GrGLSLProgramBuilder.cpp | 165 +- .../skia/src/gpu/glsl/GrGLSLProgramBuilder.h | 30 +- .../src/gpu/glsl/GrGLSLProgramDataManager.cpp | 8 + .../src/gpu/glsl/GrGLSLProgramDataManager.h | 33 +- gfx/skia/skia/src/gpu/glsl/GrGLSLSampler.h | 45 + .../skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp | 131 +- .../skia/src/gpu/glsl/GrGLSLShaderBuilder.h | 54 +- gfx/skia/skia/src/gpu/glsl/GrGLSLShaderVar.h | 22 +- .../skia/src/gpu/glsl/GrGLSLTextureSampler.h | 35 - .../skia/src/gpu/glsl/GrGLSLUniformHandler.h | 22 + .../gpu/glsl/GrGLSLVertexShaderBuilder.cpp | 6 +- .../skia/src/gpu/glsl/GrGLSLXferProcessor.cpp | 18 +- .../skia/src/gpu/glsl/GrGLSLXferProcessor.h | 14 +- .../gpu/instanced/GLInstancedRendering.cpp | 324 ++ .../src/gpu/instanced/GLInstancedRendering.h | 66 + .../src/gpu/instanced/InstanceProcessor.cpp | 2123 +++++++++++++ .../src/gpu/instanced/InstanceProcessor.h | 70 + .../src/gpu/instanced/InstancedRendering.cpp | 496 ++++ .../src/gpu/instanced/InstancedRendering.h | 185 ++ .../gpu/instanced/InstancedRenderingTypes.h | 192 ++ .../skia/src/gpu/text/GrAtlasTextBlob.cpp | 61 +- gfx/skia/skia/src/gpu/text/GrAtlasTextBlob.h | 43 +- .../gpu/text/GrAtlasTextBlob_regenInBatch.cpp | 51 +- .../skia/src/gpu/text/GrAtlasTextContext.cpp | 90 +- .../skia/src/gpu/text/GrAtlasTextContext.h | 17 +- .../skia/src/gpu/text/GrBatchFontCache.cpp | 202 +- gfx/skia/skia/src/gpu/text/GrBatchFontCache.h | 82 +- .../gpu/text/GrDistanceFieldAdjustTable.cpp | 15 +- .../src/gpu/text/GrDistanceFieldAdjustTable.h | 14 +- gfx/skia/skia/src/gpu/text/GrFontScaler.cpp | 206 -- gfx/skia/skia/src/gpu/text/GrFontScaler.h | 69 - .../gpu/text/GrStencilAndCoverTextContext.cpp | 193 +- .../gpu/text/GrStencilAndCoverTextContext.h | 39 +- gfx/skia/skia/src/gpu/text/GrTextUtils.cpp | 97 +- gfx/skia/skia/src/gpu/text/GrTextUtils.h | 15 +- .../skia/src/gpu/vk/GrVkBackendContext.cpp | 88 +- gfx/skia/skia/src/gpu/vk/GrVkBuffer.cpp | 157 +- gfx/skia/skia/src/gpu/vk/GrVkBuffer.h | 59 +- gfx/skia/skia/src/gpu/vk/GrVkCaps.cpp | 73 +- gfx/skia/skia/src/gpu/vk/GrVkCaps.h | 48 +- .../skia/src/gpu/vk/GrVkCommandBuffer.cpp | 702 +++-- gfx/skia/skia/src/gpu/vk/GrVkCommandBuffer.h | 290 +- gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp | 405 +++ gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h | 55 + gfx/skia/skia/src/gpu/vk/GrVkCopyPipeline.cpp | 190 ++ gfx/skia/skia/src/gpu/vk/GrVkCopyPipeline.h | 43 + gfx/skia/skia/src/gpu/vk/GrVkDescriptorPool.h | 9 +- .../skia/src/gpu/vk/GrVkDescriptorSet.cpp | 34 + gfx/skia/skia/src/gpu/vk/GrVkDescriptorSet.h | 44 + .../src/gpu/vk/GrVkDescriptorSetManager.cpp | 315 ++ .../src/gpu/vk/GrVkDescriptorSetManager.h | 95 + gfx/skia/skia/src/gpu/vk/GrVkExtensions.cpp | 18 +- gfx/skia/skia/src/gpu/vk/GrVkFramebuffer.cpp | 4 - gfx/skia/skia/src/gpu/vk/GrVkFramebuffer.h | 7 +- gfx/skia/skia/src/gpu/vk/GrVkGLSLSampler.h | 49 + gfx/skia/skia/src/gpu/vk/GrVkGpu.cpp | 1782 ++++++----- gfx/skia/skia/src/gpu/vk/GrVkGpu.h | 147 +- .../skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp | 450 +++ .../skia/src/gpu/vk/GrVkGpuCommandBuffer.h | 71 + gfx/skia/skia/src/gpu/vk/GrVkImage.cpp | 107 +- gfx/skia/skia/src/gpu/vk/GrVkImage.h | 121 +- gfx/skia/skia/src/gpu/vk/GrVkImageView.cpp | 16 +- gfx/skia/skia/src/gpu/vk/GrVkImageView.h | 9 +- gfx/skia/skia/src/gpu/vk/GrVkIndexBuffer.cpp | 4 +- gfx/skia/skia/src/gpu/vk/GrVkInterface.cpp | 57 - gfx/skia/skia/src/gpu/vk/GrVkMemory.cpp | 590 +++- gfx/skia/skia/src/gpu/vk/GrVkMemory.h | 142 +- gfx/skia/skia/src/gpu/vk/GrVkPipeline.cpp | 215 +- gfx/skia/skia/src/gpu/vk/GrVkPipeline.h | 15 +- .../skia/src/gpu/vk/GrVkPipelineState.cpp | 196 +- gfx/skia/skia/src/gpu/vk/GrVkPipelineState.h | 122 +- .../src/gpu/vk/GrVkPipelineStateBuilder.cpp | 173 +- .../src/gpu/vk/GrVkPipelineStateBuilder.h | 5 +- .../src/gpu/vk/GrVkPipelineStateCache.cpp | 26 +- .../gpu/vk/GrVkPipelineStateDataManager.cpp | 73 +- .../src/gpu/vk/GrVkPipelineStateDataManager.h | 8 +- gfx/skia/skia/src/gpu/vk/GrVkProgramDesc.cpp | 168 -- gfx/skia/skia/src/gpu/vk/GrVkProgramDesc.h | 69 - gfx/skia/skia/src/gpu/vk/GrVkRenderPass.cpp | 169 +- gfx/skia/skia/src/gpu/vk/GrVkRenderPass.h | 67 +- gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.cpp | 236 +- gfx/skia/skia/src/gpu/vk/GrVkRenderTarget.h | 95 +- gfx/skia/skia/src/gpu/vk/GrVkResource.h | 65 +- .../skia/src/gpu/vk/GrVkResourceProvider.cpp | 378 ++- .../skia/src/gpu/vk/GrVkResourceProvider.h | 143 +- gfx/skia/skia/src/gpu/vk/GrVkSampler.cpp | 25 +- gfx/skia/skia/src/gpu/vk/GrVkSampler.h | 19 +- .../skia/src/gpu/vk/GrVkStencilAttachment.cpp | 29 +- .../skia/src/gpu/vk/GrVkStencilAttachment.h | 8 +- gfx/skia/skia/src/gpu/vk/GrVkTexture.cpp | 242 +- gfx/skia/skia/src/gpu/vk/GrVkTexture.h | 34 +- .../src/gpu/vk/GrVkTextureRenderTarget.cpp | 192 +- .../skia/src/gpu/vk/GrVkTextureRenderTarget.h | 85 +- .../skia/src/gpu/vk/GrVkTransferBuffer.cpp | 6 +- .../skia/src/gpu/vk/GrVkUniformBuffer.cpp | 94 +- gfx/skia/skia/src/gpu/vk/GrVkUniformBuffer.h | 40 +- .../skia/src/gpu/vk/GrVkUniformHandler.cpp | 133 +- gfx/skia/skia/src/gpu/vk/GrVkUniformHandler.h | 17 +- gfx/skia/skia/src/gpu/vk/GrVkUtil.cpp | 225 +- gfx/skia/skia/src/gpu/vk/GrVkUtil.h | 15 +- .../skia/src/gpu/vk/GrVkVaryingHandler.cpp | 71 +- gfx/skia/skia/src/gpu/vk/GrVkVertexBuffer.cpp | 4 +- gfx/skia/skia/src/image/SkImage.cpp | 136 +- gfx/skia/skia/src/image/SkImagePriv.h | 62 - gfx/skia/skia/src/image/SkImageShader.cpp | 184 +- gfx/skia/skia/src/image/SkImageShader.h | 22 +- gfx/skia/skia/src/image/SkImage_Base.h | 31 +- gfx/skia/skia/src/image/SkImage_Generator.cpp | 18 +- gfx/skia/skia/src/image/SkImage_Gpu.cpp | 570 ++-- gfx/skia/skia/src/image/SkImage_Gpu.h | 22 +- gfx/skia/skia/src/image/SkImage_Raster.cpp | 118 +- gfx/skia/skia/src/image/SkSurface.cpp | 14 +- gfx/skia/skia/src/image/SkSurface_Base.h | 8 +- gfx/skia/skia/src/image/SkSurface_Gpu.cpp | 156 +- gfx/skia/skia/src/image/SkSurface_Gpu.h | 11 +- gfx/skia/skia/src/image/SkSurface_Raster.cpp | 30 +- .../skia/src/images/SkARGBImageEncoder.cpp | 117 - gfx/skia/skia/src/images/SkForceLinking.cpp | 18 +- gfx/skia/skia/src/images/SkImageEncoder.cpp | 2 +- .../skia/src/images/SkJPEGImageEncoder.cpp | 130 +- .../skia/src/images/SkKTXImageEncoder.cpp | 6 +- gfx/skia/skia/src/images/SkMovie.cpp | 4 +- .../skia/src/images/SkPNGImageEncoder.cpp | 238 +- gfx/skia/skia/src/images/transform_scanline.h | 129 +- .../skia/src/lazy/SkDiscardableMemoryPool.cpp | 12 +- gfx/skia/skia/src/opts/SkBlend_opts.h | 187 ++ gfx/skia/skia/src/opts/SkBlitRow_opts.h | 34 +- .../skia/src/opts/SkBlitRow_opts_mips_dsp.cpp | 42 +- .../skia/src/opts/SkBlurImageFilter_opts.h | 9 +- gfx/skia/skia/src/opts/SkChecksum_opts.h | 216 ++ .../skia/src/opts/SkColorCubeFilter_opts.h | 14 +- gfx/skia/skia/src/opts/SkMatrix_opts.h | 106 - gfx/skia/skia/src/opts/SkNx_neon.h | 187 +- gfx/skia/skia/src/opts/SkNx_sse.h | 195 +- gfx/skia/skia/src/opts/SkOpts_avx.cpp | 14 + gfx/skia/skia/src/opts/SkOpts_crc32.cpp | 17 + gfx/skia/skia/src/opts/SkOpts_hsw.cpp | 15 + gfx/skia/skia/src/opts/SkOpts_neon.cpp | 5 - gfx/skia/skia/src/opts/SkOpts_sse2.cpp | 42 - gfx/skia/skia/src/opts/SkOpts_sse41.cpp | 278 +- gfx/skia/skia/src/opts/SkOpts_sse42.cpp | 18 + gfx/skia/skia/src/opts/SkOpts_ssse3.cpp | 28 +- .../skia/src/opts/SkRasterPipeline_opts.h | 358 +++ gfx/skia/skia/src/opts/SkSwizzler_opts.h | 6 + .../skia/src/opts/SkTextureCompressor_opts.h | 23 +- gfx/skia/skia/src/opts/opts_check_x86.cpp | 123 +- .../skia/src/pathops/SkAddIntersections.cpp | 42 +- .../skia/src/pathops/SkAddIntersections.h | 3 +- .../src/pathops/SkDConicLineIntersection.cpp | 43 +- .../src/pathops/SkDCubicLineIntersection.cpp | 23 +- .../src/pathops/SkDQuadLineIntersection.cpp | 26 +- .../skia/src/pathops/SkIntersectionHelper.h | 5 + gfx/skia/skia/src/pathops/SkIntersections.h | 16 +- gfx/skia/skia/src/pathops/SkOpAngle.cpp | 192 +- gfx/skia/skia/src/pathops/SkOpAngle.h | 71 +- gfx/skia/skia/src/pathops/SkOpBuilder.cpp | 33 +- gfx/skia/skia/src/pathops/SkOpCoincidence.cpp | 1527 +++++++--- gfx/skia/skia/src/pathops/SkOpCoincidence.h | 297 +- gfx/skia/skia/src/pathops/SkOpContour.cpp | 24 +- gfx/skia/skia/src/pathops/SkOpContour.h | 185 +- gfx/skia/skia/src/pathops/SkOpEdgeBuilder.cpp | 173 +- gfx/skia/skia/src/pathops/SkOpEdgeBuilder.h | 19 +- gfx/skia/skia/src/pathops/SkOpSegment.cpp | 714 ++--- gfx/skia/skia/src/pathops/SkOpSegment.h | 153 +- gfx/skia/skia/src/pathops/SkOpSpan.cpp | 400 ++- gfx/skia/skia/src/pathops/SkOpSpan.h | 162 +- gfx/skia/skia/src/pathops/SkPathOpsBounds.h | 14 +- gfx/skia/skia/src/pathops/SkPathOpsCommon.cpp | 425 +-- gfx/skia/skia/src/pathops/SkPathOpsCommon.h | 15 +- gfx/skia/skia/src/pathops/SkPathOpsConic.cpp | 5 +- gfx/skia/skia/src/pathops/SkPathOpsCubic.cpp | 20 +- gfx/skia/skia/src/pathops/SkPathOpsCurve.cpp | 108 +- gfx/skia/skia/src/pathops/SkPathOpsCurve.h | 92 +- gfx/skia/skia/src/pathops/SkPathOpsDebug.cpp | 2333 +++++++++++---- gfx/skia/skia/src/pathops/SkPathOpsDebug.h | 189 +- gfx/skia/skia/src/pathops/SkPathOpsOp.cpp | 99 +- gfx/skia/skia/src/pathops/SkPathOpsPoint.h | 45 +- gfx/skia/skia/src/pathops/SkPathOpsQuad.cpp | 43 +- .../skia/src/pathops/SkPathOpsSimplify.cpp | 94 +- gfx/skia/skia/src/pathops/SkPathOpsTSect.cpp | 36 +- gfx/skia/skia/src/pathops/SkPathOpsTSect.h | 296 +- .../skia/src/pathops/SkPathOpsTightBounds.cpp | 60 +- gfx/skia/skia/src/pathops/SkPathOpsTypes.cpp | 32 +- gfx/skia/skia/src/pathops/SkPathOpsTypes.h | 117 +- .../skia/src/pathops/SkPathOpsWinding.cpp | 17 +- gfx/skia/skia/src/pathops/SkPathWriter.cpp | 408 ++- gfx/skia/skia/src/pathops/SkPathWriter.h | 53 +- gfx/skia/skia/src/pathops/SkReduceOrder.cpp | 15 +- gfx/skia/skia/src/pathops/SkReduceOrder.h | 4 +- gfx/skia/skia/src/pdf/SkBitmapKey.h | 84 +- gfx/skia/skia/src/pdf/SkDeflate.cpp | 10 +- gfx/skia/skia/src/pdf/SkDeflate.h | 2 - gfx/skia/skia/src/pdf/SkDocument_PDF_None.cpp | 12 +- gfx/skia/skia/src/pdf/SkPDFBitmap.cpp | 76 +- gfx/skia/skia/src/pdf/SkPDFBitmap.h | 4 +- gfx/skia/skia/src/pdf/SkPDFCanon.cpp | 110 +- gfx/skia/skia/src/pdf/SkPDFCanon.h | 52 +- gfx/skia/skia/src/pdf/SkPDFCanvas.cpp | 70 +- gfx/skia/skia/src/pdf/SkPDFCanvas.h | 17 + .../src/pdf/SkPDFConvertType1FontStream.cpp | 205 ++ .../src/pdf/SkPDFConvertType1FontStream.h | 28 + gfx/skia/skia/src/pdf/SkPDFDevice.cpp | 1510 +++++----- gfx/skia/skia/src/pdf/SkPDFDevice.h | 103 +- gfx/skia/skia/src/pdf/SkPDFDocument.cpp | 446 ++- gfx/skia/skia/src/pdf/SkPDFDocument.h | 37 +- gfx/skia/skia/src/pdf/SkPDFFont.cpp | 1771 ++++------- gfx/skia/skia/src/pdf/SkPDFFont.h | 178 +- gfx/skia/skia/src/pdf/SkPDFFontImpl.h | 89 - gfx/skia/skia/src/pdf/SkPDFFormXObject.cpp | 74 +- gfx/skia/skia/src/pdf/SkPDFFormXObject.h | 48 +- gfx/skia/skia/src/pdf/SkPDFGraphicState.cpp | 127 +- gfx/skia/skia/src/pdf/SkPDFGraphicState.h | 16 +- .../src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp | 262 ++ .../src/pdf/SkPDFMakeCIDGlyphWidthsArray.h | 23 + .../skia/src/pdf/SkPDFMakeToUnicodeCmap.cpp | 225 ++ .../skia/src/pdf/SkPDFMakeToUnicodeCmap.h | 29 + gfx/skia/skia/src/pdf/SkPDFMetadata.cpp | 222 +- gfx/skia/skia/src/pdf/SkPDFMetadata.h | 27 +- gfx/skia/skia/src/pdf/SkPDFResourceDict.cpp | 7 +- gfx/skia/skia/src/pdf/SkPDFResourceDict.h | 8 +- gfx/skia/skia/src/pdf/SkPDFShader.cpp | 806 ++--- gfx/skia/skia/src/pdf/SkPDFShader.h | 85 +- gfx/skia/skia/src/pdf/SkPDFStream.cpp | 69 - gfx/skia/skia/src/pdf/SkPDFStream.h | 66 - gfx/skia/skia/src/pdf/SkPDFTypes.cpp | 227 +- gfx/skia/skia/src/pdf/SkPDFTypes.h | 132 +- gfx/skia/skia/src/pdf/SkPDFUtils.cpp | 218 +- gfx/skia/skia/src/pdf/SkPDFUtils.h | 107 +- gfx/skia/skia/src/pdf/SkScopeExit.h | 50 + gfx/skia/skia/src/pipe/SkPipeCanvas.cpp | 1069 +++++++ gfx/skia/skia/src/pipe/SkPipeCanvas.h | 170 ++ gfx/skia/skia/src/pipe/SkPipeFormat.h | 220 ++ gfx/skia/skia/src/pipe/SkPipeReader.cpp | 962 ++++++ gfx/skia/skia/src/pipe/SkRefSet.h | 40 + gfx/skia/skia/src/ports/SkDebug_win.cpp | 8 +- .../skia/src/ports/SkFontConfigInterface.cpp | 30 + .../ports/SkFontConfigInterface_direct.cpp | 277 +- .../src/ports/SkFontConfigInterface_direct.h | 10 +- .../SkFontConfigInterface_direct_factory.cpp | 14 +- .../SkFontConfigInterface_direct_google3.cpp | 34 - .../SkFontConfigInterface_direct_google3.h | 26 - ...ConfigInterface_direct_google3_factory.cpp | 20 - .../skia/src/ports/SkFontConfigTypeface.h | 58 +- .../skia/src/ports/SkFontHost_FreeType.cpp | 460 ++- .../src/ports/SkFontHost_FreeType_common.cpp | 58 +- .../src/ports/SkFontHost_FreeType_common.h | 25 +- gfx/skia/skia/src/ports/SkFontHost_cairo.cpp | 33 +- .../skia/src/ports/SkFontHost_fontconfig.cpp | 236 -- gfx/skia/skia/src/ports/SkFontHost_mac.cpp | 455 ++- gfx/skia/skia/src/ports/SkFontHost_win.cpp | 81 +- .../ports/SkFontMgr_FontConfigInterface.cpp | 302 ++ .../SkFontMgr_FontConfigInterface_factory.cpp | 18 + gfx/skia/skia/src/ports/SkFontMgr_android.cpp | 181 +- .../src/ports/SkFontMgr_android_parser.cpp | 14 +- gfx/skia/skia/src/ports/SkFontMgr_custom.cpp | 186 +- .../skia/src/ports/SkFontMgr_fontconfig.cpp | 173 +- gfx/skia/skia/src/ports/SkFontMgr_win_dw.cpp | 100 +- .../ports/SkGlobalInitialization_default.cpp | 4 +- gfx/skia/skia/src/ports/SkImageEncoder_CG.cpp | 13 +- .../skia/src/ports/SkImageEncoder_WIC.cpp | 89 +- gfx/skia/skia/src/ports/SkImageGeneratorCG.h | 2 +- .../skia/src/ports/SkImageGeneratorWIC.cpp | 2 +- gfx/skia/skia/src/ports/SkImageGeneratorWIC.h | 2 +- gfx/skia/skia/src/ports/SkMemory_malloc.cpp | 4 + gfx/skia/skia/src/ports/SkOSEnvironment.cpp | 18 - gfx/skia/skia/src/ports/SkOSEnvironment.h | 13 - gfx/skia/skia/src/ports/SkOSFile_stdio.cpp | 11 +- gfx/skia/skia/src/ports/SkOSFile_win.cpp | 2 +- gfx/skia/skia/src/ports/SkOSLibrary_posix.cpp | 6 +- gfx/skia/skia/src/ports/SkOSLibrary_win.cpp | 2 +- .../src/ports/SkRemotableFontMgr_win_dw.cpp | 22 +- .../skia/src/ports/SkScalerContext_win_dw.cpp | 152 +- .../skia/src/ports/SkScalerContext_win_dw.h | 17 +- gfx/skia/skia/src/ports/SkTLS_pthread.cpp | 15 +- gfx/skia/skia/src/ports/SkTLS_win.cpp | 3 +- gfx/skia/skia/src/ports/SkTypeface_win_dw.cpp | 117 +- gfx/skia/skia/src/ports/SkTypeface_win_dw.h | 32 +- gfx/skia/skia/src/sfnt/SkIBMFamilyClass.h | 240 +- gfx/skia/skia/src/sfnt/SkOTTable_EBDT.h | 1 - gfx/skia/skia/src/sfnt/SkOTTable_EBLC.h | 14 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2.h | 10 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_V0.h | 47 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_V1.h | 47 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_V2.h | 46 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_V3.h | 47 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_V4.h | 47 +- gfx/skia/skia/src/sfnt/SkOTTable_OS_2_VA.h | 45 +- gfx/skia/skia/src/sfnt/SkOTTable_gasp.h | 1 - gfx/skia/skia/src/sfnt/SkOTTable_glyf.h | 1 - gfx/skia/skia/src/sfnt/SkOTTable_head.h | 32 +- gfx/skia/skia/src/sfnt/SkOTTable_hhea.h | 8 +- gfx/skia/skia/src/sfnt/SkOTTable_maxp_TT.h | 10 +- gfx/skia/skia/src/sfnt/SkOTTable_name.cpp | 2 +- gfx/skia/skia/src/sfnt/SkOTTable_name.h | 843 +++--- gfx/skia/skia/src/sfnt/SkOTTable_post.h | 16 +- gfx/skia/skia/src/sfnt/SkPanose.h | 940 +++--- gfx/skia/skia/src/sfnt/SkPreprocessorSeq.h | 826 ------ gfx/skia/skia/src/sfnt/SkTypedEnum.h | 68 - gfx/skia/skia/src/sksl/GLSL.std.450.h | 131 + gfx/skia/skia/src/sksl/SkSLCodeGenerator.h | 30 + gfx/skia/skia/src/sksl/SkSLCompiler.cpp | 269 ++ gfx/skia/skia/src/sksl/SkSLCompiler.h | 66 + gfx/skia/skia/src/sksl/SkSLContext.h | 227 ++ gfx/skia/skia/src/sksl/SkSLErrorReporter.h | 27 + .../skia/src/sksl/SkSLGLSLCodeGenerator.cpp | 480 +++ .../skia/src/sksl/SkSLGLSLCodeGenerator.h | 177 ++ gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp | 1260 ++++++++ gfx/skia/skia/src/sksl/SkSLIRGenerator.h | 123 + gfx/skia/skia/src/sksl/SkSLMain.cpp | 48 + gfx/skia/skia/src/sksl/SkSLParser.cpp | 1407 +++++++++ gfx/skia/skia/src/sksl/SkSLParser.h | 209 ++ gfx/skia/skia/src/sksl/SkSLPosition.h | 38 + .../skia/src/sksl/SkSLSPIRVCodeGenerator.cpp | 2638 +++++++++++++++++ .../skia/src/sksl/SkSLSPIRVCodeGenerator.h | 267 ++ gfx/skia/skia/src/sksl/SkSLToken.h | 162 + gfx/skia/skia/src/sksl/SkSLUtil.cpp | 33 + gfx/skia/skia/src/sksl/SkSLUtil.h | 57 + .../src/sksl/ast/SkSLASTBinaryExpression.h | 42 + gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h | 40 + .../skia/src/sksl/ast/SkSLASTBoolLiteral.h | 34 + .../skia/src/sksl/ast/SkSLASTBreakStatement.h | 31 + .../skia/src/sksl/ast/SkSLASTCallSuffix.h | 44 + .../src/sksl/ast/SkSLASTContinueStatement.h | 31 + .../skia/src/sksl/ast/SkSLASTDeclaration.h | 37 + .../src/sksl/ast/SkSLASTDiscardStatement.h | 31 + .../skia/src/sksl/ast/SkSLASTDoStatement.h | 37 + .../skia/src/sksl/ast/SkSLASTExpression.h | 41 + .../src/sksl/ast/SkSLASTExpressionStatement.h | 34 + gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h | 34 + .../skia/src/sksl/ast/SkSLASTFieldSuffix.h | 35 + .../skia/src/sksl/ast/SkSLASTFloatLiteral.h | 34 + .../skia/src/sksl/ast/SkSLASTForStatement.h | 56 + gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h | 57 + .../skia/src/sksl/ast/SkSLASTIdentifier.h | 34 + .../skia/src/sksl/ast/SkSLASTIfStatement.h | 47 + .../skia/src/sksl/ast/SkSLASTIndexSuffix.h | 35 + .../skia/src/sksl/ast/SkSLASTIntLiteral.h | 35 + .../skia/src/sksl/ast/SkSLASTInterfaceBlock.h | 58 + gfx/skia/skia/src/sksl/ast/SkSLASTLayout.h | 74 + gfx/skia/skia/src/sksl/ast/SkSLASTModifiers.h | 78 + gfx/skia/skia/src/sksl/ast/SkSLASTNode.h | 28 + gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h | 48 + .../skia/src/sksl/ast/SkSLASTPositionNode.h | 28 + .../src/sksl/ast/SkSLASTPrefixExpression.h | 37 + .../src/sksl/ast/SkSLASTReturnStatement.h | 39 + gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h | 46 + gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h | 51 + .../src/sksl/ast/SkSLASTSuffixExpression.h | 37 + .../src/sksl/ast/SkSLASTTernaryExpression.h | 41 + gfx/skia/skia/src/sksl/ast/SkSLASTType.h | 40 + .../skia/src/sksl/ast/SkSLASTVarDeclaration.h | 88 + .../sksl/ast/SkSLASTVarDeclarationStatement.h | 35 + .../skia/src/sksl/ast/SkSLASTWhileStatement.h | 37 + .../skia/src/sksl/ir/SkSLBinaryExpression.h | 41 + gfx/skia/skia/src/sksl/ir/SkSLBlock.h | 44 + gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h | 39 + .../skia/src/sksl/ir/SkSLBreakStatement.h | 32 + gfx/skia/skia/src/sksl/ir/SkSLConstructor.h | 52 + .../skia/src/sksl/ir/SkSLContinueStatement.h | 32 + .../skia/src/sksl/ir/SkSLDiscardStatement.h | 32 + gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h | 38 + gfx/skia/skia/src/sksl/ir/SkSLExpression.h | 55 + .../src/sksl/ir/SkSLExpressionStatement.h | 35 + gfx/skia/skia/src/sksl/ir/SkSLExtension.h | 34 + gfx/skia/skia/src/sksl/ir/SkSLField.h | 41 + gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h | 47 + gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h | 39 + gfx/skia/skia/src/sksl/ir/SkSLForStatement.h | 59 + gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h | 46 + .../src/sksl/ir/SkSLFunctionDeclaration.h | 66 + .../skia/src/sksl/ir/SkSLFunctionDefinition.h | 39 + .../skia/src/sksl/ir/SkSLFunctionReference.h | 38 + gfx/skia/skia/src/sksl/ir/SkSLIRNode.h | 32 + gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h | 44 + .../skia/src/sksl/ir/SkSLIndexExpression.h | 65 + gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h | 40 + .../skia/src/sksl/ir/SkSLInterfaceBlock.h | 51 + gfx/skia/skia/src/sksl/ir/SkSLLayout.h | 92 + gfx/skia/skia/src/sksl/ir/SkSLModifiers.h | 90 + .../skia/src/sksl/ir/SkSLPostfixExpression.h | 36 + .../skia/src/sksl/ir/SkSLPrefixExpression.h | 36 + gfx/skia/skia/src/sksl/ir/SkSLProgram.h | 42 + .../skia/src/sksl/ir/SkSLProgramElement.h | 37 + .../skia/src/sksl/ir/SkSLReturnStatement.h | 42 + gfx/skia/skia/src/sksl/ir/SkSLStatement.h | 45 + gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h | 87 + gfx/skia/skia/src/sksl/ir/SkSLSymbol.h | 40 + gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp | 100 + gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h | 56 + .../skia/src/sksl/ir/SkSLTernaryExpression.h | 43 + gfx/skia/skia/src/sksl/ir/SkSLType.cpp | 135 + gfx/skia/skia/src/sksl/ir/SkSLType.h | 345 +++ gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h | 37 + .../skia/src/sksl/ir/SkSLUnresolvedFunction.h | 40 + .../skia/src/sksl/ir/SkSLVarDeclaration.h | 83 + .../src/sksl/ir/SkSLVarDeclarationStatement.h | 35 + gfx/skia/skia/src/sksl/ir/SkSLVariable.h | 55 + .../skia/src/sksl/ir/SkSLVariableReference.h | 38 + .../skia/src/sksl/ir/SkSLWhileStatement.h | 38 + gfx/skia/skia/src/sksl/lex.sksl.c | 2505 ++++++++++++++++ gfx/skia/skia/src/sksl/sksl.flex | 191 ++ gfx/skia/skia/src/sksl/sksl.include | 544 ++++ gfx/skia/skia/src/sksl/sksl_frag.include | 8 + gfx/skia/skia/src/sksl/sksl_vert.include | 11 + gfx/skia/skia/src/sksl/spirv.h | 870 ++++++ gfx/skia/skia/src/svg/SkSVGDevice.cpp | 31 +- gfx/skia/skia/src/svg/SkSVGDevice.h | 5 +- gfx/skia/skia/src/svg/parser/SkSVG.cpp | 28 - gfx/skia/skia/src/svg/parser/SkSVGCircle.cpp | 44 - gfx/skia/skia/src/svg/parser/SkSVGCircle.h | 23 - .../skia/src/svg/parser/SkSVGClipPath.cpp | 39 - gfx/skia/skia/src/svg/parser/SkSVGClipPath.h | 22 - gfx/skia/skia/src/svg/parser/SkSVGDefs.cpp | 23 - gfx/skia/skia/src/svg/parser/SkSVGDefs.h | 22 - .../skia/src/svg/parser/SkSVGElements.cpp | 85 - gfx/skia/skia/src/svg/parser/SkSVGElements.h | 72 - gfx/skia/skia/src/svg/parser/SkSVGEllipse.cpp | 46 - gfx/skia/skia/src/svg/parser/SkSVGEllipse.h | 24 - .../src/svg/parser/SkSVGFeColorMatrix.cpp | 23 - .../skia/src/svg/parser/SkSVGFeColorMatrix.h | 25 - gfx/skia/skia/src/svg/parser/SkSVGFilter.cpp | 24 - gfx/skia/skia/src/svg/parser/SkSVGFilter.h | 26 - gfx/skia/skia/src/svg/parser/SkSVGG.cpp | 15 - gfx/skia/skia/src/svg/parser/SkSVGG.h | 20 - .../skia/src/svg/parser/SkSVGGradient.cpp | 113 - gfx/skia/skia/src/svg/parser/SkSVGGradient.h | 28 - gfx/skia/skia/src/svg/parser/SkSVGGroup.cpp | 44 - gfx/skia/skia/src/svg/parser/SkSVGGroup.h | 27 - gfx/skia/skia/src/svg/parser/SkSVGImage.cpp | 43 - gfx/skia/skia/src/svg/parser/SkSVGImage.h | 27 - gfx/skia/skia/src/svg/parser/SkSVGLine.cpp | 29 - gfx/skia/skia/src/svg/parser/SkSVGLine.h | 24 - .../src/svg/parser/SkSVGLinearGradient.cpp | 43 - .../skia/src/svg/parser/SkSVGLinearGradient.h | 27 - gfx/skia/skia/src/svg/parser/SkSVGMask.cpp | 32 - gfx/skia/skia/src/svg/parser/SkSVGMask.h | 28 - .../skia/src/svg/parser/SkSVGMetadata.cpp | 23 - gfx/skia/skia/src/svg/parser/SkSVGMetadata.h | 22 - .../skia/src/svg/parser/SkSVGPaintState.cpp | 453 --- gfx/skia/skia/src/svg/parser/SkSVGParser.cpp | 440 --- gfx/skia/skia/src/svg/parser/SkSVGPath.cpp | 36 - gfx/skia/skia/src/svg/parser/SkSVGPath.h | 21 - gfx/skia/skia/src/svg/parser/SkSVGPolygon.cpp | 32 - gfx/skia/skia/src/svg/parser/SkSVGPolygon.h | 22 - .../skia/src/svg/parser/SkSVGPolyline.cpp | 42 - gfx/skia/skia/src/svg/parser/SkSVGPolyline.h | 26 - .../src/svg/parser/SkSVGRadialGradient.cpp | 41 - .../skia/src/svg/parser/SkSVGRadialGradient.h | 29 - gfx/skia/skia/src/svg/parser/SkSVGRect.cpp | 34 - gfx/skia/skia/src/svg/parser/SkSVGRect.h | 25 - gfx/skia/skia/src/svg/parser/SkSVGSVG.cpp | 72 - gfx/skia/skia/src/svg/parser/SkSVGSVG.h | 33 - gfx/skia/skia/src/svg/parser/SkSVGStop.cpp | 23 - gfx/skia/skia/src/svg/parser/SkSVGStop.h | 22 - gfx/skia/skia/src/svg/parser/SkSVGSymbol.cpp | 21 - gfx/skia/skia/src/svg/parser/SkSVGSymbol.h | 21 - gfx/skia/skia/src/svg/parser/SkSVGText.cpp | 38 - gfx/skia/skia/src/svg/parser/SkSVGText.h | 31 - gfx/skia/skia/src/svg/parser/SkSVGUse.cpp | 29 - gfx/skia/skia/src/svg/parser/SkSVGUse.h | 27 - gfx/skia/skia/src/utils/SkBitSet.cpp | 67 - gfx/skia/skia/src/utils/SkBitSet.h | 76 +- .../src/utils/SkBitmapSourceDeserializer.cpp | 10 +- gfx/skia/skia/src/utils/SkCanvasStack.cpp | 10 +- gfx/skia/skia/src/utils/SkCanvasStack.h | 8 +- .../skia/src/utils/SkCanvasStateUtils.cpp | 13 +- gfx/skia/skia/src/utils/SkCurveMeasure.cpp | 310 ++ gfx/skia/skia/src/utils/SkCurveMeasure.h | 76 + gfx/skia/skia/src/utils/SkDashPath.cpp | 9 +- gfx/skia/skia/src/utils/SkDashPathPriv.h | 18 +- gfx/skia/skia/src/utils/SkDeferredCanvas.cpp | 570 ++++ gfx/skia/skia/src/utils/SkDeferredCanvas.h | 156 + gfx/skia/skia/src/utils/SkDumpCanvas.cpp | 40 +- gfx/skia/skia/src/utils/SkEventTracer.cpp | 10 +- gfx/skia/skia/src/utils/SkLua.cpp | 176 +- gfx/skia/skia/src/utils/SkLuaCanvas.cpp | 26 +- gfx/skia/skia/src/utils/SkMD5.h | 61 - .../skia/src/utils/SkMultiPictureDocument.cpp | 91 + .../skia/src/utils/SkMultiPictureDocument.h | 48 + .../src/utils/SkMultiPictureDocumentPriv.h | 32 + .../utils/SkMultiPictureDocumentReader.cpp | 93 + .../src/utils/SkMultiPictureDocumentReader.h | 46 + gfx/skia/skia/src/utils/SkNWayCanvas.cpp | 24 +- gfx/skia/skia/src/utils/SkNinePatch.cpp | 333 --- .../skia/src/utils/SkPaintFilterCanvas.cpp | 17 + gfx/skia/skia/src/utils/SkParsePath.cpp | 2 +- gfx/skia/skia/src/utils/SkRGBAToYUV.cpp | 2 +- gfx/skia/skia/src/utils/SkRTConf.cpp | 325 -- .../src/utils/SkShadowPaintFilterCanvas.cpp | 307 ++ .../src/utils/SkShadowPaintFilterCanvas.h | 117 + gfx/skia/skia/src/utils/SkTextBox.cpp | 4 +- .../skia/src/utils/SkTextureCompressor.cpp | 8 +- gfx/skia/skia/src/utils/SkTextureCompressor.h | 5 +- .../src/utils/SkTextureCompressor_ASTC.cpp | 2 +- gfx/skia/skia/src/utils/SkThreadUtils_win.h | 3 +- ...Checksums.cpp => SkWhitelistChecksums.inc} | 2 +- .../skia/src/utils/SkWhitelistTypefaces.cpp | 51 +- .../skia/src/utils/mac/SkCreateCGImageRef.cpp | 65 - gfx/skia/skia/src/utils/mac/SkStream_mac.cpp | 16 +- .../skia/src/utils/win/SkAutoCoInitialize.cpp | 7 +- .../utils/win/SkAutoCoInitialize.h | 2 + gfx/skia/skia/src/utils/win/SkDWrite.cpp | 4 +- gfx/skia/skia/src/utils/win/SkDWrite.h | 19 +- .../{include => src}/utils/win/SkHRESULT.h | 16 +- gfx/skia/skia/src/utils/win/SkIStream.cpp | 3 - .../{include => src}/utils/win/SkIStream.h | 3 +- .../utils/win/SkTScopedComPtr.h | 28 +- gfx/skia/skia/src/utils/win/SkWGL.h | 17 +- gfx/skia/skia/src/utils/win/SkWGL_win.cpp | 57 +- gfx/skia/skia/src/views/SkTouchGesture.cpp | 26 +- gfx/skia/skia/src/views/SkWindow.cpp | 44 +- gfx/skia/skia/src/views/ios/SkOSWindow_iOS.mm | 1 + gfx/skia/skia/src/views/mac/SkNSView.mm | 50 +- gfx/skia/skia/src/views/mac/SkOSWindow_Mac.mm | 3 +- gfx/skia/skia/src/views/mac/skia_mac.mm | 30 +- .../skia/src/views/sdl/SkOSWindow_SDL.cpp | 3 +- .../skia/src/views/unix/SkOSWindow_Unix.cpp | 3 +- gfx/skia/skia/src/views/unix/skia_unix.cpp | 2 + .../skia/src/views/win/SkOSWindow_win.cpp | 112 +- gfx/skia/skia/src/views/win/skia_win.cpp | 7 +- gfx/skia/skia/src/xml/SkBML_Verbs.h | 24 - gfx/skia/skia/src/xml/SkBML_XMLParser.cpp | 180 -- gfx/skia/skia/src/xml/SkDOM.cpp | 41 +- gfx/skia/skia/src/xml/SkXMLParser.cpp | 119 +- gfx/skia/skia/src/xml/SkXMLPullParser.cpp | 137 - gfx/skia/skia/src/xps/SkConstexprMath.h | 54 - gfx/skia/skia/src/xps/SkDocument_XPS.cpp | 12 +- gfx/skia/skia/src/xps/SkDocument_XPS_None.cpp | 6 +- gfx/skia/skia/src/xps/SkXPSDevice.cpp | 58 +- 1398 files changed, 98444 insertions(+), 55387 deletions(-) create mode 100644 gfx/skia/skia/include/codec/SkEncodedInfo.h create mode 100644 gfx/skia/skia/include/core/SkBlendMode.h create mode 100644 gfx/skia/skia/include/core/SkClipOp.h create mode 100644 gfx/skia/skia/include/core/SkColorSpace.h delete mode 100644 gfx/skia/skia/include/core/SkFontHost.h create mode 100644 gfx/skia/skia/include/core/SkImageDeserializer.h create mode 100644 gfx/skia/skia/include/core/SkLights.h rename gfx/skia/skia/include/{utils => core}/SkMatrix44.h (93%) create mode 100644 gfx/skia/skia/include/core/SkPictureAnalyzer.h create mode 100644 gfx/skia/skia/include/effects/SkGammaColorFilter.h create mode 100644 gfx/skia/skia/include/effects/SkGaussianEdgeShader.h create mode 100644 gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h delete mode 100644 gfx/skia/skia/include/effects/SkTestImageFilters.h rename gfx/skia/skia/{src => include}/gpu/GrBuffer.h (59%) create mode 100644 gfx/skia/skia/include/gpu/GrBufferAccess.h create mode 100644 gfx/skia/skia/include/gpu/GrColorSpaceXform.h delete mode 100644 gfx/skia/skia/include/gpu/SkGrPixelRef.h delete mode 100644 gfx/skia/skia/include/gpu/SkGrTexturePixelRef.h mode change 100755 => 100644 gfx/skia/skia/include/gpu/vk/GrVkTypes.h delete mode 100644 gfx/skia/skia/include/ports/SkAtomics_atomic.h delete mode 100644 gfx/skia/skia/include/ports/SkAtomics_std.h delete mode 100644 gfx/skia/skia/include/ports/SkAtomics_sync.h create mode 100644 gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h create mode 100644 gfx/skia/skia/include/private/GrInstancedPipelineInfo.h create mode 100644 gfx/skia/skia/include/private/GrRenderTargetProxy.h create mode 100644 gfx/skia/skia/include/private/GrSurfaceProxy.h create mode 100644 gfx/skia/skia/include/private/GrTextureProxy.h rename gfx/skia/skia/{src/gpu/effects => include/private}/GrTextureStripAtlas.h (98%) create mode 100644 gfx/skia/skia/include/private/SkBitmaskEnum.h delete mode 100644 gfx/skia/skia/include/private/SkGpuFenceSync.h create mode 100644 gfx/skia/skia/include/private/SkLeanWindows.h delete mode 100644 gfx/skia/skia/include/private/SkOncePtr.h create mode 100644 gfx/skia/skia/include/private/SkShadowParams.h delete mode 100644 gfx/skia/skia/include/svg/parser/SkSVGAttribute.h delete mode 100644 gfx/skia/skia/include/svg/parser/SkSVGBase.h delete mode 100644 gfx/skia/skia/include/svg/parser/SkSVGPaintState.h delete mode 100644 gfx/skia/skia/include/svg/parser/SkSVGParser.h delete mode 100644 gfx/skia/skia/include/svg/parser/SkSVGTypes.h delete mode 100644 gfx/skia/skia/include/utils/SkJSONCPP.h delete mode 100644 gfx/skia/skia/include/utils/SkNinePatch.h delete mode 100644 gfx/skia/skia/include/utils/SkRTConf.h delete mode 100644 gfx/skia/skia/include/views/SkOSWindow_Android.h delete mode 100644 gfx/skia/skia/include/xml/SkBML_WXMLParser.h delete mode 100644 gfx/skia/skia/include/xml/SkBML_XMLParser.h delete mode 100644 gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp delete mode 100644 gfx/skia/skia/src/android/SkBitmapRegionCanvas.h rename gfx/skia/skia/src/animator/{SkCondensedDebug.cpp => SkCondensedDebug.inc} (100%) rename gfx/skia/skia/src/animator/{SkCondensedRelease.cpp => SkCondensedRelease.inc} (100%) delete mode 100644 gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.cpp delete mode 100644 gfx/skia/skia/src/core/SkBitmapHeap.cpp delete mode 100644 gfx/skia/skia/src/core/SkBitmapHeap.h create mode 100644 gfx/skia/skia/src/core/SkBlendModePriv.h rename gfx/skia/skia/src/{effects => core}/SkBlurImageFilter.cpp (68%) delete mode 100644 gfx/skia/skia/src/core/SkChecksum.cpp create mode 100644 gfx/skia/skia/src/core/SkColorShader.cpp delete mode 100644 gfx/skia/skia/src/core/SkColorSpace.h create mode 100644 gfx/skia/skia/src/core/SkColorSpacePriv.h create mode 100644 gfx/skia/skia/src/core/SkColorSpaceXform.cpp create mode 100644 gfx/skia/skia/src/core/SkColorSpaceXform.h create mode 100644 gfx/skia/skia/src/core/SkColorSpace_Base.h create mode 100644 gfx/skia/skia/src/core/SkColorSpace_ICC.cpp create mode 100644 gfx/skia/skia/src/core/SkCpu.cpp create mode 100644 gfx/skia/skia/src/core/SkCpu.h create mode 100644 gfx/skia/skia/src/core/SkDeduper.h create mode 100644 gfx/skia/skia/src/core/SkExchange.h delete mode 100644 gfx/skia/skia/src/core/SkFloatBits.cpp rename gfx/skia/skia/src/core/{SkFontHost.cpp => SkFontLCDConfig.cpp} (50%) create mode 100644 gfx/skia/skia/src/core/SkFuzzLogging.h create mode 100644 gfx/skia/skia/src/core/SkGpuBlurUtils.cpp create mode 100644 gfx/skia/skia/src/core/SkGpuBlurUtils.h create mode 100644 gfx/skia/skia/src/core/SkImageFilterCache.cpp create mode 100644 gfx/skia/skia/src/core/SkImageFilterCache.h delete mode 100644 gfx/skia/skia/src/core/SkImageFilterCacheKey.h create mode 100644 gfx/skia/skia/src/core/SkImagePriv.h create mode 100644 gfx/skia/skia/src/core/SkLatticeIter.cpp create mode 100644 gfx/skia/skia/src/core/SkLatticeIter.h delete mode 100644 gfx/skia/skia/src/core/SkLayerInfo.h delete mode 100644 gfx/skia/skia/src/core/SkLight.h create mode 100644 gfx/skia/skia/src/core/SkLights.cpp create mode 100644 gfx/skia/skia/src/core/SkLiteDL.cpp create mode 100644 gfx/skia/skia/src/core/SkLiteDL.h create mode 100644 gfx/skia/skia/src/core/SkLiteRecorder.cpp create mode 100644 gfx/skia/skia/src/core/SkLiteRecorder.h rename gfx/skia/skia/src/{utils => core}/SkMD5.cpp (94%) create mode 100644 gfx/skia/skia/src/core/SkMD5.h create mode 100644 gfx/skia/skia/src/core/SkMakeUnique.h rename gfx/skia/skia/src/{utils => core}/SkMatrix44.cpp (96%) create mode 100644 gfx/skia/skia/src/core/SkMatrixPriv.h delete mode 100644 gfx/skia/skia/src/core/SkNinePatchIter.cpp delete mode 100644 gfx/skia/skia/src/core/SkNinePatchIter.h create mode 100644 gfx/skia/skia/src/core/SkNormalBevelSource.cpp create mode 100644 gfx/skia/skia/src/core/SkNormalBevelSource.h create mode 100644 gfx/skia/skia/src/core/SkNormalFlatSource.cpp create mode 100644 gfx/skia/skia/src/core/SkNormalFlatSource.h create mode 100644 gfx/skia/skia/src/core/SkNormalMapSource.cpp create mode 100644 gfx/skia/skia/src/core/SkNormalMapSource.h create mode 100644 gfx/skia/skia/src/core/SkNormalSource.cpp create mode 100644 gfx/skia/skia/src/core/SkNormalSource.h create mode 100644 gfx/skia/skia/src/core/SkNormalSourcePriv.h create mode 100644 gfx/skia/skia/src/core/SkPathMeasurePriv.h create mode 100644 gfx/skia/skia/src/core/SkPictureAnalyzer.cpp create mode 100644 gfx/skia/skia/src/core/SkPipe.h create mode 100644 gfx/skia/skia/src/core/SkRadialShadowMapShader.cpp create mode 100644 gfx/skia/skia/src/core/SkRadialShadowMapShader.h create mode 100644 gfx/skia/skia/src/core/SkRasterPipeline.cpp create mode 100644 gfx/skia/skia/src/core/SkRasterPipeline.h create mode 100644 gfx/skia/skia/src/core/SkRasterPipelineBlitter.cpp create mode 100644 gfx/skia/skia/src/core/SkRecordedDrawable.cpp create mode 100644 gfx/skia/skia/src/core/SkRecordedDrawable.h create mode 100644 gfx/skia/skia/src/core/SkSRGB.cpp create mode 100644 gfx/skia/skia/src/core/SkSRGB.h create mode 100644 gfx/skia/skia/src/core/SkShadowShader.cpp create mode 100644 gfx/skia/skia/src/core/SkShadowShader.h rename gfx/skia/skia/src/{pdf => core}/SkSinglyLinkedList.h (95%) create mode 100644 gfx/skia/skia/src/core/SkXfermodeF16.cpp delete mode 100644 gfx/skia/skia/src/core/SkXfermodeU64.cpp create mode 100644 gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.cpp create mode 100644 gfx/skia/skia/src/effects/GrAlphaThresholdFragmentProcessor.h create mode 100644 gfx/skia/skia/src/effects/SkArithmeticModePriv.h create mode 100644 gfx/skia/skia/src/effects/SkGammaColorFilter.cpp create mode 100644 gfx/skia/skia/src/effects/SkGaussianEdgeShader.cpp delete mode 100644 gfx/skia/skia/src/effects/SkGpuBlurUtils.cpp delete mode 100644 gfx/skia/skia/src/effects/SkGpuBlurUtils.h create mode 100644 gfx/skia/skia/src/effects/SkRRectsGaussianEdgeShader.cpp delete mode 100755 gfx/skia/skia/src/effects/SkTestImageFilters.cpp delete mode 100644 gfx/skia/skia/src/fonts/SkFontMgr_fontconfig.cpp create mode 100644 gfx/skia/skia/src/gpu/GrAppliedClip.h create mode 100644 gfx/skia/skia/src/gpu/GrBuffer.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrClip.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrClipMaskManager.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrClipMaskManager.h create mode 100644 gfx/skia/skia/src/gpu/GrClipStackClip.cpp create mode 100644 gfx/skia/skia/src/gpu/GrClipStackClip.h create mode 100644 gfx/skia/skia/src/gpu/GrColorSpaceXform.cpp create mode 100644 gfx/skia/skia/src/gpu/GrContextPriv.h create mode 100644 gfx/skia/skia/src/gpu/GrFixedClip.cpp create mode 100644 gfx/skia/skia/src/gpu/GrFixedClip.h create mode 100644 gfx/skia/skia/src/gpu/GrGpuCommandBuffer.cpp create mode 100644 gfx/skia/skia/src/gpu/GrGpuCommandBuffer.h delete mode 100644 gfx/skia/skia/src/gpu/GrLayerAtlas.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrLayerAtlas.h delete mode 100644 gfx/skia/skia/src/gpu/GrLayerCache.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrLayerCache.h delete mode 100644 gfx/skia/skia/src/gpu/GrLayerHoister.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrLayerHoister.h rename gfx/skia/skia/src/gpu/{gl/GrGLProgramDesc.cpp => GrProgramDesc.cpp} (63%) delete mode 100644 gfx/skia/skia/src/gpu/GrRecordReplaceDraw.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrRecordReplaceDraw.h create mode 100644 gfx/skia/skia/src/gpu/GrRenderTargetProxy.cpp create mode 100644 gfx/skia/skia/src/gpu/GrResourceHandle.h create mode 100644 gfx/skia/skia/src/gpu/GrScissorState.h create mode 100644 gfx/skia/skia/src/gpu/GrShape.cpp create mode 100644 gfx/skia/skia/src/gpu/GrShape.h delete mode 100644 gfx/skia/skia/src/gpu/GrStencil.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrStencil.h create mode 100644 gfx/skia/skia/src/gpu/GrStencilSettings.cpp create mode 100644 gfx/skia/skia/src/gpu/GrStencilSettings.h delete mode 100644 gfx/skia/skia/src/gpu/GrStrokeInfo.cpp delete mode 100644 gfx/skia/skia/src/gpu/GrStrokeInfo.h create mode 100644 gfx/skia/skia/src/gpu/GrStyle.cpp create mode 100644 gfx/skia/skia/src/gpu/GrStyle.h rename gfx/skia/skia/src/gpu/{SkGrTexturePixelRef.cpp => GrSurfaceProxy.cpp} (64%) create mode 100644 gfx/skia/skia/src/gpu/GrTextureProxy.cpp create mode 100644 gfx/skia/skia/src/gpu/GrUserStencilSettings.h create mode 100644 gfx/skia/skia/src/gpu/GrWindowRectangles.h create mode 100644 gfx/skia/skia/src/gpu/GrWindowRectsState.h delete mode 100644 gfx/skia/skia/src/gpu/SkGrPixelRef.cpp create mode 100644 gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.cpp create mode 100644 gfx/skia/skia/src/gpu/batches/GrAnalyticRectBatch.h create mode 100644 gfx/skia/skia/src/gpu/batches/GrClearStencilClipBatch.h create mode 100644 gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.cpp create mode 100644 gfx/skia/skia/src/gpu/batches/GrMSAAPathRenderer.h create mode 100644 gfx/skia/skia/src/gpu/batches/GrNonAAFillRectPerspectiveBatch.cpp create mode 100644 gfx/skia/skia/src/gpu/batches/GrPathStencilSettings.h create mode 100644 gfx/skia/skia/src/gpu/batches/GrRegionBatch.cpp create mode 100644 gfx/skia/skia/src/gpu/batches/GrRegionBatch.h delete mode 100644 gfx/skia/skia/src/gpu/batches/GrTInstanceBatch.h create mode 100644 gfx/skia/skia/src/gpu/effects/GrGammaEffect.cpp create mode 100644 gfx/skia/skia/src/gpu/effects/GrGammaEffect.h create mode 100644 gfx/skia/skia/src/gpu/gl/GrGLGpuCommandBuffer.h delete mode 100644 gfx/skia/skia/src/gpu/gl/GrGLProgramDesc.h create mode 100644 gfx/skia/skia/src/gpu/gl/GrGLSampler.h create mode 100644 gfx/skia/skia/src/gpu/glsl/GrGLSLColorSpaceXformHelper.h delete mode 100644 gfx/skia/skia/src/gpu/glsl/GrGLSLProcessorTypes.h create mode 100644 gfx/skia/skia/src/gpu/glsl/GrGLSLSampler.h delete mode 100644 gfx/skia/skia/src/gpu/glsl/GrGLSLTextureSampler.h create mode 100644 gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.cpp create mode 100644 gfx/skia/skia/src/gpu/instanced/GLInstancedRendering.h create mode 100644 gfx/skia/skia/src/gpu/instanced/InstanceProcessor.cpp create mode 100644 gfx/skia/skia/src/gpu/instanced/InstanceProcessor.h create mode 100644 gfx/skia/skia/src/gpu/instanced/InstancedRendering.cpp create mode 100644 gfx/skia/skia/src/gpu/instanced/InstancedRendering.h create mode 100644 gfx/skia/skia/src/gpu/instanced/InstancedRenderingTypes.h delete mode 100644 gfx/skia/skia/src/gpu/text/GrFontScaler.cpp delete mode 100644 gfx/skia/skia/src/gpu/text/GrFontScaler.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkCopyManager.cpp create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkCopyManager.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkCopyPipeline.cpp create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkCopyPipeline.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkDescriptorSet.cpp create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkDescriptorSet.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.cpp create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkDescriptorSetManager.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkGLSLSampler.h create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.cpp create mode 100644 gfx/skia/skia/src/gpu/vk/GrVkGpuCommandBuffer.h delete mode 100644 gfx/skia/skia/src/gpu/vk/GrVkProgramDesc.cpp delete mode 100644 gfx/skia/skia/src/gpu/vk/GrVkProgramDesc.h delete mode 100644 gfx/skia/skia/src/image/SkImagePriv.h delete mode 100644 gfx/skia/skia/src/images/SkARGBImageEncoder.cpp create mode 100644 gfx/skia/skia/src/opts/SkBlend_opts.h create mode 100644 gfx/skia/skia/src/opts/SkChecksum_opts.h delete mode 100644 gfx/skia/skia/src/opts/SkMatrix_opts.h create mode 100644 gfx/skia/skia/src/opts/SkOpts_avx.cpp create mode 100644 gfx/skia/skia/src/opts/SkOpts_crc32.cpp create mode 100644 gfx/skia/skia/src/opts/SkOpts_hsw.cpp delete mode 100644 gfx/skia/skia/src/opts/SkOpts_sse2.cpp create mode 100644 gfx/skia/skia/src/opts/SkOpts_sse42.cpp create mode 100644 gfx/skia/skia/src/opts/SkRasterPipeline_opts.h create mode 100644 gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.cpp create mode 100644 gfx/skia/skia/src/pdf/SkPDFConvertType1FontStream.h delete mode 100644 gfx/skia/skia/src/pdf/SkPDFFontImpl.h create mode 100644 gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp create mode 100644 gfx/skia/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h create mode 100644 gfx/skia/skia/src/pdf/SkPDFMakeToUnicodeCmap.cpp create mode 100644 gfx/skia/skia/src/pdf/SkPDFMakeToUnicodeCmap.h delete mode 100644 gfx/skia/skia/src/pdf/SkPDFStream.cpp delete mode 100644 gfx/skia/skia/src/pdf/SkPDFStream.h create mode 100644 gfx/skia/skia/src/pdf/SkScopeExit.h create mode 100644 gfx/skia/skia/src/pipe/SkPipeCanvas.cpp create mode 100644 gfx/skia/skia/src/pipe/SkPipeCanvas.h create mode 100644 gfx/skia/skia/src/pipe/SkPipeFormat.h create mode 100644 gfx/skia/skia/src/pipe/SkPipeReader.cpp create mode 100644 gfx/skia/skia/src/pipe/SkRefSet.h create mode 100644 gfx/skia/skia/src/ports/SkFontConfigInterface.cpp delete mode 100644 gfx/skia/skia/src/ports/SkFontConfigInterface_direct_google3.cpp delete mode 100644 gfx/skia/skia/src/ports/SkFontConfigInterface_direct_google3.h delete mode 100644 gfx/skia/skia/src/ports/SkFontConfigInterface_direct_google3_factory.cpp delete mode 100644 gfx/skia/skia/src/ports/SkFontHost_fontconfig.cpp create mode 100644 gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface.cpp create mode 100644 gfx/skia/skia/src/ports/SkFontMgr_FontConfigInterface_factory.cpp delete mode 100644 gfx/skia/skia/src/ports/SkOSEnvironment.cpp delete mode 100644 gfx/skia/skia/src/ports/SkOSEnvironment.h delete mode 100644 gfx/skia/skia/src/sfnt/SkPreprocessorSeq.h delete mode 100644 gfx/skia/skia/src/sfnt/SkTypedEnum.h create mode 100644 gfx/skia/skia/src/sksl/GLSL.std.450.h create mode 100644 gfx/skia/skia/src/sksl/SkSLCodeGenerator.h create mode 100644 gfx/skia/skia/src/sksl/SkSLCompiler.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLCompiler.h create mode 100644 gfx/skia/skia/src/sksl/SkSLContext.h create mode 100644 gfx/skia/skia/src/sksl/SkSLErrorReporter.h create mode 100644 gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLGLSLCodeGenerator.h create mode 100644 gfx/skia/skia/src/sksl/SkSLIRGenerator.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLIRGenerator.h create mode 100644 gfx/skia/skia/src/sksl/SkSLMain.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLParser.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLParser.h create mode 100644 gfx/skia/skia/src/sksl/SkSLPosition.h create mode 100644 gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLSPIRVCodeGenerator.h create mode 100644 gfx/skia/skia/src/sksl/SkSLToken.h create mode 100644 gfx/skia/skia/src/sksl/SkSLUtil.cpp create mode 100644 gfx/skia/skia/src/sksl/SkSLUtil.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTBinaryExpression.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTBlock.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTBoolLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTBreakStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTCallSuffix.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTContinueStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTDeclaration.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTDiscardStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTDoStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTExpression.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTExpressionStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTExtension.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTFieldSuffix.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTFloatLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTForStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTFunction.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTIdentifier.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTIfStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTIndexSuffix.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTIntLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTInterfaceBlock.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTLayout.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTModifiers.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTNode.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTParameter.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTPositionNode.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTPrefixExpression.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTReturnStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTSuffix.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTSuffixExpression.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTTernaryExpression.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTType.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclaration.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTVarDeclarationStatement.h create mode 100644 gfx/skia/skia/src/sksl/ast/SkSLASTWhileStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLBinaryExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLBlock.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLBoolLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLBreakStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLConstructor.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLContinueStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLDiscardStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLDoStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLExpressionStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLExtension.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLField.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFieldAccess.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFloatLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLForStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFunctionCall.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFunctionDeclaration.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFunctionDefinition.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLFunctionReference.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLIRNode.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLIfStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLIndexExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLIntLiteral.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLInterfaceBlock.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLLayout.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLModifiers.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLPostfixExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLPrefixExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLProgram.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLProgramElement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLReturnStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLSwizzle.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLSymbol.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.cpp create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLSymbolTable.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLTernaryExpression.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLType.cpp create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLType.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLTypeReference.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLUnresolvedFunction.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLVarDeclaration.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLVarDeclarationStatement.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLVariable.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLVariableReference.h create mode 100644 gfx/skia/skia/src/sksl/ir/SkSLWhileStatement.h create mode 100644 gfx/skia/skia/src/sksl/lex.sksl.c create mode 100644 gfx/skia/skia/src/sksl/sksl.flex create mode 100644 gfx/skia/skia/src/sksl/sksl.include create mode 100644 gfx/skia/skia/src/sksl/sksl_frag.include create mode 100644 gfx/skia/skia/src/sksl/sksl_vert.include create mode 100644 gfx/skia/skia/src/sksl/spirv.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVG.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGCircle.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGCircle.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGClipPath.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGClipPath.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGDefs.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGDefs.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGElements.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGElements.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGEllipse.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGEllipse.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGFeColorMatrix.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGFeColorMatrix.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGFilter.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGFilter.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGG.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGG.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGGradient.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGGradient.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGGroup.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGGroup.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGImage.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGImage.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGLine.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGLine.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGLinearGradient.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGLinearGradient.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGMask.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGMask.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGMetadata.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGMetadata.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPaintState.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGParser.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPath.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPath.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPolygon.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPolygon.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPolyline.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGPolyline.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGRadialGradient.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGRadialGradient.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGRect.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGRect.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGSVG.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGSVG.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGStop.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGStop.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGSymbol.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGSymbol.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGText.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGText.h delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGUse.cpp delete mode 100644 gfx/skia/skia/src/svg/parser/SkSVGUse.h delete mode 100755 gfx/skia/skia/src/utils/SkBitSet.cpp create mode 100644 gfx/skia/skia/src/utils/SkCurveMeasure.cpp create mode 100644 gfx/skia/skia/src/utils/SkCurveMeasure.h create mode 100644 gfx/skia/skia/src/utils/SkDeferredCanvas.cpp create mode 100644 gfx/skia/skia/src/utils/SkDeferredCanvas.h delete mode 100644 gfx/skia/skia/src/utils/SkMD5.h create mode 100644 gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp create mode 100644 gfx/skia/skia/src/utils/SkMultiPictureDocument.h create mode 100644 gfx/skia/skia/src/utils/SkMultiPictureDocumentPriv.h create mode 100644 gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.cpp create mode 100644 gfx/skia/skia/src/utils/SkMultiPictureDocumentReader.h delete mode 100644 gfx/skia/skia/src/utils/SkNinePatch.cpp delete mode 100644 gfx/skia/skia/src/utils/SkRTConf.cpp create mode 100644 gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.cpp create mode 100644 gfx/skia/skia/src/utils/SkShadowPaintFilterCanvas.h rename gfx/skia/skia/src/utils/{SkWhitelistChecksums.cpp => SkWhitelistChecksums.inc} (97%) rename gfx/skia/skia/{include => src}/utils/win/SkAutoCoInitialize.h (95%) rename gfx/skia/skia/{include => src}/utils/win/SkHRESULT.h (80%) rename gfx/skia/skia/{include => src}/utils/win/SkIStream.h (98%) rename gfx/skia/skia/{include => src}/utils/win/SkTScopedComPtr.h (73%) delete mode 100644 gfx/skia/skia/src/xml/SkBML_Verbs.h delete mode 100644 gfx/skia/skia/src/xml/SkBML_XMLParser.cpp delete mode 100644 gfx/skia/skia/src/xml/SkXMLPullParser.cpp delete mode 100644 gfx/skia/skia/src/xps/SkConstexprMath.h diff --git a/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h b/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h index 575ad9dc01a1..b8922d469771 100644 --- a/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h +++ b/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h @@ -21,7 +21,6 @@ class SkBitmapRegionDecoder { public: enum Strategy { - kCanvas_Strategy, // Draw to the canvas, uses SkCodec kAndroidCodec_Strategy, // Uses SkAndroidCodec for scaling and subsetting }; @@ -30,8 +29,7 @@ public: * @param strategy Strategy used for scaling and subsetting * @return Tries to create an SkBitmapRegionDecoder, returns NULL on failure */ - static SkBitmapRegionDecoder* Create( - SkData* data, Strategy strategy); + static SkBitmapRegionDecoder* Create(sk_sp, Strategy strategy); /* * @param stream Takes ownership of the stream diff --git a/gfx/skia/skia/include/c/sk_types.h b/gfx/skia/skia/include/c/sk_types.h index 41dd2715b064..baa3ac9ce6ec 100644 --- a/gfx/skia/skia/include/c/sk_types.h +++ b/gfx/skia/skia/include/c/sk_types.h @@ -23,8 +23,20 @@ #define SK_C_PLUS_PLUS_END_GUARD #endif -#ifndef SK_API -#define SK_API +#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 /////////////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/include/codec/SkAndroidCodec.h b/gfx/skia/skia/include/codec/SkAndroidCodec.h index 7fee5be255f5..c7587b62e98a 100644 --- a/gfx/skia/skia/include/codec/SkAndroidCodec.h +++ b/gfx/skia/skia/include/codec/SkAndroidCodec.h @@ -37,10 +37,11 @@ public: * * The SkPngChunkReader handles unknown chunks in PNGs. * See SkCodec.h for more details. - * - * Will take a ref if it returns a codec, else will not affect the data. */ - static SkAndroidCodec* NewFromData(SkData*, SkPngChunkReader* = NULL); + static SkAndroidCodec* NewFromData(sk_sp, SkPngChunkReader* = NULL); + static SkAndroidCodec* NewFromData(SkData* data, SkPngChunkReader* reader) { + return NewFromData(sk_ref_sp(data), reader); + } virtual ~SkAndroidCodec() {} diff --git a/gfx/skia/skia/include/codec/SkCodec.h b/gfx/skia/skia/include/codec/SkCodec.h index 629274d21cca..363347dd72c0 100644 --- a/gfx/skia/skia/include/codec/SkCodec.h +++ b/gfx/skia/skia/include/codec/SkCodec.h @@ -11,6 +11,7 @@ #include "../private/SkTemplates.h" #include "SkColor.h" #include "SkEncodedFormat.h" +#include "SkEncodedInfo.h" #include "SkImageInfo.h" #include "SkSize.h" #include "SkStream.h" @@ -22,6 +23,12 @@ class SkData; class SkPngChunkReader; class SkSampler; +namespace DM { +class CodecSrc; +class ColorCodecSrc; +} +class ColorCodecBench; + /** * Abstraction layer directly on top of an image codec. */ @@ -88,10 +95,11 @@ public: * failure to decode the image. * If the PNG does not contain unknown chunks, the SkPngChunkReader * will not be used or modified. - * - * Will take a ref if it returns a codec, else will not affect the data. */ - static SkCodec* NewFromData(SkData*, SkPngChunkReader* = NULL); + static SkCodec* NewFromData(sk_sp, SkPngChunkReader* = NULL); + static SkCodec* NewFromData(SkData* data, SkPngChunkReader* reader) { + return NewFromData(sk_ref_sp(data), reader); + } virtual ~SkCodec(); @@ -100,12 +108,7 @@ public: */ const SkImageInfo& getInfo() const { return fSrcInfo; } - /** - * Returns the color space associated with the codec. - * Does not affect ownership. - * Might be NULL. - */ - SkColorSpace* getColorSpace() const { return fColorSpace.get(); } + const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; } enum Origin { kTopLeft_Origin = 1, // Default @@ -250,8 +253,8 @@ public: * If the EncodedFormat is kWEBP_SkEncodedFormat (the only one which * currently supports subsets), the top and left values must be even. * - * In getPixels, we will attempt to decode the exact rectangular - * subset specified by fSubset. + * 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 @@ -284,6 +287,12 @@ public: * 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 info is kIndex8_SkColorType, then the caller must provide storage for up to 256 * SkPMColor values in ctable. On success the generator must copy N colors into that storage, * (where N is the logical number of table entries) and set ctableCount to N. @@ -345,6 +354,67 @@ public: 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. + * @param ctable A pointer to a color table. When dstInfo.colorType() is + * kIndex8, this should be non-NULL and have enough storage for 256 + * colors. The color table will be populated after decoding the palette. + * @param ctableCount A pointer to the size of the color table. When + * dstInfo.colorType() is kIndex8, this should be non-NULL. It will + * be modified to the true size of the color table (<= 256) after + * decoding the palette. + * @return Enum representing success or reason for failure. + */ + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + const SkCodec::Options*, SkPMColor* ctable, int* ctableCount); + + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, + const SkCodec::Options* options) { + return this->startIncrementalDecode(dstInfo, dst, rowBytes, options, nullptr, nullptr); + } + + Result startIncrementalDecode(const SkImageInfo& dstInfo, void* dst, size_t rowBytes) { + return this->startIncrementalDecode(dstInfo, dst, rowBytes, nullptr, nullptr, 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. */ @@ -465,17 +535,6 @@ public: * Interlaced gifs are an example. */ kOutOfOrder_SkScanlineOrder, - - /* - * Indicates that the entire image must be decoded in order to output - * any amount of scanlines. In this case, it is a REALLY BAD IDEA to - * request scanlines 1-by-1 or in small chunks. The client should - * determine which scanlines are needed and ask for all of them in - * a single call to getScanlines(). - * - * Interlaced pngs are an example. - */ - kNone_SkScanlineOrder, }; /** @@ -511,11 +570,22 @@ protected: /** * Takes ownership of SkStream* */ - SkCodec(const SkImageInfo&, + SkCodec(int width, + int height, + const SkEncodedInfo&, SkStream*, sk_sp = nullptr, Origin = kTopLeft_Origin); + /** + * Takes ownership of SkStream* + * Allows the subclass to set the recommended SkImageInfo + */ + SkCodec(const SkEncodedInfo&, + const SkImageInfo&, + SkStream*, + Origin = kTopLeft_Origin); + virtual SkISize onGetScaledDimensions(float /*desiredScale*/) const { // By default, scaling is not supported. return this->getInfo().dimensions(); @@ -581,30 +651,30 @@ protected: * On an incomplete input, getPixels() and getScanlines() will fill any uninitialized * scanlines. This allows the subclass to indicate what value to fill with. * - * @param colorType Destination color type. + * @param dstInfo Describes the destination. * @return The value with which to fill uninitialized pixels. * - * Note that we can interpret the return value as an SkPMColor, a 16-bit 565 color, - * an 8-bit gray color, or an 8-bit index into a color table, depending on the color - * type. + * Note that we can interpret the return value as a 64-bit Float16 color, a SkPMColor, + * a 16-bit 565 color, an 8-bit gray color, or an 8-bit index into a color table, + * depending on the color type. */ - uint32_t getFillValue(SkColorType colorType) const { - return this->onGetFillValue(colorType); + uint64_t getFillValue(const SkImageInfo& dstInfo) const { + return this->onGetFillValue(dstInfo); } /** * Some subclasses will override this function, but this is a useful default for the color - * types that we support. Note that for color types that do not use the full 32-bits, + * types that we support. Note that for color types that do not use the full 64-bits, * we will simply take the low bits of the fill value. * + * The defaults are: + * kRGBA_F16_SkColorType: Transparent or Black, depending on the src alpha type * kN32_SkColorType: Transparent or Black, depending on the src alpha type * kRGB_565_SkColorType: Black * kGray_8_SkColorType: Black * kIndex_8_SkColorType: First color in color table */ - virtual uint32_t onGetFillValue(SkColorType /*colorType*/) const { - return kOpaque_SkAlphaType == fSrcInfo.alphaType() ? SK_ColorBLACK : SK_ColorTRANSPARENT; - } + virtual uint64_t onGetFillValue(const SkImageInfo& dstInfo) const; /** * Get method for the input stream @@ -622,11 +692,6 @@ protected: */ virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; } - /** - * Update the current scanline. Used by interlaced png. - */ - void updateCurrScanline(int newY) { fCurrScanline = newY; } - const SkImageInfo& dstInfo() const { return fDstInfo; } const SkCodec::Options& options() const { return fOptions; } @@ -641,18 +706,26 @@ protected: virtual int onOutputScanline(int inputScanline) const; + /** + * Used for testing with qcms. + * FIXME: Remove this when we are done comparing with qcms. + */ + virtual sk_sp getICCData() const { return nullptr; } private: + const SkEncodedInfo fEncodedInfo; const SkImageInfo fSrcInfo; SkAutoTDelete fStream; bool fNeedsRewind; - sk_sp fColorSpace; const Origin fOrigin; - // These fields are only meaningful during scanline decodes. SkImageInfo fDstInfo; SkCodec::Options fOptions; + + // Only meaningful during scanline decodes. int fCurrScanline; + bool fStartedIncrementalDecode; + /** * Return whether these dimensions are supported as a scale. * @@ -672,6 +745,16 @@ private: return kUnimplemented; } + virtual Result onStartIncrementalDecode(const SkImageInfo& /*dstInfo*/, void*, size_t, + const SkCodec::Options&, SkPMColor*, int*) { + 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; } @@ -703,6 +786,12 @@ private: */ virtual SkSampler* getSampler(bool /*createIfNecessary*/) { return nullptr; } + // For testing with qcms + // FIXME: Remove these when we are done comparing with qcms. + friend class DM::ColorCodecSrc; + friend class ColorCodecBench; + + friend class DM::CodecSrc; // for fillIncompleteImage friend class SkSampledCodec; friend class SkIcoCodec; }; diff --git a/gfx/skia/skia/include/codec/SkEncodedInfo.h b/gfx/skia/skia/include/codec/SkEncodedInfo.h new file mode 100644 index 000000000000..eb8c147a3b70 --- /dev/null +++ b/gfx/skia/skia/include/codec/SkEncodedInfo.h @@ -0,0 +1,199 @@ +/* + * 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 "SkImageInfo.h" + +class SkColorSpace; + +struct SkEncodedInfo { +public: + + 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, 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(Color color, Alpha alpha, int bitsPerComponent) { + 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; + default: + SkASSERT(false); + break; + } + + return SkEncodedInfo(color, alpha, bitsPerComponent); + } + + /* + * Returns an SkImageInfo with Skia color and alpha types that are the + * closest possible match to the encoded info. + */ + SkImageInfo makeImageInfo(int width, int height, sk_sp colorSpace) const { + switch (fColor) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == fAlpha); + return SkImageInfo::Make(width, height, kGray_8_SkColorType, + kOpaque_SkAlphaType, colorSpace); + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, + kUnpremul_SkAlphaType, colorSpace); + case kPalette_Color: { + SkAlphaType alphaType = (kOpaque_Alpha == fAlpha) ? kOpaque_SkAlphaType : + kUnpremul_SkAlphaType; + return SkImageInfo::Make(width, height, kIndex_8_SkColorType, + alphaType, colorSpace); + } + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, + kOpaque_SkAlphaType, colorSpace); + case kRGBA_Color: + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(kOpaque_Alpha != fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, + kUnpremul_SkAlphaType, std::move(colorSpace)); + default: + SkASSERT(false); + return SkImageInfo::MakeUnknown(); + } + } + + Color color() const { return fColor; } + Alpha alpha() const { return fAlpha; } + uint8_t bitsPerComponent() const { return fBitsPerComponent; } + + uint8_t bitsPerPixel() const { + switch (fColor) { + case kGray_Color: + return fBitsPerComponent; + case kGrayAlpha_Color: + return 2 * fBitsPerComponent; + case kPalette_Color: + return fBitsPerComponent; + case kRGB_Color: + case kBGR_Color: + case kYUV_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; + } + } + +private: + + SkEncodedInfo(Color color, Alpha alpha, uint8_t bitsPerComponent) + : fColor(color) + , fAlpha(alpha) + , fBitsPerComponent(bitsPerComponent) + {} + + Color fColor; + Alpha fAlpha; + uint8_t fBitsPerComponent; +}; + +#endif diff --git a/gfx/skia/skia/include/config/SkUserConfig.h b/gfx/skia/skia/include/config/SkUserConfig.h index 23e097b581a7..005b1664b381 100644 --- a/gfx/skia/skia/include/config/SkUserConfig.h +++ b/gfx/skia/skia/include/config/SkUserConfig.h @@ -95,7 +95,7 @@ /* Define this to provide font subsetter in PDF generation. */ -//#define SK_SFNTLY_SUBSETTER "sfntly/subsetter/font_subsetter.h" +//#define SK_SFNTLY_SUBSETTER "sample/chromium/font_subsetter.h" /* 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 @@ -154,6 +154,8 @@ #define SK_RASTERIZE_EVEN_ROUNDING +#define SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER + #define SK_DISABLE_SLOW_DEBUG_VALIDATION 1 #define MOZ_SKIA 1 @@ -166,15 +168,4 @@ # endif #endif -/* Check if building with either MSVC, libc++, or a sufficiently recent version of libstdc++. -+ * On platforms like OS X 10.6 or older Android SDKs, we need to work around a lack of certain -+ * C++11 features. -+ */ -#include "mozilla/Compiler.h" -#if MOZ_IS_MSVC || MOZ_USING_LIBCXX || MOZ_LIBSTDCXX_VERSION_AT_LEAST(4, 8, 0) -# define MOZ_SKIA_AVOID_CXX11 0 -#else -# define MOZ_SKIA_AVOID_CXX11 1 -#endif - #endif diff --git a/gfx/skia/skia/include/core/SkBBHFactory.h b/gfx/skia/skia/include/core/SkBBHFactory.h index ca7040409d37..58bd754b2bd9 100644 --- a/gfx/skia/skia/include/core/SkBBHFactory.h +++ b/gfx/skia/skia/include/core/SkBBHFactory.h @@ -18,7 +18,7 @@ public: * Allocate a new SkBBoxHierarchy. Return NULL on failure. */ virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const = 0; - virtual ~SkBBHFactory() {}; + virtual ~SkBBHFactory() {} }; class SK_API SkRTreeFactory : public SkBBHFactory { diff --git a/gfx/skia/skia/include/core/SkBitmap.h b/gfx/skia/skia/include/core/SkBitmap.h index a81e03eefa68..ce1b56e7bf0e 100644 --- a/gfx/skia/skia/include/core/SkBitmap.h +++ b/gfx/skia/skia/include/core/SkBitmap.h @@ -23,7 +23,6 @@ class SkPixelRef; class SkPixelRefFactory; class SkRegion; class SkString; -class GrTexture; /** \class SkBitmap @@ -85,7 +84,7 @@ public: int height() const { return fInfo.height(); } SkColorType colorType() const { return fInfo.colorType(); } SkAlphaType alphaType() const { return fInfo.alphaType(); } - SkColorProfileType profileType() const { return fInfo.profileType(); } + SkColorSpace* colorSpace() const { return fInfo.colorSpace(); } /** * Return the number of bytes per pixel based on the colortype. If the colortype is @@ -105,7 +104,7 @@ public: * Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel * colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType. */ - int shiftPerPixel() const { return this->bytesPerPixel() >> 1; } + int shiftPerPixel() const { return this->fInfo.shiftPerPixel(); } /////////////////////////////////////////////////////////////////////////// @@ -455,6 +454,7 @@ public: * not be used as targets for a raster device/canvas (since all pixels * modifications will be lost when unlockPixels() is called.) */ + // DEPRECATED bool lockPixelsAreWritable() const; bool requestLock(SkAutoPixmapUnlock* result) const; @@ -468,10 +468,6 @@ public: (this->colorType() != kIndex_8_SkColorType || fColorTable); } - /** Returns the pixelRef's texture, or NULL - */ - GrTexture* getTexture() const; - /** Return the bitmap's colortable, if it uses one (i.e. colorType is Index_8) and the pixels are locked. Otherwise returns NULL. Does not affect the colortable's @@ -774,8 +770,8 @@ private: static void WriteRawPixels(SkWriteBuffer*, const SkBitmap&); static bool ReadRawPixels(SkReadBuffer*, SkBitmap*); - friend class SkReadBuffer; // unflatten, rawpixels - friend class SkWriteBuffer; // rawpixels + friend class SkReadBuffer; // unflatten, rawpixels + friend class SkBinaryWriteBuffer; // rawpixels friend struct SkBitmapProcState; }; diff --git a/gfx/skia/skia/include/core/SkBitmapDevice.h b/gfx/skia/skia/include/core/SkBitmapDevice.h index b53bfd06224c..31c0aa3a35e5 100644 --- a/gfx/skia/skia/include/core/SkBitmapDevice.h +++ b/gfx/skia/skia/include/core/SkBitmapDevice.h @@ -13,7 +13,6 @@ #include "SkCanvas.h" #include "SkColor.h" #include "SkDevice.h" -#include "SkImageFilter.h" #include "SkImageInfo.h" #include "SkRect.h" #include "SkScalar.h" @@ -22,6 +21,7 @@ #include "SkTypes.h" class SkDraw; +class SkImageFilterCache; class SkMatrix; class SkPaint; class SkPath; @@ -58,8 +58,6 @@ public: static SkBitmapDevice* Create(const SkImageInfo&, const SkSurfaceProps&); - SkImageInfo imageInfo() const override; - protected: bool onShouldDisableLCD(const SkPaint&) const override; @@ -121,6 +119,13 @@ protected: const SkPaint& paint) override; virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, const SkPaint&) override; + /////////////////////////////////////////////////////////////////////////// + + void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) override; + sk_sp makeSpecial(const SkBitmap&) override; + sk_sp makeSpecial(const SkImage*) override; + sk_sp snapSpecial() override; + /////////////////////////////////////////////////////////////////////////// /** Update as needed the pixel value in the bitmap, so that the caller can @@ -128,7 +133,11 @@ protected: altered. The config/width/height/rowbytes must remain unchanged. @return the device contents as a bitmap */ +#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP const SkBitmap& onAccessBitmap() override; +#else + const SkBitmap& onAccessBitmap(); +#endif SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); } // just for subclasses, to assign a custom pixelref @@ -141,8 +150,6 @@ protected: bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) override; bool onPeekPixels(SkPixmap*) override; bool onAccessPixels(SkPixmap*) override; - void onAttachToCanvas(SkCanvas*) override; - void onDetachFromCanvas() override; private: friend class SkCanvas; @@ -162,7 +169,7 @@ private: sk_sp makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; - SkImageFilter::Cache* getImageFilterCache() override; + SkImageFilterCache* getImageFilterCache() override; SkBitmap fBitmap; diff --git a/gfx/skia/skia/include/core/SkBlendMode.h b/gfx/skia/skia/include/core/SkBlendMode.h new file mode 100644 index 000000000000..eb3469f25600 --- /dev/null +++ b/gfx/skia/skia/include/core/SkBlendMode.h @@ -0,0 +1,51 @@ +/* + * 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 SkBlendMode_DEFINED +#define SkBlendMode_DEFINED + +enum class SkBlendMode { + kClear, //!< [0, 0] + kSrc, //!< [Sa, Sc] + kDst, //!< [Da, Dc] + kSrcOver, //!< [Sa + Da * (1 - Sa), Sc + Dc * (1 - Sa)] + kDstOver, //!< [Da + Sa * (1 - Da), Dc + Sc * (1 - Da)] + kSrcIn, //!< [Sa * Da, Sc * Da] + kDstIn, //!< [Da * Sa, Dc * Sa] + kSrcOut, //!< [Sa * (1 - Da), Sc * (1 - Da)] + kDstOut, //!< [Da * (1 - Sa), Dc * (1 - Sa)] + kSrcATop, //!< [Da, Sc * Da + Dc * (1 - Sa)] + kDstATop, //!< [Sa, Dc * Sa + Sc * (1 - Da)] + kXor, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa)] + kPlus, //!< [Sa + Da, Sc + Dc] + kModulate, // multiplies all components (= alpha and color) + + // Following blend modes are defined in the CSS Compositing standard: + // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending + kScreen, + kLastCoeffMode = kScreen, + + kOverlay, + kDarken, + kLighten, + kColorDodge, + kColorBurn, + kHardLight, + kSoftLight, + kDifference, + kExclusion, + kMultiply, + kLastSeparableMode = kMultiply, + + kHue, + kSaturation, + kColor, + kLuminosity, + kLastMode = kLuminosity +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkCanvas.h b/gfx/skia/skia/include/core/SkCanvas.h index 8e675b42fc49..5078f4255ce2 100644 --- a/gfx/skia/skia/include/core/SkCanvas.h +++ b/gfx/skia/skia/include/core/SkCanvas.h @@ -9,7 +9,9 @@ #define SkCanvas_DEFINED #include "SkTypes.h" +#include "SkBlendMode.h" #include "SkBitmap.h" +#include "SkClipOp.h" #include "SkDeque.h" #include "SkImage.h" #include "SkPaint.h" @@ -17,9 +19,11 @@ #include "SkRegion.h" #include "SkSurfaceProps.h" #include "SkXfermode.h" +#include "SkLights.h" +#include "../private/SkShadowParams.h" class GrContext; -class GrRenderTarget; +class GrDrawContext; class SkBaseDevice; class SkCanvasClipVisitor; class SkClipStack; @@ -32,12 +36,15 @@ class SkMetaData; class SkPath; class SkPicture; class SkPixmap; +class SkRasterClip; class SkRRect; struct SkRSXform; class SkSurface; class SkSurface_Base; class SkTextBlob; +//#define SK_SUPPORT_LEGACY_CLIP_REGIONOPS + /** \class SkCanvas A Canvas encapsulates all of the state about drawing into a device (bitmap). @@ -57,8 +64,27 @@ class SK_API SkCanvas : public SkRefCnt { enum PrivateSaveLayerFlags { kDontClipToLayer_PrivateSaveLayerFlag = 1U << 31, }; - + public: +#ifdef SK_SUPPORT_LEGACY_CLIP_REGIONOPS + typedef SkRegion::Op ClipOp; + + static const ClipOp kDifference_Op = SkRegion::kDifference_Op; + static const ClipOp kIntersect_Op = SkRegion::kIntersect_Op; + static const ClipOp kUnion_Op = SkRegion::kUnion_Op; + static const ClipOp kXOR_Op = SkRegion::kXOR_Op; + static const ClipOp kReverseDifference_Op = SkRegion::kReverseDifference_Op; + static const ClipOp kReplace_Op = SkRegion::kReplace_Op; +#else + typedef SkClipOp ClipOp; + + static const ClipOp kDifference_Op = kDifference_SkClipOp; + static const ClipOp kIntersect_Op = kIntersect_SkClipOp; + static const ClipOp kUnion_Op = kUnion_SkClipOp; + static const ClipOp kXOR_Op = kXOR_SkClipOp; + static const ClipOp kReverseDifference_Op = kReverseDifference_SkClipOp; + static const ClipOp kReplace_Op = kReplace_SkClipOp; +#endif /** * Attempt to allocate raster canvas, matching the ImageInfo, that will draw directly into the * specified pixels. To access the pixels after drawing to them, the caller should call @@ -418,11 +444,18 @@ public: */ void scale(SkScalar sx, SkScalar sy); - /** Preconcat the current matrix with the specified rotation. + /** Preconcat the current matrix with the specified rotation about the origin. @param degrees The amount to rotate, in degrees */ void rotate(SkScalar degrees); + /** Preconcat the current matrix with the specified rotation about a given point. + @param degrees The amount to rotate, in degrees + @param px The x coordinate of the point to rotate about. + @param py The y coordinate of the point to rotate about. + */ + void rotate(SkScalar degrees, SkScalar px, SkScalar py); + /** Preconcat the current matrix with the specified skew. @param sx The amount to skew in X @param sy The amount to skew in Y @@ -443,15 +476,37 @@ public: */ void resetMatrix(); +#ifdef SK_EXPERIMENTAL_SHADOWING + /** Add the specified translation to the current draw depth of the canvas. + @param z The distance to translate in Z. + Negative into screen, positive out of screen. + Without translation, the draw depth defaults to 0. + */ + void translateZ(SkScalar z); + + /** Set the current set of lights in the canvas. + @param lights The lights that we want the canvas to have. + */ + void setLights(sk_sp lights); + + /** Returns the current set of lights the canvas uses + */ + sk_sp getLights() const; +#endif + /** * Modify the current clip with the specified rectangle. * @param rect The rect to combine with the current clip * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipRect(const SkRect& rect, - SkRegion::Op op = SkRegion::kIntersect_Op, - bool doAntiAlias = false); + void clipRect(const SkRect& rect, ClipOp, bool doAntiAlias); + void clipRect(const SkRect& rect, ClipOp op) { + this->clipRect(rect, op, false); + } + void clipRect(const SkRect& rect, bool doAntiAlias = false) { + this->clipRect(rect, kIntersect_Op, doAntiAlias); + } /** * Modify the current clip with the specified SkRRect. @@ -459,9 +514,13 @@ public: * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipRRect(const SkRRect& rrect, - SkRegion::Op op = SkRegion::kIntersect_Op, - bool doAntiAlias = false); + void clipRRect(const SkRRect& rrect, ClipOp op, bool doAntiAlias); + void clipRRect(const SkRRect& rrect, ClipOp op) { + this->clipRRect(rrect, op, false); + } + void clipRRect(const SkRRect& rrect, bool doAntiAlias = false) { + this->clipRRect(rrect, kIntersect_Op, doAntiAlias); + } /** * Modify the current clip with the specified path. @@ -469,16 +528,12 @@ public: * @param op The region op to apply to the current clip * @param doAntiAlias true if the clip should be antialiased */ - void clipPath(const SkPath& path, - SkRegion::Op op = SkRegion::kIntersect_Op, - bool doAntiAlias = false); - - /** EXPERIMENTAL -- only used for testing - Set to false to force clips to be hard, even if doAntiAlias=true is - passed to clipRect or clipPath. - */ - void setAllowSoftClip(bool allow) { - fAllowSoftClip = allow; + void clipPath(const SkPath& path, ClipOp op, bool doAntiAlias); + void clipPath(const SkPath& path, ClipOp op) { + this->clipPath(path, op, false); + } + void clipPath(const SkPath& path, bool doAntiAlias = false) { + this->clipPath(path, kIntersect_Op, doAntiAlias); } /** EXPERIMENTAL -- only used for testing @@ -495,17 +550,7 @@ public: @param deviceRgn The region to apply to the current clip @param op The region op to apply to the current clip */ - void clipRegion(const SkRegion& deviceRgn, - SkRegion::Op op = SkRegion::kIntersect_Op); - - /** Helper for clipRegion(rgn, kReplace_Op). Sets the current clip to the - specified region. This does not intersect or in any other way account - for the existing clip region. - @param deviceRgn The region to copy into the current clip. - */ - void setClipRegion(const SkRegion& deviceRgn) { - this->clipRegion(deviceRgn, SkRegion::kReplace_Op); - } + void clipRegion(const SkRegion& deviceRgn, ClipOp op = kIntersect_Op); /** Return true if the specified rectangle, after being transformed by the current matrix, would lie completely outside of the current clip. Call @@ -529,40 +574,6 @@ public: */ bool quickReject(const SkPath& path) const; - /** Return true if the horizontal band specified by top and bottom is - completely clipped out. This is a conservative calculation, meaning - that it is possible that if the method returns false, the band may still - in fact be clipped out, but the converse is not true. If this method - returns true, then the band is guaranteed to be clipped out. - @param top The top of the horizontal band to compare with the clip - @param bottom The bottom of the horizontal and to compare with the clip - @return true if the horizontal band is completely clipped out (i.e. does - not intersect the current clip) - */ - bool quickRejectY(SkScalar top, SkScalar bottom) const { - SkASSERT(top <= bottom); - -#ifndef SK_WILL_NEVER_DRAW_PERSPECTIVE_TEXT - // TODO: add a hasPerspective method similar to getLocalClipBounds. This - // would cache the SkMatrix::hasPerspective result. Alternatively, have - // the MC stack just set a hasPerspective boolean as it is updated. - if (this->getTotalMatrix().hasPerspective()) { - // TODO: consider implementing some half-plane test between the - // two Y planes and the device-bounds (i.e., project the top and - // bottom Y planes and then determine if the clip bounds is completely - // outside either one). - return false; - } -#endif - - const SkRect& clipR = this->getLocalClipBounds(); - // In the case where the clip is empty and we are provided with a - // negative top and positive bottom parameter then this test will return - // false even though it will be clipped. We have chosen to exclude that - // check as it is rare and would result double the comparisons. - return top >= clipR.fBottom || bottom <= clipR.fTop; - } - /** Return the bounds of the current clip (in local coordinates) in the bounds parameter, and return true if it is non-empty. This can be useful in a way similar to quickReject, in that it tells you that drawing @@ -585,22 +596,31 @@ public: @param b the blue component (0..255) of the color to fill the canvas @param mode the mode to apply the color in (defaults to SrcOver) */ - void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, - SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); + void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode = SkBlendMode::kSrcOver); +#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT + void drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkXfermode::Mode mode) { + this->drawARGB(a, r, g, b, (SkBlendMode)mode); + } +#endif /** Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and mode. @param color the color to draw with @param mode the mode to apply the color in (defaults to SrcOver) */ - void drawColor(SkColor color, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode); + void drawColor(SkColor color, SkBlendMode mode = SkBlendMode::kSrcOver); +#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT + void drawColor(SkColor color, SkXfermode::Mode mode) { + this->drawColor(color, (SkBlendMode)mode); + } +#endif /** * Helper method for drawing a color in SRC mode, completely replacing all the pixels * in the current clip with this color. */ void clear(SkColor color) { - this->drawColor(color, SkXfermode::kSrc_Mode); + this->drawColor(color, SkBlendMode::kSrc); } /** @@ -709,6 +729,12 @@ public: void drawRectCoords(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom, const SkPaint& paint); + /** Draw the outline of the specified region using the specified paint. + @param region The region to be drawn + @param paint The paint used to draw the region + */ + void drawRegion(const SkRegion& region, const SkPaint& paint); + /** Draw the specified oval using the specified paint. The oval will be filled or framed based on the Style in the paint. @param oval The rectangle bounds of the oval to be drawn @@ -743,14 +769,17 @@ public: const SkPaint& paint); /** Draw the specified arc, which will be scaled to fit inside the - specified oval. If the sweep angle is >= 360, then the oval is drawn - completely. Note that this differs slightly from SkPath::arcTo, which - treats the sweep angle mod 360. - @param oval The bounds of oval used to define the shape of the arc + specified oval. Sweep angles are not treated as modulo 360 and thus can + exceed a full sweep of the oval. Note that this differs slightly from + SkPath::arcTo, which treats the sweep angle mod 360. If the oval is empty + or the sweep angle is zero nothing is drawn. If useCenter is true the oval + center is inserted into the implied path before the arc and the path is + closed back to the, center forming a wedge. Otherwise, the implied path + contains just the arc and is not closed. + @param oval The bounds of oval used to define the shape of the arc. @param startAngle Starting angle (in degrees) where the arc begins - @param sweepAngle Sweep angle (in degrees) measured clockwise - @param useCenter true means include the center of the oval. For filling - this will draw a wedge. False means just use the arc. + @param sweepAngle Sweep angle (in degrees) measured clockwise. + @param useCenter true means include the center of the oval. @param paint The paint used to draw the arc */ void drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, @@ -911,7 +940,7 @@ public: SrcRectConstraint = kStrict_SrcRectConstraint); /** - * Draw the bitmap stretched differentially to fit into dst. + * Draw the bitmap stretched or shrunk differentially to fit into dst. * center is a rect within the bitmap, and logically divides the bitmap * into 9 sections (3x3). For example, if the middle pixel of a [5x5] * bitmap is the "center", then the center-rect should be [2, 2, 3, 3]. @@ -927,6 +956,69 @@ public: void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint = NULL); + /** + * Specifies coordinates to divide a bitmap into (xCount*yCount) rects. + * + * If the lattice divs or bounds are invalid, the entire lattice + * struct will be ignored on the draw call. + */ + struct Lattice { + enum Flags : uint8_t { + // If set, indicates that we should not draw corresponding rect. + kTransparent_Flags = 1 << 0, + }; + + // An array of x-coordinates that divide the bitmap vertically. + // These must be unique, increasing, and in the set [fBounds.fLeft, fBounds.fRight). + // Does not have ownership. + const int* fXDivs; + + // An array of y-coordinates that divide the bitmap horizontally. + // These must be unique, increasing, and in the set [fBounds.fTop, fBounds.fBottom). + // Does not have ownership. + const int* fYDivs; + + // If non-null, the length of this array must be equal to + // (fXCount + 1) * (fYCount + 1). Note that we allow the first rect + // in each direction to be empty (ex: fXDivs[0] = fBounds.fLeft). + // In this case, the caller still must specify a flag (as a placeholder) + // for these empty rects. + // The flags correspond to the rects in the lattice, first moving + // left to right and then top to bottom. + const Flags* fFlags; + + // The number of fXDivs. + int fXCount; + + // The number of fYDivs. + int fYCount; + + // The bound to draw from. Must be contained by the src that is being drawn, + // non-empty, and non-inverted. + // If nullptr, the bounds are the entire src. + const SkIRect* fBounds; + }; + + /** + * Draw the bitmap stretched or shrunk differentially to fit into dst. + * + * Moving horizontally across the bitmap, alternating rects will be "scalable" + * (in the x-dimension) to fit into dst or must be left "fixed". The first rect + * is treated as "fixed", but it's possible to specify an empty first rect by + * making lattice.fXDivs[0] = 0. + * + * The scale factor for all "scalable" rects will be the same, and may be greater + * than or less than 1 (meaning we can stretch or shrink). If the number of + * "fixed" pixels is greater than the width of the dst, we will collapse all of + * the "scalable" regions and appropriately downscale the "fixed" regions. + * + * The same interpretation also applies to the y-dimension. + */ + void drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint = nullptr); + void drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint = nullptr); + /** Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted based on the Align setting in the paint. @param text The text to be drawn @@ -988,6 +1080,14 @@ public: void drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint); + /** + * Draw the text with each character/glyph individually transformed by its xform. + * If cullRect is not null, it is a conservative bounds of what will be drawn + * taking into account the xforms and the paint, and will be used to accelerate culling. + */ + void drawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], + const SkRect* cullRect, const SkPaint& paint); + /** Draw the text blob, offset by (x,y), using the specified paint. @param blob The text blob to be drawn @param x The x-offset of the text being drawn @@ -995,6 +1095,9 @@ public: @param paint The paint used for the text (e.g. color, size, style) */ void drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); + void drawTextBlob(const sk_sp& blob, SkScalar x, SkScalar y, const SkPaint& paint) { + this->drawTextBlob(blob.get(), x, y, paint); + } /** Draw the picture into this canvas. This method effective brackets the playback of the picture's draw calls with save/restore, so the state @@ -1026,6 +1129,53 @@ public: this->drawPicture(picture.get(), matrix, paint); } +#ifdef SK_EXPERIMENTAL_SHADOWING + /** + * Draw the picture into this canvas, with shadows! + * + * We will use the canvas's lights along with the picture information (draw depths of + * objects, etc) to first create a set of shadowmaps for the light-picture pairs, and + * then use that set of shadowmaps to render the scene with shadows. + * + * If matrix is non-null, apply that matrix to the CTM when drawing this picture. This is + * logically equivalent to + * save/concat/drawPicture/restore + * + * If paint is non-null, draw the picture into a temporary buffer, and then apply the paint's + * alpha/colorfilter/imagefilter/xfermode to that buffer as it is drawn to the canvas. + * This is logically equivalent to + * saveLayer(paint)/drawPicture/restore + * + * We also support using variance shadow maps for blurred shadows; the user can specify + * what shadow mapping algorithm to use with params. + * - Variance Shadow Mapping works by storing both the depth and depth^2 in the shadow map. + * - Then, the shadow map can be blurred, and when reading from it, the fragment shader + * can calculate the variance of the depth at a position by doing E(x^2) - E(x)^2. + * - We can then use the depth variance and depth at a fragment to arrive at an upper bound + * of the probability that the current surface is shadowed by using Chebyshev's + * inequality, and then use that to shade the fragment. + * + * - There are a few problems with VSM. + * * Light Bleeding | Areas with high variance, such as near the edges of high up rects, + * will cause their shadow penumbras to overwrite otherwise solid + * shadows. + * * Shape Distortion | We can combat Light Bleeding by biasing the shadow (setting + * mostly shaded fragments to completely shaded) and increasing + * the minimum allowed variance. However, this warps and rounds + * out the shape of the shadow. + */ + void drawShadowedPicture(const SkPicture*, + const SkMatrix* matrix, + const SkPaint* paint, + const SkShadowParams& params); + void drawShadowedPicture(const sk_sp& picture, + const SkMatrix* matrix, + const SkPaint* paint, + const SkShadowParams& params) { + this->drawShadowedPicture(picture.get(), matrix, paint, params); + } +#endif + enum VertexMode { kTriangles_VertexMode, kTriangleStrip_VertexMode, @@ -1220,46 +1370,8 @@ public: /////////////////////////////////////////////////////////////////////////// - /** 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 SK_API LayerIter /*: SkNoncopyable*/ { - public: - /** Initialize iterator with canvas, and set values for 1st device */ - LayerIter(SkCanvas*, bool skipEmptyClips); - ~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; - const SkRegion& clip() 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; - }; - // don't call - GrRenderTarget* internal_private_accessTopLayerRenderTarget(); + GrDrawContext* internal_private_accessTopLayerDrawContext(); // don't call static void Internal_Private_SetIgnoreSaveLayerBounds(bool); @@ -1275,13 +1387,30 @@ public: const SkPaint* paint, SrcRectConstraint constraint = kStrict_SrcRectConstraint); + // expose minimum amount of information necessary for transitional refactoring + /** + * Returns CTM and clip bounds, translated from canvas coordinates to top layer coordinates. + */ + void temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds); + protected: +#ifdef SK_EXPERIMENTAL_SHADOWING + /** Returns the current (cumulative) draw depth of the canvas. + */ + SkScalar getZ() const; + + sk_sp fLights; +#endif + // default impl defers to getDevice()->newSurface(info) virtual sk_sp onNewSurface(const SkImageInfo&, const SkSurfaceProps&); // default impl defers to its device virtual bool onPeekPixels(SkPixmap*); virtual bool onAccessTopLayerPixels(SkPixmap*); + virtual SkImageInfo onImageInfo() const; + virtual bool onGetProps(SkSurfaceProps*) const; + virtual void onFlush(); // Subclass save/restore notifiers. // Overriders should call the corresponding INHERITED method up the inheritance chain. @@ -1300,6 +1429,13 @@ protected: 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)); + } + +#ifdef SK_EXPERIMENTAL_SHADOWING + virtual void didTranslateZ(SkScalar) {} +#endif virtual void onDrawAnnotation(const SkRect&, const char key[], SkData* value); virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); @@ -1317,6 +1453,8 @@ protected: virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint); + virtual void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], + const SkRect* cullRect, const SkPaint& paint); virtual void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint); @@ -1328,7 +1466,10 @@ protected: virtual void onDrawPaint(const SkPaint&); virtual void onDrawRect(const SkRect&, const SkPaint&); + virtual void onDrawRegion(const SkRegion& region, const SkPaint& paint); virtual void onDrawOval(const SkRect&, const SkPaint&); + virtual void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, + const SkPaint&); virtual void onDrawRRect(const SkRRect&, const SkPaint&); virtual void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&); virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[], @@ -1343,27 +1484,38 @@ protected: SrcRectConstraint); virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint*); + virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst, + const SkPaint*); virtual void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*); virtual void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, SrcRectConstraint); virtual void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*); + virtual void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst, + const SkPaint*); enum ClipEdgeStyle { kHard_ClipEdgeStyle, kSoft_ClipEdgeStyle }; - virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle); - virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle); - virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle); - virtual void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op); + virtual void onClipRect(const SkRect& rect, ClipOp, ClipEdgeStyle); + virtual void onClipRRect(const SkRRect& rrect, ClipOp, ClipEdgeStyle); + virtual void onClipPath(const SkPath& path, ClipOp, ClipEdgeStyle); + virtual void onClipRegion(const SkRegion& deviceRgn, ClipOp); virtual void onDiscard(); virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); +#ifdef SK_EXPERIMENTAL_SHADOWING + virtual void onDrawShadowedPicture(const SkPicture*, + const SkMatrix*, + const SkPaint*, + const SkShadowParams& params); +#endif + // Returns the canvas to be used by DrawIter. Default implementation // returns this. Subclasses that encapsulate an indirect canvas may // need to overload this method. The impl must keep track of this, as it @@ -1378,9 +1530,51 @@ protected: const SkImageFilter* imageFilter = NULL); 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; + const SkRasterClip& clip() 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 SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags); + static void DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter, + SkBaseDevice* dst, const SkMatrix& ctm, + const SkClipStack* clipStack); + enum ShaderOverrideOpacity { kNone_ShaderOverrideOpacity, //!< there is no overriding shader (bitmap or image) kOpaque_ShaderOverrideOpacity, //!< the overriding shader is opaque @@ -1406,7 +1600,7 @@ private: enum { kMCRecSize = 128, // most recent measurement kMCRecCount = 32, // common depth for save/restores - kDeviceCMSize = 136, // most recent measurement + kDeviceCMSize = 176, // most recent measurement }; intptr_t fMCRecStorage[kMCRecSize * kMCRecCount / sizeof(intptr_t)]; intptr_t fDeviceCMStorage[kDeviceCMSize / sizeof(intptr_t)]; @@ -1430,6 +1624,7 @@ private: void doSave(); void checkForDeferredSave(); + void internalSetMatrix(const SkMatrix&); friend class SkDrawIter; // needs setupDrawForLayerDevice() friend class AutoDrawLooper; @@ -1437,6 +1632,7 @@ private: friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip friend class SkSurface_Raster; // needs getDevice() friend class SkRecorder; // InitFlags + friend class SkLiteRecorder; // InitFlags friend class SkNoSaveLayerCanvas; // InitFlags friend class SkPictureImageFilter; // SkCanvas(SkBaseDevice*, SkSurfaceProps*, InitFlags) friend class SkPictureRecord; // predrawNotify (why does it need it? ) @@ -1472,7 +1668,7 @@ private: SrcRectConstraint); void internalDrawPaint(const SkPaint& paint); void internalSaveLayer(const SaveLayerRec&, SaveLayerStrategy); - void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*, bool isBitmapDevice); + void internalDrawDevice(SkBaseDevice*, int x, int y, const SkPaint*); // shared by save() and saveLayer() void internalSave(); @@ -1498,25 +1694,18 @@ private: */ bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint&); - /* These maintain a cache of the clip bounds in local coordinates, - (converted to 2s-compliment if floats are slow). + + /** + * 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. */ - mutable SkRect fCachedLocalClipBounds; - mutable bool fCachedLocalClipBoundsDirty; + bool fIsScaleTranslate; + SkRect fDeviceClipBounds; + bool fAllowSoftClip; bool fAllowSimplifyClip; const bool fConservativeRasterClip; - const SkRect& getLocalClipBounds() const { - if (fCachedLocalClipBoundsDirty) { - if (!this->getClipBounds(&fCachedLocalClipBounds)) { - fCachedLocalClipBounds.setEmpty(); - } - fCachedLocalClipBoundsDirty = false; - } - return fCachedLocalClipBounds; - } - class AutoValidateClip : ::SkNoncopyable { public: explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) { @@ -1577,9 +1766,9 @@ private: class SkCanvasClipVisitor { public: virtual ~SkCanvasClipVisitor(); - virtual void clipRect(const SkRect&, SkRegion::Op, bool antialias) = 0; - virtual void clipRRect(const SkRRect&, SkRegion::Op, bool antialias) = 0; - virtual void clipPath(const SkPath&, SkRegion::Op, bool antialias) = 0; + virtual void clipRect(const SkRect&, SkCanvas::ClipOp, bool antialias) = 0; + virtual void clipRRect(const SkRRect&, SkCanvas::ClipOp, bool antialias) = 0; + virtual void clipPath(const SkPath&, SkCanvas::ClipOp, bool antialias) = 0; }; #endif diff --git a/gfx/skia/skia/include/core/SkChunkAlloc.h b/gfx/skia/skia/include/core/SkChunkAlloc.h index 9699842e6b42..bb4ec8faecad 100644 --- a/gfx/skia/skia/include/core/SkChunkAlloc.h +++ b/gfx/skia/skia/include/core/SkChunkAlloc.h @@ -33,7 +33,18 @@ public: kThrow_AllocFailType }; + /** + * Allocates a memory block of size bytes. + * On success: returns a pointer to beginning of memory block that is + * 8 byte aligned. The content of allocated block is not initialized. + * On failure: calls abort() if called with kThrow_AllocFailType, + * otherwise returns NULL pointer. + */ void* alloc(size_t bytes, AllocFailType); + + /** + * Shortcut for calling alloc with kThrow_AllocFailType. + */ void* allocThrow(size_t bytes) { return this->alloc(bytes, kThrow_AllocFailType); } diff --git a/gfx/skia/skia/include/core/SkClipOp.h b/gfx/skia/skia/include/core/SkClipOp.h new file mode 100644 index 000000000000..2e4fbbf86806 --- /dev/null +++ b/gfx/skia/skia/include/core/SkClipOp.h @@ -0,0 +1,26 @@ +/* + * 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" + +// these kept in SkRegion::Op order for now ... +enum SkClipOp { + kDifference_SkClipOp = 0, + kIntersect_SkClipOp = 1, + + // Goal: remove these, since they can grow the current clip + + kUnion_SkClipOp = 2, + kXOR_SkClipOp = 3, + kReverseDifference_SkClipOp = 4, + kReplace_SkClipOp = 5, +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkClipStack.h b/gfx/skia/skia/include/core/SkClipStack.h index 973f70a42be2..7a8eb5ca846d 100644 --- a/gfx/skia/skia/include/core/SkClipStack.h +++ b/gfx/skia/skia/include/core/SkClipStack.h @@ -1,13 +1,14 @@ - /* * 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 SkClipStack_DEFINED #define SkClipStack_DEFINED +#include "SkCanvas.h" #include "SkDeque.h" #include "SkPath.h" #include "SkRect.h" @@ -53,21 +54,21 @@ public: static const int kTypeCnt = kLastType + 1; Element() { - this->initCommon(0, SkRegion::kReplace_Op, false); + this->initCommon(0, SkCanvas::kReplace_Op, false); this->setEmpty(); } Element(const Element&); - Element(const SkRect& rect, SkRegion::Op op, bool doAA) { + Element(const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { this->initRect(0, rect, op, doAA); } - Element(const SkRRect& rrect, SkRegion::Op op, bool doAA) { + Element(const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { this->initRRect(0, rrect, op, doAA); } - Element(const SkPath& path, SkRegion::Op op, bool doAA) { + Element(const SkPath& path, SkCanvas::ClipOp op, bool doAA) { this->initPath(0, path, op, doAA); } @@ -93,7 +94,7 @@ public: } //!< Call if getType() is not kEmpty to get the set operation used to combine this element. - SkRegion::Op getOp() const { return fOp; } + SkCanvas::ClipOp getOp() const { return fOp; } //!< Call to get the element as a path, regardless of its type. void asPath(SkPath* path) const; @@ -109,7 +110,7 @@ public: void invertShapeFillType(); //!< Sets the set operation represented by the element. - void setOp(SkRegion::Op op) { fOp = op; } + void setOp(SkCanvas::ClipOp op) { fOp = op; } /** The GenID can be used by clip stack clients to cache representations of the clip. The ID corresponds to the set of clip elements up to and including this element within the @@ -158,6 +159,23 @@ public: } } + bool contains(const SkRRect& rrect) const { + switch (fType) { + case kRect_Type: + return this->getRect().contains(rrect.getBounds()); + case kRRect_Type: + // We don't currently have a generalized rrect-rrect containment. + return fRRect.contains(rrect.getBounds()) || rrect == fRRect; + case kPath_Type: + return fPath.get()->conservativelyContainsRect(rrect.getBounds()); + case kEmpty_Type: + return false; + default: + SkDEBUGFAIL("Unexpected type."); + return false; + } + } + /** * Is the clip shape inverse filled. */ @@ -170,7 +188,7 @@ public: */ void replay(SkCanvasClipVisitor*) const; -#ifdef SK_DEVELOPER +#ifdef SK_DEBUG /** * Dumps the element to SkDebugf. This is intended for Skia development debugging * Don't rely on the existence of this function or the formatting of its output. @@ -184,7 +202,7 @@ public: SkTLazy fPath; SkRRect fRRect; int fSaveCount; // save count of stack when this element was added. - SkRegion::Op fOp; + SkCanvas::ClipOp fOp; Type fType; bool fDoAA; @@ -208,23 +226,23 @@ public: int fGenID; Element(int saveCount) { - this->initCommon(saveCount, SkRegion::kReplace_Op, false); + this->initCommon(saveCount, SkCanvas::kReplace_Op, false); this->setEmpty(); } - Element(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) { + Element(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { this->initRRect(saveCount, rrect, op, doAA); } - Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { + Element(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { this->initRect(saveCount, rect, op, doAA); } - Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) { + Element(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doAA) { this->initPath(saveCount, path, op, doAA); } - void initCommon(int saveCount, SkRegion::Op op, bool doAA) { + void initCommon(int saveCount, SkCanvas::ClipOp op, bool doAA) { fSaveCount = saveCount; fOp = op; fDoAA = doAA; @@ -236,13 +254,13 @@ public: fGenID = kInvalidGenID; } - void initRect(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) { + void initRect(int saveCount, const SkRect& rect, SkCanvas::ClipOp op, bool doAA) { fRRect.setRect(rect); fType = kRect_Type; this->initCommon(saveCount, op, doAA); } - void initRRect(int saveCount, const SkRRect& rrect, SkRegion::Op op, bool doAA) { + void initRRect(int saveCount, const SkRRect& rrect, SkCanvas::ClipOp op, bool doAA) { SkRRect::Type type = rrect.getType(); fRRect = rrect; if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) { @@ -253,13 +271,13 @@ public: this->initCommon(saveCount, op, doAA); } - void initPath(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA); + void initPath(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doAA); void setEmpty(); // All Element methods below are only used within SkClipStack.cpp inline void checkEmpty() const; - inline bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const; + inline bool canBeIntersectedInPlace(int saveCount, SkCanvas::ClipOp op) const; /* This method checks to see if two rect clips can be safely merged into one. The issue here is that to be strictly correct all the edges of the resulting rect must have the same anti-aliasing. */ @@ -284,8 +302,6 @@ public: SkClipStack(); SkClipStack(const SkClipStack& b); - explicit SkClipStack(const SkRect& r); - explicit SkClipStack(const SkIRect& r); ~SkClipStack(); SkClipStack& operator=(const SkClipStack& b); @@ -312,11 +328,17 @@ public: bool* isIntersectionOfRects = NULL) const; /** - * Returns true if the input rect in device space is entirely contained - * by the clip. A return value of false does not guarantee that the rect + * Returns true if the input (r)rect in device space is entirely contained + * by the clip. A return value of false does not guarantee that the (r)rect * is not contained by the clip. */ - bool quickContains(const SkRect& devRect) const; + bool quickContains(const SkRect& devRect) const { + return this->isWideOpen() || this->internalQuickContains(devRect); + } + + bool quickContains(const SkRRect& devRRect) const { + return this->isWideOpen() || this->internalQuickContains(devRRect); + } /** * Flattens the clip stack into a single SkPath. Returns true if any of @@ -324,14 +346,14 @@ public: */ bool asPath(SkPath* path) const; - void clipDevRect(const SkIRect& ir, SkRegion::Op op) { + void clipDevRect(const SkIRect& ir, SkCanvas::ClipOp op) { SkRect r; r.set(ir); - this->clipDevRect(r, op, false); + this->clipRect(r, SkMatrix::I(), op, false); } - void clipDevRect(const SkRect&, SkRegion::Op, bool doAA); - void clipDevRRect(const SkRRect&, SkRegion::Op, bool doAA); - void clipDevPath(const SkPath&, SkRegion::Op, bool doAA); + void clipRect(const SkRect&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); + void clipRRect(const SkRRect&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); + void clipPath(const SkPath&, const SkMatrix& matrix, SkCanvas::ClipOp, bool doAA); // An optimized version of clipDevRect(emptyRect, kIntersect, ...) void clipEmpty(); @@ -339,7 +361,22 @@ public: * isWideOpen returns true if the clip state corresponds to the infinite * plane (i.e., draws are not limited at all) */ - bool isWideOpen() const; + bool isWideOpen() const { return this->getTopmostGenID() == kWideOpenGenID; } + + /** + * This method quickly and conservatively determines whether the entire stack is equivalent to + * intersection with a rrect given a bounds, where the rrect must not contain the entire bounds. + * + * @param bounds A bounds on what will be drawn through the clip. The clip only need be + * equivalent to a intersection with a rrect for draws within the bounds. The + * returned rrect must intersect the bounds but need not be contained by the + * bounds. + * @param rrect If return is true rrect will contain the rrect equivalent to the stack. + * @param aa If return is true aa will indicate whether the equivalent rrect clip is + * antialiased. + * @return true if the stack is equivalent to a single rrect intersect clip, false otherwise. + */ + bool isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const; /** * The generation ID has three reserved values to indicate special @@ -353,7 +390,7 @@ public: int32_t getTopmostGenID() const; -#ifdef SK_DEVELOPER +#ifdef SK_DEBUG /** * Dumps the contents of the clip stack to SkDebugf. This is intended for Skia development * debugging. Don't rely on the existence of this function or the formatting of its output. @@ -387,7 +424,7 @@ public: * Moves the iterator to the topmost element with the specified RegionOp and returns that * element. If no clip element with that op is found, the first element is returned. */ - const Element* skipToTopmost(SkRegion::Op op); + const Element* skipToTopmost(SkCanvas::ClipOp op); /** * Restarts the iterator on a clip stack. @@ -461,6 +498,9 @@ private: // invalid ID. static int32_t gGenID; + bool internalQuickContains(const SkRect& devRect) const; + bool internalQuickContains(const SkRRect& devRRect) const; + /** * Helper for clipDevPath, etc. */ diff --git a/gfx/skia/skia/include/core/SkColor.h b/gfx/skia/skia/include/core/SkColor.h index a40e5f1f1588..8f2776da61b1 100644 --- a/gfx/skia/skia/include/core/SkColor.h +++ b/gfx/skia/skia/include/core/SkColor.h @@ -9,6 +9,7 @@ #define SkColor_DEFINED #include "SkScalar.h" +#include "SkPoint3.h" #include "SkTypes.h" /** \file SkColor.h @@ -166,10 +167,10 @@ struct SkPM4f; * The float values are 0...1 unpremultiplied */ struct SkColor4f { - float fA; float fR; float fG; float fB; + float fA; bool operator==(const SkColor4f& other) const { return fA == other.fA && fR == other.fR && fG == other.fG && fB == other.fB; @@ -178,14 +179,17 @@ struct SkColor4f { return !(*this == other); } - const float* vec() const { return &fA; } - float* vec() { return &fA; } + const float* vec() const { return &fR; } + float* vec() { return &fR; } - static SkColor4f Pin(float a, float r, float g, float b); + static SkColor4f Pin(float r, float g, float b, float a); static SkColor4f FromColor(SkColor); + static SkColor4f FromColor3f(SkColor3f, float a); + + SkColor toSkColor() const; SkColor4f pin() const { - return Pin(fA, fR, fG, fB); + return Pin(fR, fG, fB, fA); } SkPM4f premul() const; diff --git a/gfx/skia/skia/include/core/SkColorFilter.h b/gfx/skia/skia/include/core/SkColorFilter.h index 7ac335fb1036..5a23a343a28c 100644 --- a/gfx/skia/skia/include/core/SkColorFilter.h +++ b/gfx/skia/skia/include/core/SkColorFilter.h @@ -10,11 +10,13 @@ #include "SkColor.h" #include "SkFlattenable.h" +#include "SkRefCnt.h" #include "SkXfermode.h" class GrContext; class GrFragmentProcessor; class SkBitmap; +class SkRasterPipeline; /** * ColorFilters are optional objects in the drawing pipeline. When present in @@ -69,6 +71,8 @@ public: virtual void filterSpan4f(const SkPM4f src[], int count, SkPM4f result[]) const; + bool appendStages(SkRasterPipeline*) const; + enum Flags { /** If set the filter methods will not change the alpha channel of the colors. */ @@ -111,6 +115,9 @@ public: or NULL if the mode will have no effect. */ static sk_sp MakeModeFilter(SkColor c, SkXfermode::Mode mode); + static sk_sp MakeModeFilter(SkColor c, SkBlendMode mode) { + return MakeModeFilter(c, (SkXfermode::Mode)mode); + } /** Construct a colorfilter whose effect is to first apply the inner filter and then apply * the outer filter to the result of the inner's. @@ -142,6 +149,7 @@ public: } #endif +#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. @@ -151,9 +159,8 @@ public: * * A null return indicates that the color filter isn't implemented for the GPU backend. */ - virtual const GrFragmentProcessor* asFragmentProcessor(GrContext*) const { - return nullptr; - } + virtual sk_sp asFragmentProcessor(GrContext*) const; +#endif bool affectsTransparentBlack() const { return this->filterColor(0) != 0; @@ -167,6 +174,8 @@ public: protected: SkColorFilter() {} + virtual bool onAppendStages(SkRasterPipeline*) const; + private: /* * Returns 1 if this is a single filter (not a composition of other filters), otherwise it diff --git a/gfx/skia/skia/include/core/SkColorSpace.h b/gfx/skia/skia/include/core/SkColorSpace.h new file mode 100644 index 000000000000..a96f6220951a --- /dev/null +++ b/gfx/skia/skia/include/core/SkColorSpace.h @@ -0,0 +1,106 @@ +/* + * 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 "SkMatrix44.h" +#include "SkRefCnt.h" + +class SkData; + +class SK_API SkColorSpace : public SkRefCnt { +public: + + /** + * Common, named profiles that we can recognize. + */ + enum Named : uint8_t { + /** + * By far the most common color space. + * This is the default space for images, unmarked content, and monitors. + */ + kSRGB_Named, + + /** + * Very common wide gamut color space. + * Often used by images and monitors. + */ + kAdobeRGB_Named, + + /** + * 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...) + */ + kSRGBLinear_Named, + }; + + 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, + }; + + /** + * Create an SkColorSpace from a transfer function and a color gamut transform to D50 XYZ. + */ + static sk_sp NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50); + + /** + * Create a common, named SkColorSpace. + */ + static sk_sp NewNamed(Named); + + /** + * Create an SkColorSpace from an ICC profile. + */ + static sk_sp NewICC(const void*, size_t); + + /** + * Create an SkColorSpace with the same gamut as this color space, but with linear gamma. + */ + sk_sp makeLinearGamma(); + + /** + * Returns true if the color space gamma is near enough to be approximated as sRGB. + */ + bool gammaCloseToSRGB() const; + + /** + * Returns true if the color space gamma is linear. + */ + bool gammaIsLinear() 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* src, const SkColorSpace* dst); + +protected: + SkColorSpace() {} +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkColorTable.h b/gfx/skia/skia/include/core/SkColorTable.h index ccea7ed550bf..07dfd675b2c3 100644 --- a/gfx/skia/skia/include/core/SkColorTable.h +++ b/gfx/skia/skia/include/core/SkColorTable.h @@ -10,7 +10,7 @@ #ifndef SkColorTable_DEFINED #define SkColorTable_DEFINED -#include "../private/SkOncePtr.h" +#include "../private/SkOnce.h" #include "SkColor.h" #include "SkFlattenable.h" #include "SkImageInfo.h" @@ -62,12 +62,14 @@ private: SkColorTable(SkPMColor* colors, int count, AllocatedWithMalloc); SkPMColor* fColors; - SkOncePtr f16BitCache; + mutable uint16_t* f16BitCache = nullptr; + mutable SkOnce f16BitCacheOnce; int fCount; void init(const SkPMColor* colors, int count); friend class SkImageGenerator; + friend class SkBitmapRegionCodec; // Only call if no other thread or cache has seen this table. void dangerous_overwriteColors(const SkPMColor newColors[], int count) { if (count < 0 || count > fCount) { diff --git a/gfx/skia/skia/include/core/SkData.h b/gfx/skia/skia/include/core/SkData.h index 628029f82b9f..76c9c9ebec2b 100644 --- a/gfx/skia/skia/include/core/SkData.h +++ b/gfx/skia/skia/include/core/SkData.h @@ -14,14 +14,12 @@ class SkStream; -#define SK_SUPPORT_LEGACY_DATA_FACTORIES - /** * 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 : public SkRefCnt { +class SK_API SkData final : public SkNVRefCnt { public: /** * Returns the number of bytes stored. @@ -69,7 +67,6 @@ public: * effectively returning 0 == memcmp(...) */ bool equals(const SkData* other) const; - bool equals(sk_sp& other) const { return this->equals(other.get()); } /** * Function that, if provided, will be called when the SkData goes out @@ -82,7 +79,7 @@ public: */ 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. @@ -160,38 +157,8 @@ public: */ static sk_sp MakeEmpty(); -#ifdef SK_SUPPORT_LEGACY_DATA_FACTORIES - static SkData* NewWithCopy(const void* data, size_t length) { - return MakeWithCopy(data, length).release(); - } - static SkData* NewUninitialized(size_t length) { - return MakeUninitialized(length).release(); - } - static SkData* NewWithCString(const char cstr[]) { - return MakeWithCString(cstr).release(); - } - static SkData* NewWithProc(const void* ptr, size_t length, ReleaseProc proc, void* context) { - return MakeWithProc(ptr, length, proc, context).release(); - } - static SkData* NewWithoutCopy(const void* data, size_t length) { - return MakeWithoutCopy(data, length).release(); - } - static SkData* NewFromMalloc(const void* data, size_t length) { - return MakeFromMalloc(data, length).release(); - } - static SkData* NewFromFileName(const char path[]) { return MakeFromFileName(path).release(); } - static SkData* NewFromFILE(FILE* f) { return MakeFromFILE(f).release(); } - static SkData* NewFromFD(int fd) { return MakeFromFD(fd).release(); } - static SkData* NewFromStream(SkStream* stream, size_t size) { - return MakeFromStream(stream, size).release(); - } - static SkData* NewSubset(const SkData* src, size_t offset, size_t length) { - return MakeSubset(src, offset, length).release(); - } - static SkData* NewEmpty() { return MakeEmpty().release(); } -#endif - private: + friend class SkNVRefCnt; ReleaseProc fReleaseProc; void* fReleaseProcContext; void* fPtr; @@ -199,7 +166,7 @@ private: SkData(const void* ptr, size_t size, ReleaseProc, void* context); explicit SkData(size_t size); // inplace new/delete - virtual ~SkData(); + ~SkData(); // Objects of this type are sometimes created in a custom fashion using sk_malloc_throw and @@ -216,14 +183,9 @@ private: // shared internal factory static sk_sp PrivateNewWithCopy(const void* srcOrNull, size_t length); - static void DummyReleaseProc(const void*, void*) {} + static void DummyReleaseProc(const void*, void*); // {} typedef SkRefCnt INHERITED; }; -#ifdef SK_SUPPORT_LEGACY_DATA_FACTORIES -/** Typedef of SkAutoTUnref for automatically unref-ing a SkData. */ -typedef SkAutoTUnref SkAutoDataUnref; -#endif - #endif diff --git a/gfx/skia/skia/include/core/SkDataTable.h b/gfx/skia/skia/include/core/SkDataTable.h index c9d915d2555e..2ec2d0f2e232 100644 --- a/gfx/skia/skia/include/core/SkDataTable.h +++ b/gfx/skia/skia/include/core/SkDataTable.h @@ -63,7 +63,7 @@ public: typedef void (*FreeProc)(void* context); - static SkDataTable* NewEmpty(); + static sk_sp MakeEmpty(); /** * Return a new DataTable that contains a copy of the data stored in each @@ -74,8 +74,8 @@ public: * ptrs[] array. * @param count the number of array elements in ptrs[] and sizes[] to copy. */ - static SkDataTable* NewCopyArrays(const void * const * ptrs, - const size_t sizes[], int count); + 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. @@ -85,11 +85,10 @@ public: * @param count the number of entries to be copied out of array. The number * of bytes that will be copied is count * elemSize. */ - static SkDataTable* NewCopyArray(const void* array, size_t elemSize, - int count); + static sk_sp MakeCopyArray(const void* array, size_t elemSize, int count); - static SkDataTable* NewArrayProc(const void* array, size_t elemSize, - int count, FreeProc proc, void* context); + static sk_sp MakeArrayProc(const void* array, size_t elemSize, int count, + FreeProc proc, void* context); private: struct Dir { @@ -164,7 +163,7 @@ public: * calls to append(). This call also clears any accumluated entries from * this builder, so its count() will be 0 after this call. */ - SkDataTable* detachDataTable(); + sk_sp detachDataTable(); private: SkTDArray fDir; diff --git a/gfx/skia/skia/include/core/SkDevice.h b/gfx/skia/skia/include/core/SkDevice.h index c15aeccf82dc..c29a65d7761a 100644 --- a/gfx/skia/skia/include/core/SkDevice.h +++ b/gfx/skia/skia/include/core/SkDevice.h @@ -11,17 +11,18 @@ #include "SkRefCnt.h" #include "SkCanvas.h" #include "SkColor.h" -#include "SkImageFilter.h" #include "SkSurfaceProps.h" class SkBitmap; class SkClipStack; class SkDraw; class SkDrawFilter; +class SkImageFilterCache; struct SkIRect; class SkMatrix; class SkMetaData; class SkRegion; +class SkSpecialImage; class GrRenderTarget; class SK_API SkBaseDevice : public SkRefCnt { @@ -29,7 +30,7 @@ public: /** * Construct a new device. */ - explicit SkBaseDevice(const SkSurfaceProps&); + explicit SkBaseDevice(const SkImageInfo&, const SkSurfaceProps&); virtual ~SkBaseDevice(); SkMetaData& getMetaData(); @@ -38,7 +39,7 @@ public: * Return ImageInfo for this device. If the canvas is not backed by pixels * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. */ - virtual SkImageInfo imageInfo() const; + const SkImageInfo& imageInfo() const { return fInfo; } /** * Return SurfaceProps for this device. @@ -76,6 +77,7 @@ public: return this->imageInfo().isOpaque(); } +#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP /** Return the bitmap associated with this device. Call this each time you need to access the bitmap, as it notifies the subclass to perform any flushing etc. before you examine the pixels. @@ -83,6 +85,7 @@ public: @return the device's bitmap */ const SkBitmap& accessBitmap(bool changePixels); +#endif bool writePixels(const SkImageInfo&, const void*, size_t rowBytes, int x, int y); @@ -103,44 +106,12 @@ public: */ bool peekPixels(SkPixmap*); - /** - * Return the device's associated gpu render target, or NULL. - */ - virtual GrRenderTarget* accessRenderTarget() { return NULL; } - - /** * Return the device's origin: its offset in device coordinates from * the default origin in its canvas' matrix/clip */ const SkIPoint& getOrigin() const { return fOrigin; } - /** - * onAttachToCanvas is invoked whenever a device is installed in a canvas - * (i.e., setDevice, saveLayer (for the new device created by the save), - * and SkCanvas' SkBaseDevice & SkBitmap -taking ctors). It allows the - * devices to prepare for drawing (e.g., locking their pixels, etc.) - */ - virtual void onAttachToCanvas(SkCanvas*) { - SkASSERT(!fAttachedToCanvas); -#ifdef SK_DEBUG - fAttachedToCanvas = true; -#endif - }; - - /** - * onDetachFromCanvas notifies a device that it will no longer be drawn to. - * It gives the device a chance to clean up (e.g., unlock its pixels). It - * is invoked from setDevice (for the displaced device), restore and - * possibly from SkCanvas' dtor. - */ - virtual void onDetachFromCanvas() { - SkASSERT(fAttachedToCanvas); -#ifdef SK_DEBUG - fAttachedToCanvas = false; -#endif - }; - protected: enum TileUsage { kPossible_TileUsage, //!< the created device may be drawn tiled @@ -159,25 +130,6 @@ protected: virtual bool onShouldDisableLCD(const SkPaint&) const { return false; } - /** - * - * DEPRECATED: This will be removed in a future change. Device subclasses - * should use the matrix and clip from the SkDraw passed to draw functions. - * - * Called with the correct matrix and clip before this device is drawn - * to using those settings. If your subclass overrides this, be sure to - * call through to the base class as well. - * - * The clipstack is another view of the clip. It records the actual - * geometry that went into building the region. It is present for devices - * that want to parse it, but is not required: the region is a complete - * picture of the current clip. (i.e. if you regionize all of the geometry - * in the clipstack, you will arrive at an equivalent region to the one - * passed in). - */ - virtual void setMatrixClip(const SkMatrix&, const SkRegion&, - const SkClipStack&) {}; - /** These are called inside the per-device-layer loop for each draw call. When these are called, we have already applied any saveLayer operations, and are handling any looping from the paint, and any effects from the @@ -188,8 +140,13 @@ protected: const SkPoint[], const SkPaint& paint) = 0; virtual void drawRect(const SkDraw&, const SkRect& r, const SkPaint& paint) = 0; + virtual void drawRegion(const SkDraw&, const SkRegion& r, + const SkPaint& paint); virtual void drawOval(const SkDraw&, const SkRect& oval, const SkPaint& paint) = 0; + /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */ + virtual void drawArc(const SkDraw&, const SkRect& oval, SkScalar startAngle, + SkScalar sweepAngle, bool useCenter, const SkPaint& paint); virtual void drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) = 0; @@ -226,13 +183,17 @@ protected: const SkPaint& paint, SkCanvas::SrcRectConstraint) = 0; virtual void drawBitmapNine(const SkDraw&, const SkBitmap&, const SkIRect& center, - const SkRect& dst, const SkPaint&); + const SkRect& dst, const SkPaint&); + virtual void drawBitmapLattice(const SkDraw&, const SkBitmap&, const SkCanvas::Lattice&, + const SkRect& dst, const SkPaint&); virtual void drawImage(const SkDraw&, const SkImage*, SkScalar x, SkScalar y, const SkPaint&); virtual void drawImageRect(const SkDraw&, const SkImage*, const SkRect* src, const SkRect& dst, const SkPaint&, SkCanvas::SrcRectConstraint); virtual void drawImageNine(const SkDraw&, const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint&); + virtual void drawImageLattice(const SkDraw&, const SkImage*, const SkCanvas::Lattice&, + const SkRect& dst, const SkPaint&); /** * Does not handle text decoration. @@ -269,38 +230,30 @@ protected: virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath&, const SkMatrix*, const SkPaint&); + virtual void drawTextRSXform(const SkDraw&, const void* text, size_t len, const SkRSXform[], + const SkPaint&); + + virtual void drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&); + virtual sk_sp makeSpecial(const SkBitmap&); + virtual sk_sp makeSpecial(const SkImage*); + virtual sk_sp snapSpecial(); bool readPixels(const SkImageInfo&, void* dst, size_t rowBytes, int x, int y); /////////////////////////////////////////////////////////////////////////// +#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP /** Update as needed the pixel value in the bitmap, so that the caller can access the pixels directly. @return The device contents as a bitmap */ - virtual const SkBitmap& onAccessBitmap() = 0; - - /** - * Override and return true for filters that the device can handle - * intrinsically. Doing so means that SkCanvas will pass-through this - * filter to drawSprite and drawDevice (and potentially filterImage). - * Returning false means the SkCanvas will have apply the filter itself, - * and just pass the resulting image to the device. - */ - virtual bool canHandleImageFilter(const SkImageFilter*) { return false; } - - /** - * Related (but not required) to canHandleImageFilter, this method returns - * true if the device could apply the filter to the src bitmap and return - * the result (and updates offset as needed). - * If the device does not recognize or support this filter, - * it just returns false and leaves result and offset unchanged. - */ - virtual bool filterImage(const SkImageFilter*, const SkBitmap&, - const SkImageFilter::Context&, - SkBitmap* /*result*/, SkIPoint* /*offset*/) { - return false; + virtual const SkBitmap& onAccessBitmap() { + SkASSERT(0); + return fLegacyBitmap; } +#endif + + virtual GrContext* context() const { return nullptr; } protected: virtual sk_sp makeSurface(const SkImageInfo&, const SkSurfaceProps&); @@ -324,19 +277,6 @@ protected: virtual bool onAccessPixels(SkPixmap*) { return false; } - /** - * PRIVATE / EXPERIMENTAL -- do not call - * This entry point gives the backend an opportunity to take over the rendering - * of 'picture'. If optimization data is available (due to an earlier - * 'optimize' call) this entry point should make use of it and return true - * if all rendering has been done. If false is returned, SkCanvas will - * perform its own rendering pass. It is acceptable for the backend - * to perform some device-specific warm up tasks and then let SkCanvas - * perform the main rendering loop (by return false from here). - */ - virtual bool EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*, - const SkPaint*); - struct CreateInfo { static SkPixelGeometry AdjustGeometry(const SkImageInfo&, TileUsage, SkPixelGeometry, bool preserveLCDText); @@ -348,22 +288,20 @@ protected: : fInfo(info) , fTileUsage(tileUsage) , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, false)) - , fForImageFilter(false) {} + {} CreateInfo(const SkImageInfo& info, TileUsage tileUsage, SkPixelGeometry geo, - bool preserveLCDText, - bool forImageFilter) + bool preserveLCDText) : fInfo(info) , fTileUsage(tileUsage) , fPixelGeometry(AdjustGeometry(info, tileUsage, geo, preserveLCDText)) - , fForImageFilter(forImageFilter) {} + {} const SkImageInfo fInfo; const TileUsage fTileUsage; const SkPixelGeometry fPixelGeometry; - const bool fForImageFilter; }; /** @@ -381,11 +319,8 @@ protected: return NULL; } - /** - * Calls through to drawSprite, processing the imagefilter. - */ - virtual void drawSpriteWithFilter(const SkDraw&, const SkBitmap&, - int x, int y, const SkPaint&); + // A helper function used by derived classes to log the scale factor of a bitmap or image draw. + static void LogDrawScaleFactor(const SkMatrix&, SkFilterQuality); private: friend class SkCanvas; @@ -393,9 +328,9 @@ private: friend class SkDraw; friend class SkDrawIter; friend class SkDeviceFilteredPaint; - friend class SkImageFilter::DeviceProxy; friend class SkNoPixelsBitmapDevice; friend class SkSurface_Raster; + friend class DeviceTestingAccess; // used to change the backend's pixels (and possibly config/rowbytes) // but cannot change the width/height, so there should be no change to @@ -405,6 +340,11 @@ private: virtual bool forceConservativeRasterClip() const { return false; } + /** + * Don't call this! + */ + virtual GrDrawContext* accessDrawContext() { return nullptr; } + // just called by SkCanvas when built as a layer void setOrigin(int x, int y) { fOrigin.set(x, y); } @@ -412,14 +352,20 @@ private: */ virtual void flush() {} - virtual SkImageFilter::Cache* getImageFilterCache() { return NULL; } + virtual SkImageFilterCache* getImageFilterCache() { return NULL; } + + friend class SkBitmapDevice; + void privateResize(int w, int h) { + *const_cast(&fInfo) = fInfo.makeWH(w, h); + } SkIPoint fOrigin; SkMetaData* fMetaData; - SkSurfaceProps fSurfaceProps; + const SkImageInfo fInfo; + const SkSurfaceProps fSurfaceProps; -#ifdef SK_DEBUG - bool fAttachedToCanvas; +#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP + SkBitmap fLegacyBitmap; #endif typedef SkRefCnt INHERITED; diff --git a/gfx/skia/skia/include/core/SkDocument.h b/gfx/skia/skia/include/core/SkDocument.h index e5d8cf3a9bab..418a8374370c 100644 --- a/gfx/skia/skia/include/core/SkDocument.h +++ b/gfx/skia/skia/include/core/SkDocument.h @@ -10,13 +10,13 @@ #include "SkBitmap.h" #include "SkPicture.h" +#include "SkPixelSerializer.h" #include "SkRect.h" #include "SkRefCnt.h" #include "SkString.h" #include "SkTime.h" class SkCanvas; -class SkPixelSerializer; class SkWStream; /** SK_ScalarDefaultDPI is 72 DPI. @@ -35,12 +35,63 @@ class SkWStream; */ class SK_API SkDocument : public SkRefCnt { public: + struct OptionalTimestamp { + SkTime::DateTime fDateTime; + bool fEnabled; + OptionalTimestamp() : fEnabled(false) {} + }; + /** - * Create a PDF-backed document, writing the results into a SkWStream. + * Optional metadata to be passed into the PDF factory function. + */ + struct PDFMetadata { + /** + * 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. + */ + OptionalTimestamp fCreation; + /** + * The date and time the document was most recently modified. + */ + OptionalTimestamp fModified; + }; + + /** + * 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. + * PDF pages are sized in point units. 1 pt == 1/72 inch == + * 127/360 mm. * - * @param SkWStream* A PDF document will be written to this + * @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. @@ -52,49 +103,58 @@ public: * 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. - * @returns NULL if there is an error, otherwise a newly created - * PDF-backed SkDocument. - */ - static SkDocument* CreatePDF(SkWStream*, - SkScalar dpi = SK_ScalarDefaultRasterDPI); - - /** + * @param metadata a PDFmetadata object. Any fields may be left + * empty. * @param jpegEncoder For PDF documents, if a jpegEncoder is set, * use it to encode SkImages and SkBitmaps as [JFIF]JPEGs. * This feature is deprecated and is only supplied for * backwards compatability. - * * The prefered method to create PDFs with JPEG images is * to use SkImage::NewFromEncoded() and not jpegEncoder. * Chromium uses NewFromEncoded. - * * If the encoder is unset, or if jpegEncoder->onEncode() * returns NULL, fall back on encoding images losslessly * with Deflate. + * @param pdfa Iff 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 + * + * @returns NULL if there is an error, otherwise a newly created + * PDF-backed SkDocument. */ - static SkDocument* CreatePDF(SkWStream*, - SkScalar dpi, - SkPixelSerializer* jpegEncoder); + static sk_sp MakePDF(SkWStream* stream, + SkScalar dpi, + const SkDocument::PDFMetadata& metadata, + sk_sp jpegEncoder, + bool pdfa); + + static sk_sp MakePDF(SkWStream* stream, + SkScalar dpi = SK_ScalarDefaultRasterDPI) { + return SkDocument::MakePDF(stream, dpi, SkDocument::PDFMetadata(), + nullptr, false); + } /** * Create a PDF-backed document, writing the results into a file. */ - static SkDocument* CreatePDF(const char outputFilePath[], - SkScalar dpi = SK_ScalarDefaultRasterDPI); + static sk_sp MakePDF(const char outputFilePath[], + SkScalar dpi = SK_ScalarDefaultRasterDPI); /** * Create a XPS-backed document, writing the results into the stream. * Returns NULL if XPS is not supported. */ - static SkDocument* CreateXPS(SkWStream* stream, - SkScalar dpi = SK_ScalarDefaultRasterDPI); + static sk_sp MakeXPS(SkWStream* stream, + SkScalar dpi = SK_ScalarDefaultRasterDPI); /** * Create a XPS-backed document, writing the results into a file. * Returns NULL if XPS is not supported. */ - static SkDocument* CreateXPS(const char path[], - SkScalar dpi = SK_ScalarDefaultRasterDPI); + static sk_sp MakeXPS(const char path[], + SkScalar dpi = SK_ScalarDefaultRasterDPI); + /** * 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 @@ -115,9 +175,8 @@ public: * 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. - * Returns true on success or false on failure. */ - bool close(); + void close(); /** * Call abort() to stop producing the document immediately. @@ -125,34 +184,6 @@ public: */ void abort(); - /** - * Set the document's metadata, if supported by the document - * type. The creationDate and modifiedDate parameters can be - * nullptr. For example: - * - * SkDocument* make_doc(SkWStream* output) { - * std::vector info; - * info.emplace_back(SkString("Title"), SkString("...")); - * info.emplace_back(SkString("Author"), SkString("...")); - * info.emplace_back(SkString("Subject"), SkString("...")); - * info.emplace_back(SkString("Keywords"), SkString("...")); - * info.emplace_back(SkString("Creator"), SkString("...")); - * SkTime::DateTime now; - * SkTime::GetDateTime(&now); - * SkDocument* doc = SkDocument::CreatePDF(output); - * doc->setMetadata(&info[0], (int)info.size(), &now, &now); - * return doc; - * } - */ - struct Attribute { - SkString fKey, fValue; - Attribute(const SkString& k, const SkString& v) : fKey(k), fValue(v) {} - }; - virtual void setMetadata(const SkDocument::Attribute[], - int /* attributeCount */, - const SkTime::DateTime* /* creationDate */, - const SkTime::DateTime* /* modifiedDate */) {} - protected: SkDocument(SkWStream*, void (*)(SkWStream*, bool aborted)); @@ -163,7 +194,7 @@ protected: virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height, const SkRect& content) = 0; virtual void onEndPage() = 0; - virtual bool onClose(SkWStream*) = 0; + virtual void onClose(SkWStream*) = 0; virtual void onAbort() = 0; // Allows subclasses to write to the stream as pages are written. diff --git a/gfx/skia/skia/include/core/SkDraw.h b/gfx/skia/skia/include/core/SkDraw.h index ea8638a9105b..d7068fd3fcb3 100644 --- a/gfx/skia/skia/include/core/SkDraw.h +++ b/gfx/skia/skia/include/core/SkDraw.h @@ -13,6 +13,7 @@ #include "SkCanvas.h" #include "SkMask.h" #include "SkPaint.h" +#include "SkStrokeRec.h" class SkBitmap; class SkClipStack; @@ -29,7 +30,6 @@ class SkRRect; class SkDraw { public: SkDraw(); - SkDraw(const SkDraw& src); void drawPaint(const SkPaint&) const; void drawPoints(SkCanvas::PointMode, size_t count, const SkPoint[], @@ -93,7 +93,7 @@ public: static bool DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, const SkMaskFilter*, const SkMatrix* filterMatrix, SkMask* mask, SkMask::CreateMode mode, - SkPaint::Style style); + SkStrokeRec::InitStyle style); enum RectType { kHair_RectType, @@ -128,6 +128,9 @@ private: bool pathIsMutable, bool drawCoverage, SkBlitter* customBlitter = NULL) const; + void drawLine(const SkPoint[2], const SkPaint&) const; + void drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage, + SkBlitter* customBlitter, bool doFill) const; /** * Return the current clip bounds, in local coordinates, with slop to account * for antialiasing or hairlines (i.e. device-bounds outset by 1, and then @@ -139,17 +142,16 @@ private: bool SK_WARN_UNUSED_RESULT computeConservativeLocalClipBounds(SkRect* bounds) const; - /** Returns the current setting for using fake gamma. */ - SkPaint::FakeGamma SK_WARN_UNUSED_RESULT fakeGamma() const; + /** Returns the current setting for using fake gamma and contrast. */ + uint32_t SK_WARN_UNUSED_RESULT scalerContextFlags() const; public: SkPixmap fDst; const SkMatrix* fMatrix; // required - const SkRegion* fClip; // DEPRECATED const SkRasterClip* fRC; // required - const SkClipStack* fClipStack; // optional - SkBaseDevice* fDevice; // optional + const SkClipStack* fClipStack; // optional, may be null + SkBaseDevice* fDevice; // optional, may be null #ifdef SK_DEBUG void validate() const; diff --git a/gfx/skia/skia/include/core/SkDrawable.h b/gfx/skia/skia/include/core/SkDrawable.h index 2f0a62d8b5eb..6fec3fcf9398 100644 --- a/gfx/skia/skia/include/core/SkDrawable.h +++ b/gfx/skia/skia/include/core/SkDrawable.h @@ -8,9 +8,10 @@ #ifndef SkDrawable_DEFINED #define SkDrawable_DEFINED -#include "SkRefCnt.h" +#include "SkFlattenable.h" class SkCanvas; +class SkMatrix; class SkPicture; struct SkRect; @@ -21,7 +22,7 @@ struct SkRect; * 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 SkDrawable : public SkRefCnt { +class SkDrawable : public SkFlattenable { public: SkDrawable(); @@ -58,6 +59,9 @@ public: */ void notifyDrawingChanged(); + SK_DEFINE_FLATTENABLE_TYPE(SkDrawable) + Factory getFactory() const override { return nullptr; } + protected: virtual SkRect onGetBounds() = 0; virtual void onDraw(SkCanvas*) = 0; diff --git a/gfx/skia/skia/include/core/SkFilterQuality.h b/gfx/skia/skia/include/core/SkFilterQuality.h index db0597e697dd..54fae51fe19e 100644 --- a/gfx/skia/skia/include/core/SkFilterQuality.h +++ b/gfx/skia/skia/include/core/SkFilterQuality.h @@ -18,7 +18,9 @@ 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 + kHigh_SkFilterQuality, //!< slowest but highest quality, typically bicubic or better + + kLast_SkFilterQuality = kHigh_SkFilterQuality }; #endif diff --git a/gfx/skia/skia/include/core/SkFlattenable.h b/gfx/skia/skia/include/core/SkFlattenable.h index c76f119c131d..88aeb7ee3805 100644 --- a/gfx/skia/skia/include/core/SkFlattenable.h +++ b/gfx/skia/skia/include/core/SkFlattenable.h @@ -71,6 +71,7 @@ class SK_API SkFlattenable : public SkRefCnt { public: enum Type { kSkColorFilter_Type, + kSkDrawable_Type, kSkDrawLooper_Type, kSkImageFilter_Type, kSkMaskFilter_Type, @@ -80,6 +81,7 @@ public: kSkShader_Type, kSkUnused_Type, // used to be SkUnitMapper kSkXfermode_Type, + kSkNormalSource_Type, }; typedef sk_sp (*Factory)(SkReadBuffer&); @@ -92,9 +94,15 @@ public: */ virtual Factory getFactory() const = 0; - /** Returns the name of the object's class - */ - const char* getTypeName() const { return FactoryToName(getFactory()); } + /** + * Returns the name of the object's class. + * + * Subclasses should override this function if they intend to provide + * support for flattening without using the global registry. + * + * If the flattenable is registered, there is no need to override. + */ + virtual const char* getTypeName() const { return FactoryToName(getFactory()); } static Factory NameToFactory(const char name[]); static const char* FactoryToName(Factory); diff --git a/gfx/skia/skia/include/core/SkFont.h b/gfx/skia/skia/include/core/SkFont.h index e4ebebb244af..e50909aaec78 100644 --- a/gfx/skia/skia/include/core/SkFont.h +++ b/gfx/skia/skia/include/core/SkFont.h @@ -117,17 +117,21 @@ public: kLCD_MaskType, }; - static SkFont* Create(SkTypeface*, SkScalar size, MaskType, uint32_t flags); - static SkFont* Create(SkTypeface*, SkScalar size, SkScalar scaleX, SkScalar skewX, - MaskType, uint32_t flags); + static sk_sp Make(sk_sp, SkScalar size, MaskType, uint32_t flags); + static sk_sp Make(sk_sp, SkScalar size, SkScalar scaleX, SkScalar skewX, + MaskType, uint32_t flags); /** * Return a font with the same attributes of this font, but with the specified size. * If size is not supported (e.g. <= 0 or non-finite) NULL will be returned. */ - SkFont* cloneWithSize(SkScalar size) const; + sk_sp makeWithSize(SkScalar size) const; + /** + * Return a font with the same attributes of this font, but with the flags. + */ + sk_sp makeWithFlags(uint32_t newFlags) const; - SkTypeface* getTypeface() const { return fTypeface; } + SkTypeface* getTypeface() const { return fTypeface.get(); } SkScalar getSize() const { return fSize; } SkScalar getScaleX() const { return fScaleX; } SkScalar getSkewX() const { return fSkewX; } @@ -139,23 +143,28 @@ public: bool isEnableAutoHints() const { return SkToBool(fFlags & kEnableAutoHints_Flag); } bool isEnableByteCodeHints() const { return SkToBool(fFlags & kEnableByteCodeHints_Flag); } bool isUseNonLinearMetrics() const { return SkToBool(fFlags & kUseNonlinearMetrics_Flag); } + bool isDevKern() const { return SkToBool(fFlags & kDevKern_Flag); } int textToGlyphs(const void* text, size_t byteLength, SkTextEncoding, - uint16_t glyphs[], int maxGlyphCount) const; + SkGlyphID glyphs[], int maxGlyphCount) const; + + int countText(const void* text, size_t byteLength, SkTextEncoding encoding) { + return this->textToGlyphs(text, byteLength, encoding, nullptr, 0); + } SkScalar measureText(const void* text, size_t byteLength, SkTextEncoding) const; - static SkFont* Testing_CreateFromPaint(const SkPaint&); + static sk_sp Testing_CreateFromPaint(const SkPaint&); private: enum { kAllFlags = 0xFF, }; - SkFont(SkTypeface*, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType, uint32_t flags); - virtual ~SkFont(); + SkFont(sk_sp, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType, + uint32_t flags); - SkTypeface* fTypeface; + sk_sp fTypeface; SkScalar fSize; SkScalar fScaleX; SkScalar fSkewX; diff --git a/gfx/skia/skia/include/core/SkFontHost.h b/gfx/skia/skia/include/core/SkFontHost.h deleted file mode 100644 index a2cc04bc7097..000000000000 --- a/gfx/skia/skia/include/core/SkFontHost.h +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * 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 SkFontHost_DEFINED -#define SkFontHost_DEFINED - -#include "SkTypeface.h" - -class SkDescriptor; -class SkScalerContext; -struct SkScalerContextRec; -class SkStream; -class SkWStream; - -/** \class SkFontHost - - This class is ported to each environment. It is responsible for bridging - the gap between the (sort of) abstract class SkTypeface and the - platform-specific implementation that provides access to font files. - - One basic task is for each create (subclass of) SkTypeface, the FontHost is - responsible for assigning a uniqueID. The ID should be unique for the - underlying font file/data, not unique per typeface instance. Thus it is - possible/common to request a typeface for the same font more than once - (e.g. asking for the same font by name several times). The FontHost may - return seperate typeface instances in that case, or it may choose to use a - cache and return the same instance (but calling typeface->ref(), since the - caller is always responsible for calling unref() on each instance that is - returned). Either way, the fontID for those instance(s) will be the same. - In addition, the fontID should never be set to 0. That value is used as a - sentinel to indicate no-font-id. - - The major aspects are: - 1) Given either a name/style, return a subclass of SkTypeface that - references the closest matching font available on the host system. - 2) Given the data for a font (either in a stream or a file name), return - a typeface that allows access to that data. - 3) Each typeface instance carries a 32bit ID for its corresponding font. - SkFontHost turns that ID into a stream to access the font's data. - 4) Given a font ID, return a subclass of SkScalerContext, which connects a - font scaler (e.g. freetype or other) to the font's data. - 5) Utilites to manage the font cache (budgeting) and gamma correction -*/ -class SK_API SkFontHost { -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/gfx/skia/skia/include/core/SkFontLCDConfig.h b/gfx/skia/skia/include/core/SkFontLCDConfig.h index 03ee09f8b55c..58b5a82b9c03 100644 --- a/gfx/skia/skia/include/core/SkFontLCDConfig.h +++ b/gfx/skia/skia/include/core/SkFontLCDConfig.h @@ -10,7 +10,7 @@ #include "SkTypes.h" -class SkFontLCDConfig { +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 diff --git a/gfx/skia/skia/include/core/SkFontStyle.h b/gfx/skia/skia/include/core/SkFontStyle.h index f42d7dd47018..7dd25910a2f0 100644 --- a/gfx/skia/skia/include/core/SkFontStyle.h +++ b/gfx/skia/skia/include/core/SkFontStyle.h @@ -13,15 +13,17 @@ class SK_API SkFontStyle { public: enum Weight { - 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 + 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 { @@ -33,18 +35,19 @@ public: kSemiExpanded_Width = 6, kExpanded_Width = 7, kExtraExpanded_Width = 8, - kUltaExpanded_Width = 9 + kUltraExpanded_Width = 9, }; enum Slant { kUpright_Slant, kItalic_Slant, + kOblique_Slant, }; SkFontStyle(); SkFontStyle(int weight, int width, Slant); - /** oldStyle means the style-bits in SkTypeface::Style: bold=1, italic=2 */ - explicit SkFontStyle(unsigned oldStyle); + + static SkFontStyle FromOldStyle(unsigned oldStyle); bool operator==(const SkFontStyle& rhs) const { return fUnion.fU32 == rhs.fUnion.fU32; @@ -54,10 +57,6 @@ public: int width() const { return fUnion.fR.fWidth; } Slant slant() const { return (Slant)fUnion.fR.fSlant; } - bool isItalic() const { - return kItalic_Slant == fUnion.fR.fSlant; - } - private: union { struct { diff --git a/gfx/skia/skia/include/core/SkImage.h b/gfx/skia/skia/include/core/SkImage.h index 6be3b6e54a95..f55b679c0b13 100644 --- a/gfx/skia/skia/include/core/SkImage.h +++ b/gfx/skia/skia/include/core/SkImage.h @@ -28,8 +28,6 @@ class GrContext; class GrContextThreadSafeProxy; class GrTexture; -#define SK_SUPPORT_LEGACY_IMAGEFACTORY - /** * SkImage is an abstraction for drawing a rectagle of pixels, though the * particular type of image could be actually storing its data on the GPU, or @@ -75,7 +73,7 @@ public: * * If a subset is specified, it must be contained within the generator's bounds. */ - static sk_sp MakeFromGenerator(SkImageGenerator*, const SkIRect* subset = NULL); + static sk_sp MakeFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); /** * Construct a new SkImage based on the specified encoded data. Returns NULL on failure, @@ -83,7 +81,7 @@ public: * * If a subset is specified, it must be contained within the encoded data's bounds. */ - static sk_sp MakeFromEncoded(sk_sp encoded, const SkIRect* subset = NULL); + static sk_sp MakeFromEncoded(sk_sp encoded, const SkIRect* subset = nullptr); /** * Create a new image from the specified descriptor. Note - the caller is responsible for @@ -92,12 +90,12 @@ public: * Will return NULL if the specified descriptor is unsupported. */ static sk_sp MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc) { - return MakeFromTexture(ctx, desc, kPremul_SkAlphaType, NULL, NULL); + return MakeFromTexture(ctx, desc, kPremul_SkAlphaType, nullptr, nullptr, nullptr); } static sk_sp MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& de, SkAlphaType at) { - return MakeFromTexture(ctx, de, at, NULL, NULL); + return MakeFromTexture(ctx, de, at, nullptr, nullptr, nullptr); } typedef void (*TextureReleaseProc)(ReleaseContext); @@ -109,8 +107,21 @@ public: * * Will return NULL if the specified descriptor is unsupported. */ + static sk_sp MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, + SkAlphaType at, TextureReleaseProc trp, + ReleaseContext rc) { + return MakeFromTexture(ctx, desc, at, nullptr, trp, rc); + } + + /** + * Create a new image from the specified descriptor. The underlying platform texture must stay + * valid and unaltered until the specified release-proc is invoked, indicating that Skia + * no longer is holding a reference to it. + * + * Will return NULL if the specified descriptor is unsupported. + */ static sk_sp MakeFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType, - TextureReleaseProc, ReleaseContext); + sk_sp, TextureReleaseProc, ReleaseContext); /** * Create a new image from the specified descriptor. Note - Skia will delete or recycle the @@ -119,16 +130,8 @@ public: * Will return NULL if the specified descriptor is unsupported. */ static sk_sp MakeFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&, - SkAlphaType = kPremul_SkAlphaType); - - /** - * Create a new image by copying the pixels from the specified descriptor. No reference is - * kept to the original platform texture. - * - * Will return NULL if the specified descriptor is unsupported. - */ - static sk_sp MakeFromTextureCopy(GrContext*, const GrBackendTextureDesc&, - SkAlphaType = kPremul_SkAlphaType); + SkAlphaType = kPremul_SkAlphaType, + sk_sp = nullptr); /** * Create a new image by copying the pixels from the specified y, u, v textures. The data @@ -138,7 +141,18 @@ public: static sk_sp MakeFromYUVTexturesCopy(GrContext*, SkYUVColorSpace, const GrBackendObject yuvTextureHandles[3], const SkISize yuvSizes[3], - GrSurfaceOrigin); + GrSurfaceOrigin, + sk_sp = nullptr); + + /** + * Create a new image by copying the pixels from the specified y and uv textures. The data + * from the textures is immediately ingested into the image and the textures can be modified or + * deleted after the function returns. The image will have the dimensions of the y texture. + */ + static sk_sp MakeFromNV12TexturesCopy(GrContext*, SkYUVColorSpace, + const GrBackendObject nv12TextureHandles[2], + const SkISize nv12Sizes[2], GrSurfaceOrigin, + sk_sp = nullptr); static sk_sp MakeFromPicture(sk_sp, const SkISize& dimensions, const SkMatrix*, const SkPaint*); @@ -152,7 +166,8 @@ public: SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); } SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); } uint32_t uniqueID() const { return fUniqueID; } - virtual bool isOpaque() const { return false; } + SkAlphaType alphaType() const; + bool isOpaque() const { return SkAlphaTypeIsOpaque(this->alphaType()); } /** * Extracts YUV planes from the SkImage and stores them in client-provided memory. The sizes @@ -322,10 +337,40 @@ public: */ sk_sp makeTextureImage(GrContext*) const; + /** + * If the image is texture-backed this will make a raster copy of it (or nullptr if reading back + * the pixels fails). Otherwise, it returns the original image. + */ + sk_sp makeNonTextureImage() const; + /** + * Apply a given image filter to this image, and return the filtered result. + * + * The subset represents the active portion of this image. The return value is similarly an + * SkImage, with an active subset (outSubset). This is usually used with texture-backed + * images, where the texture may be approx-match and thus larger than the required size. + * + * clipBounds constrains the device-space extent of the image which may be produced to the + * given rect. + * + * 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, null + * is returned, in which case the offset and outSubset parameters should be ignored by the + * caller. + */ + sk_sp makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, + const SkIRect& clipBounds, SkIRect* outSubset, + SkIPoint* offset) const; + /** Drawing params for which a deferred texture image data should be optimized. */ struct DeferredTextureImageUsageParams { + DeferredTextureImageUsageParams(const SkMatrix matrix, const SkFilterQuality quality, + int preScaleMipLevel) + : fMatrix(matrix), fQuality(quality), fPreScaleMipLevel(preScaleMipLevel) {} SkMatrix fMatrix; SkFilterQuality fQuality; + int fPreScaleMipLevel; }; /** @@ -351,7 +396,9 @@ public: size_t getDeferredTextureImageData(const GrContextThreadSafeProxy&, const DeferredTextureImageUsageParams[], int paramCnt, - void* buffer) const; + void* buffer, + SkSourceGammaTreatment treatment = + SkSourceGammaTreatment::kIgnore) const; /** * Returns a texture-backed image from data produced in SkImage::getDeferredTextureImageData. @@ -377,7 +424,7 @@ public: * to empty. */ bool asLegacyBitmap(SkBitmap*, LegacyBitmapMode) const; - + /** * Returns true if the image is backed by an image-generator or other src that creates * (and caches) its pixels / texture on-demand. @@ -392,21 +439,19 @@ public: static SkImage* NewFromRaster(const Info&, const void* pixels, size_t rowBytes, RasterReleaseProc, ReleaseContext); static SkImage* NewFromBitmap(const SkBitmap&); - static SkImage* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = NULL); - static SkImage* NewFromEncoded(SkData* encoded, const SkIRect* subset = NULL); + static SkImage* NewFromGenerator(SkImageGenerator*, const SkIRect* subset = nullptr); + static SkImage* NewFromEncoded(SkData* encoded, const SkIRect* subset = nullptr); static SkImage* NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc) { - return NewFromTexture(ctx, desc, kPremul_SkAlphaType, NULL, NULL); + return NewFromTexture(ctx, desc, kPremul_SkAlphaType, nullptr, nullptr); } static SkImage* NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& de, SkAlphaType at) { - return NewFromTexture(ctx, de, at, NULL, NULL); + return NewFromTexture(ctx, de, at, nullptr, nullptr); } static SkImage* NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType, TextureReleaseProc, ReleaseContext); static SkImage* NewFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType = kPremul_SkAlphaType); - static SkImage* NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, - SkAlphaType = kPremul_SkAlphaType); static SkImage* NewFromYUVTexturesCopy(GrContext*, SkYUVColorSpace, const GrBackendObject yuvTextureHandles[3], const SkISize yuvSizes[3], @@ -424,6 +469,10 @@ protected: SkImage(int width, int height, uint32_t uniqueID); private: + static sk_sp MakeTextureFromMipMap(GrContext*, const SkImageInfo&, + const GrMipLevel* texels, int mipLevelCount, + SkBudgeted, SkSourceGammaTreatment); + const int fWidth; const int fHeight; const uint32_t fUniqueID; diff --git a/gfx/skia/skia/include/core/SkImageDeserializer.h b/gfx/skia/skia/include/core/SkImageDeserializer.h new file mode 100644 index 000000000000..ba1422647b37 --- /dev/null +++ b/gfx/skia/skia/include/core/SkImageDeserializer.h @@ -0,0 +1,36 @@ +/* + * 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 SkImageDeserializer_DEFINED +#define SkImageDeserializer_DEFINED + +#include "SkRefCnt.h" + +struct SkIRect; +class SkData; +class SkImage; + +class SK_API SkImageDeserializer { +public: + virtual ~SkImageDeserializer() {} + + /** + * Given a data containing serialized content, return an SkImage from it. + * + * @param data The data containing the encoded image. The subclass may ref this for later + * decoding, or read it and process it immediately. + * @param subset Optional rectangle represent the subset of the encoded data that is being + * requested to be turned into an image. + * @return The new image, or nullptr on failure. + * + * The default implementation is to call SkImage::MakeFromEncoded(...) + */ + virtual sk_sp makeFromData(SkData*, const SkIRect* subset); + virtual sk_sp makeFromMemory(const void* data, size_t length, const SkIRect* subset); +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkImageEncoder.h b/gfx/skia/skia/include/core/SkImageEncoder.h index 1ccfae0bf9ee..7d15250917cf 100644 --- a/gfx/skia/skia/include/core/SkImageEncoder.h +++ b/gfx/skia/skia/include/core/SkImageEncoder.h @@ -91,7 +91,7 @@ protected: // This macro declares a global (i.e., non-class owned) creation entry point // for each encoder (e.g., CreateJPEGImageEncoder) #define DECLARE_ENCODER_CREATOR(codec) \ - SkImageEncoder *Create ## codec (); + SK_API SkImageEncoder *Create ## codec (); // This macro defines the global creation entry point for each encoder. Each // encoder implementation that registers with the encoder factory must call it. @@ -100,22 +100,17 @@ protected: // All the encoders known by Skia. Note that, depending on the compiler settings, // not all of these will be available -/** An ARGBImageEncoder will always write out - * bitmap.width() * bitmap.height() * 4 - * bytes. - */ -DECLARE_ENCODER_CREATOR(ARGBImageEncoder); DECLARE_ENCODER_CREATOR(JPEGImageEncoder); DECLARE_ENCODER_CREATOR(PNGImageEncoder); DECLARE_ENCODER_CREATOR(KTXImageEncoder); DECLARE_ENCODER_CREATOR(WEBPImageEncoder); #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) -DECLARE_ENCODER_CREATOR(PNGImageEncoder_CG); +SkImageEncoder* CreateImageEncoder_CG(SkImageEncoder::Type type); #endif #if defined(SK_BUILD_FOR_WIN) -DECLARE_ENCODER_CREATOR(ImageEncoder_WIC); +SkImageEncoder* CreateImageEncoder_WIC(SkImageEncoder::Type type); #endif // Typedef to make registering encoder callback easier diff --git a/gfx/skia/skia/include/core/SkImageFilter.h b/gfx/skia/skia/include/core/SkImageFilter.h index 8a8e512254f2..9188a89e274f 100644 --- a/gfx/skia/skia/include/core/SkImageFilter.h +++ b/gfx/skia/skia/include/core/SkImageFilter.h @@ -11,19 +11,19 @@ #include "../private/SkTArray.h" #include "../private/SkTemplates.h" #include "../private/SkMutex.h" +#include "SkColorSpace.h" #include "SkFilterQuality.h" #include "SkFlattenable.h" #include "SkMatrix.h" #include "SkRect.h" -#include "SkSurfaceProps.h" +class GrContext; class GrFragmentProcessor; -class GrTexture; -class SkBaseDevice; -class SkBitmap; class SkColorFilter; struct SkIPoint; class SkSpecialImage; +class SkImageFilterCache; +struct SkImageFilterCacheKey; /** * Base class for image filters. If one is installed in the paint, then @@ -34,38 +34,42 @@ class SkSpecialImage; */ class SK_API SkImageFilter : public SkFlattenable { public: - // This cache maps from (filter's unique ID + CTM + clipBounds + src bitmap generation ID) to - // (result, offset). - class Cache : public SkRefCnt { + // 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: - struct Key; - virtual ~Cache() {} - static Cache* Create(size_t maxBytes); - static Cache* Get(); - virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const = 0; - virtual SkSpecialImage* get(const Key& key, SkIPoint* offset) const = 0; - virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) = 0; - virtual void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) = 0; - virtual void purge() {} - virtual void purgeByKeys(const Key[], int) {} + explicit OutputProperties(SkColorSpace* colorSpace) : fColorSpace(colorSpace) {} + + SkColorSpace* colorSpace() const { return fColorSpace; } + + private: + // 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, Cache* cache) + 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; } - Cache* cache() const { return fCache; } + SkImageFilterCache* cache() const { return fCache; } + const OutputProperties& outputProperties() const { return fOutputProperties; } private: - SkMatrix fCTM; - SkIRect fClipBounds; - Cache* fCache; + SkMatrix fCTM; + SkIRect fClipBounds; + SkImageFilterCache* fCache; + OutputProperties fOutputProperties; }; class CropRect { @@ -109,38 +113,8 @@ public: kNever_TileUsage, //!< the created device will never be drawn tiled }; - class Proxy { - public: - virtual ~Proxy() {} - - virtual SkBaseDevice* createDevice(int width, int height, - TileUsage usage = kNever_TileUsage) = 0; - - // Returns true if the proxy handled the filter itself. If this returns - // false then the filter's code will be called. - virtual bool filterImage(const SkImageFilter*, const SkBitmap& src, - const SkImageFilter::Context&, - SkBitmap* result, SkIPoint* offset) = 0; - }; - - class DeviceProxy : public Proxy { - public: - DeviceProxy(SkBaseDevice* device) : fDevice(device) {} - - SkBaseDevice* createDevice(int width, int height, - TileUsage usage = kNever_TileUsage) override; - - // Returns true if the proxy handled the filter itself. If this returns - // false then the filter's code will be called. - bool filterImage(const SkImageFilter*, const SkBitmap& src, const SkImageFilter::Context&, - SkBitmap* result, SkIPoint* offset) override; - - private: - SkBaseDevice* fDevice; - }; - /** - * Request a new (result) image to be created from the src image. + * 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. @@ -148,8 +122,9 @@ public: * 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, return null, in which case - * the offset parameters will be ignored by the caller. + * 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. @@ -174,27 +149,12 @@ public: SkIRect filterBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection = kReverse_MapDirection) const; - /** - * Returns true if the filter can be processed on the GPU. This is most - * often used for multi-pass effects, where intermediate results must be - * rendered to textures. For single-pass effects, use asFragmentProcessor(). - * The default implementation returns asFragmentProcessor(NULL, NULL, SkMatrix::I(), - * SkIRect()). - */ - virtual bool canFilterImageGPU() const; - - /** - * Process this image filter on the GPU. This is most often used for - * multi-pass effects, where intermediate results must be rendered to - * textures. For single-pass effects, use asFragmentProcessor(). src is the - * source image for processing, as a texture-backed bitmap. result is - * the destination bitmap, which should contain a texture-backed pixelref - * on success. offset is the amount to translate the resulting image - * relative to the src when it is drawn. The default implementation does - * single-pass processing using asFragmentProcessor(). - */ - virtual bool filterImageGPUDeprecated(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const; +#if SK_SUPPORT_GPU + static sk_sp DrawWithFP(GrContext* context, + sk_sp fp, + const SkIRect& bounds, + const OutputProperties& outputProperties); +#endif /** * Returns whether this image filter is a color filter and puts the color filter into the @@ -212,6 +172,10 @@ public: return this->isColorFilterNode(filterPtr); } + static sk_sp MakeBlur(SkScalar sigmaX, SkScalar sigmaY, + sk_sp input, + const CropRect* cropRect = nullptr); + /** * 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 @@ -223,15 +187,15 @@ public: * Returns the number of inputs this filter will accept (some inputs can * be NULL). */ - int countInputs() const { return fInputCount; } + 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 < fInputCount); - return fInputs[i]; + SkASSERT(i < fInputs.count()); + return fInputs[i].get(); } /** @@ -241,9 +205,7 @@ public: * 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 and - * filterImageGPU(). (The latter ensures that the resulting buffer is - * drawn in the correct location.) + * be added to the "offset" parameter in onFilterImage. */ bool cropRectIsSet() const { return fCropRect.flags() != 0x0; } @@ -268,11 +230,19 @@ public: #endif /** - * Create an SkMatrixImageFilter, which transforms its input by the given matrix. + * 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, + SkFilterQuality quality, sk_sp input); + #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR static SkImageFilter* CreateMatrixFilter(const SkMatrix& matrix, SkFilterQuality filterQuality, @@ -281,26 +251,9 @@ public: } #endif - - sk_sp filterInput(int index, - SkSpecialImage* src, - const Context&, - SkIPoint* offset) const; - -#if SK_SUPPORT_GPU - // Helper function which invokes GPU filter processing on the - // input at the specified "index". If the input is null, it leaves - // "result" and "offset" untouched, and returns true. If the input - // has a GPU implementation, it will be invoked directly. - // Otherwise, the filter will be processed in software and - // uploaded to the GPU. - bool filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy, - const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const; -#endif - SK_TO_STRING_PUREVIRT() SK_DEFINE_FLATTENABLE_TYPE(SkImageFilter) + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() protected: class Common { @@ -321,12 +274,6 @@ protected: sk_sp getInput(int index) const { return fInputs[index]; } - // If the caller wants a copy of the inputs, call this and it will transfer ownership - // of the unflattened input filters to the caller. This is just a short-cut for copying - // the inputs, calling ref() on each, and then waiting for Common's destructor to call - // unref() on each. - void detachInputs(SkImageFilter** inputs); - private: CropRect fCropRect; // most filters accept at most 2 input-filters @@ -335,8 +282,6 @@ protected: void allocInputs(int count); }; - SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect = nullptr); - SkImageFilter(sk_sp* inputs, int inputCount, const CropRect* cropRect); virtual ~SkImageFilter(); @@ -364,15 +309,15 @@ protected: * 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, this should false, in which - * case both the result and offset parameters will be ignored by the - * caller. + * 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 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const; - virtual sk_sp onFilterImage(SkSpecialImage* src, const Context&, - SkIPoint* offset) const; + SkIPoint* offset) const = 0; /** * This function recurses into its inputs with the given rect (first @@ -403,12 +348,13 @@ protected: virtual SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const; // Helper function which invokes filter processing on the input at the - // specified "index". If the input is null, it leaves "result" and - // "offset" untouched, and returns true. If the input is non-null, it - // calls filterImage() on that input, and returns true on success. - // i.e., return !getInput(index) || getInput(index)->filterImage(...); - bool filterInputDeprecated(int index, Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const; + // 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 @@ -418,13 +364,18 @@ protected: return false; } - /** Given a "srcBounds" rect, computes destination bounds for this - * 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 + /** + * 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; @@ -438,30 +389,9 @@ protected: * which are not capable of processing a smaller source bitmap into a * larger destination. */ - bool applyCropRectDeprecated(const Context&, Proxy* proxy, const SkBitmap& src, - SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* result) const; - sk_sp applyCropRect(const Context&, SkSpecialImage* src, SkIPoint* srcOffset, SkIRect* bounds) const; - /** - * Returns true if the filter can be expressed a single-pass - * GrProcessor, used to process this filter on the GPU, or false if - * not. - * - * If effect is non-NULL, a new GrProcessor instance is stored - * in it. The caller assumes ownership of the stage, and it is up to the - * caller to unref it. - * - * The effect can assume its vertexCoords space maps 1-to-1 with texels - * in the texture. "matrix" is a transformation to apply to filter - * parameters before they are used in the effect. Note that this function - * will be called with (NULL, NULL, SkMatrix::I()) to query for support, - * so returning "true" indicates support for all possible matrices. - */ - virtual bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, - const 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 @@ -474,20 +404,19 @@ private: friend class SkGraphics; static void PurgeCache(); - bool filterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const; + void init(sk_sp* inputs, int inputCount, const CropRect* cropRect); bool usesSrcInput() const { return fUsesSrcInput; } virtual bool affectsTransparentBlack() const { return false; } - typedef SkFlattenable INHERITED; - int fInputCount; - SkImageFilter** fInputs; + SkAutoSTArray<2, sk_sp> fInputs; + bool fUsesSrcInput; CropRect fCropRect; uint32_t fUniqueID; // Globally unique - mutable SkTArray fCacheKeys; + mutable SkTArray fCacheKeys; mutable SkMutex fMutex; + typedef SkFlattenable INHERITED; }; /** diff --git a/gfx/skia/skia/include/core/SkImageGenerator.h b/gfx/skia/skia/include/core/SkImageGenerator.h index 1a46f6b9cd7d..3712a924a55f 100644 --- a/gfx/skia/skia/include/core/SkImageGenerator.h +++ b/gfx/skia/skia/include/core/SkImageGenerator.h @@ -251,7 +251,11 @@ public: } protected: - SkImageGenerator(const SkImageInfo& info); + enum { + kNeedNewImageUniqueID = 0 + }; + + SkImageGenerator(const SkImageInfo& info, uint32_t uniqueId = kNeedNewImageUniqueID); virtual SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM); diff --git a/gfx/skia/skia/include/core/SkImageInfo.h b/gfx/skia/skia/include/core/SkImageInfo.h index c55edd36c225..cf50acacae43 100644 --- a/gfx/skia/skia/include/core/SkImageInfo.h +++ b/gfx/skia/skia/include/core/SkImageInfo.h @@ -8,6 +8,7 @@ #ifndef SkImageInfo_DEFINED #define SkImageInfo_DEFINED +#include "SkColorSpace.h" #include "SkMath.h" #include "SkRect.h" #include "SkSize.h" @@ -105,6 +106,25 @@ static int SkColorTypeBytesPerPixel(SkColorType ct) { return gSize[ct]; } +static int SkColorTypeShiftPerPixel(SkColorType ct) { + static const uint8_t gShift[] = { + 0, // Unknown + 0, // Alpha_8 + 1, // RGB_565 + 1, // ARGB_4444 + 2, // RGBA_8888 + 2, // BGRA_8888 + 0, // kIndex_8 + 0, // kGray_8 + 3, // kRGBA_F16 + }; + static_assert(SK_ARRAY_COUNT(gShift) == (size_t)(kLastEnum_SkColorType + 1), + "size_mismatch_with_SkColorType_enum"); + + SkASSERT((size_t)ct < SK_ARRAY_COUNT(gShift)); + return gShift[ct]; +} + static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) { return width * SkColorTypeBytesPerPixel(ct); } @@ -114,15 +134,10 @@ static inline bool SkColorTypeIsValid(unsigned value) { } static inline size_t SkColorTypeComputeOffset(SkColorType ct, int x, int y, size_t rowBytes) { - int shift = 0; - switch (SkColorTypeBytesPerPixel(ct)) { - case 8: shift = 3; break; - case 4: shift = 2; break; - case 2: shift = 1; break; - case 1: shift = 0; break; - default: return 0; + if (kUnknown_SkColorType == ct) { + return 0; } - return y * rowBytes + (x << shift); + return y * rowBytes + (x << SkColorTypeShiftPerPixel(ct)); } /////////////////////////////////////////////////////////////////////////////// @@ -154,11 +169,9 @@ enum SkYUVColorSpace { /////////////////////////////////////////////////////////////////////////////// -enum SkColorProfileType { - kLinear_SkColorProfileType, - kSRGB_SkColorProfileType, - - kLastEnum_SkColorProfileType = kSRGB_SkColorProfileType +enum class SkSourceGammaTreatment { + kRespect, + kIgnore, }; /** @@ -168,61 +181,59 @@ enum SkColorProfileType { struct SK_API SkImageInfo { public: SkImageInfo() - : fWidth(0) + : fColorSpace(nullptr) + , fWidth(0) , fHeight(0) , fColorType(kUnknown_SkColorType) , fAlphaType(kUnknown_SkAlphaType) - , fProfileType(kLinear_SkColorProfileType) {} static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at, - SkColorProfileType pt = kLinear_SkColorProfileType) { - return SkImageInfo(width, height, ct, at, pt); + sk_sp cs = nullptr) { + return SkImageInfo(width, height, ct, at, std::move(cs)); } /** * Sets colortype to the native ARGB32 type. */ static SkImageInfo MakeN32(int width, int height, SkAlphaType at, - SkColorProfileType pt = kLinear_SkColorProfileType) { - return SkImageInfo(width, height, kN32_SkColorType, at, pt); + sk_sp cs = nullptr) { + return Make(width, height, kN32_SkColorType, at, cs); } + /** + * Create an ImageInfo marked as SRGB with N32 swizzle. + */ + static SkImageInfo MakeS32(int width, int height, SkAlphaType at); + /** * Sets colortype to the native ARGB32 type, and the alphatype to premul. */ - static SkImageInfo MakeN32Premul(int width, int height, - SkColorProfileType pt = kLinear_SkColorProfileType) { - return SkImageInfo(width, height, kN32_SkColorType, kPremul_SkAlphaType, pt); + static SkImageInfo MakeN32Premul(int width, int height, sk_sp cs = nullptr) { + return Make(width, height, kN32_SkColorType, kPremul_SkAlphaType, cs); } - /** - * Sets colortype to the native ARGB32 type, and the alphatype to premul. - */ - static SkImageInfo MakeN32Premul(const SkISize& size, - SkColorProfileType pt = kLinear_SkColorProfileType) { - return MakeN32Premul(size.width(), size.height(), pt); + static SkImageInfo MakeN32Premul(const SkISize& size) { + return MakeN32Premul(size.width(), size.height()); } static SkImageInfo MakeA8(int width, int height) { - return SkImageInfo(width, height, kAlpha_8_SkColorType, kPremul_SkAlphaType, - kLinear_SkColorProfileType); + return Make(width, height, kAlpha_8_SkColorType, kPremul_SkAlphaType, nullptr); } static SkImageInfo MakeUnknown(int width, int height) { - return SkImageInfo(width, height, kUnknown_SkColorType, kUnknown_SkAlphaType, - kLinear_SkColorProfileType); + return Make(width, height, kUnknown_SkColorType, kUnknown_SkAlphaType, nullptr); } static SkImageInfo MakeUnknown() { - return SkImageInfo(); + return MakeUnknown(0, 0); } - + int width() const { return fWidth; } int height() const { return fHeight; } SkColorType colorType() const { return fColorType; } SkAlphaType alphaType() const { return fAlphaType; } - SkColorProfileType profileType() const { return fProfileType; } + SkColorSpace* colorSpace() const { return fColorSpace.get(); } bool isEmpty() const { return fWidth <= 0 || fHeight <= 0; } @@ -230,32 +241,37 @@ public: return SkAlphaTypeIsOpaque(fAlphaType); } - bool isLinear() const { return kLinear_SkColorProfileType == fProfileType; } - bool isSRGB() const { return kSRGB_SkColorProfileType == fProfileType; } - SkISize dimensions() const { return SkISize::Make(fWidth, fHeight); } SkIRect bounds() const { return SkIRect::MakeWH(fWidth, fHeight); } + bool gammaCloseToSRGB() const { + return fColorSpace && fColorSpace->gammaCloseToSRGB(); + } + /** * Return a new ImageInfo with the same colortype and alphatype as this info, * but with the specified width and height. */ SkImageInfo makeWH(int newWidth, int newHeight) const { - return SkImageInfo::Make(newWidth, newHeight, fColorType, fAlphaType, fProfileType); + return Make(newWidth, newHeight, fColorType, fAlphaType, fColorSpace); } SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const { - return SkImageInfo::Make(fWidth, fHeight, fColorType, newAlphaType, fProfileType); + return Make(fWidth, fHeight, fColorType, newAlphaType, fColorSpace); } SkImageInfo makeColorType(SkColorType newColorType) const { - return SkImageInfo::Make(fWidth, fHeight, newColorType, fAlphaType, fProfileType); + return Make(fWidth, fHeight, newColorType, fAlphaType, fColorSpace); } - int bytesPerPixel() const { - return SkColorTypeBytesPerPixel(fColorType); + SkImageInfo makeColorSpace(sk_sp cs) const { + return Make(fWidth, fHeight, fColorType, fAlphaType, std::move(cs)); } + int bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); } + + int shiftPerPixel() const { return SkColorTypeShiftPerPixel(fColorType); } + uint64_t minRowBytes64() const { return sk_64_mul(fWidth, this->bytesPerPixel()); } @@ -271,10 +287,12 @@ public: } bool operator==(const SkImageInfo& other) const { - return 0 == memcmp(this, &other, sizeof(other)); + return fWidth == other.fWidth && fHeight == other.fHeight && + fColorType == other.fColorType && fAlphaType == other.fAlphaType && + SkColorSpace::Equals(fColorSpace.get(), other.fColorSpace.get()); } bool operator!=(const SkImageInfo& other) const { - return 0 != memcmp(this, &other, sizeof(other)); + return !(*this == other); } void unflatten(SkReadBuffer&); @@ -300,32 +318,42 @@ public: return rowBytes >= rb; } + void reset() { + fColorSpace = nullptr; + fWidth = 0; + fHeight = 0; + fColorType = kUnknown_SkColorType; + fAlphaType = kUnknown_SkAlphaType; + } + SkDEBUGCODE(void validate() const;) private: + sk_sp fColorSpace; int fWidth; int fHeight; SkColorType fColorType; SkAlphaType fAlphaType; - SkColorProfileType fProfileType; - SkImageInfo(int width, int height, SkColorType ct, SkAlphaType at, SkColorProfileType pt) - : fWidth(width) + SkImageInfo(int width, int height, SkColorType ct, SkAlphaType at, sk_sp cs) + : fColorSpace(std::move(cs)) + , fWidth(width) , fHeight(height) , fColorType(ct) , fAlphaType(at) - , fProfileType(pt) {} }; /////////////////////////////////////////////////////////////////////////////// -static inline bool SkColorAndProfileAreGammaCorrect(SkColorType ct, SkColorProfileType pt) { - return kSRGB_SkColorProfileType == pt || kRGBA_F16_SkColorType == ct; +static inline bool SkColorAndColorSpaceAreGammaCorrect(SkColorType ct, SkColorSpace* cs) { + // Anything with a color-space attached is gamma-correct, as is F16. + // To get legacy behavior, you need to ask for non-F16, with a nullptr color space. + return (cs != nullptr) || kRGBA_F16_SkColorType == ct; } static inline bool SkImageInfoIsGammaCorrect(const SkImageInfo& info) { - return SkColorAndProfileAreGammaCorrect(info.colorType(), info.profileType()); + return SkColorAndColorSpaceAreGammaCorrect(info.colorType(), info.colorSpace()); } #endif diff --git a/gfx/skia/skia/include/core/SkLights.h b/gfx/skia/skia/include/core/SkLights.h new file mode 100644 index 000000000000..954168de4d1e --- /dev/null +++ b/gfx/skia/skia/include/core/SkLights.h @@ -0,0 +1,199 @@ + +/* + * 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 "../private/SkTArray.h" +#include "SkPoint3.h" +#include "SkRefCnt.h" + +class SkReadBuffer; +class SkWriteBuffer; +class SkImage; + +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) + , fShadowMap(other.fShadowMap) + , fIsRadial(other.fIsRadial) { + } + + Light(Light&& other) + : fType(other.fType) + , fColor(other.fColor) + , fDirOrPos(other.fDirOrPos) + , fIntensity(other.fIntensity) + , fShadowMap(std::move(other.fShadowMap)) + , fIsRadial(other.fIsRadial) { + } + + static Light MakeDirectional(const SkColor3f& color, const SkVector3& dir, + bool isRadial = false) { + Light light(kDirectional_LightType, color, dir, isRadial); + 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, + bool isRadial = false) { + return Light(kPoint_LightType, color, pos, intensity, isRadial); + } + + 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; + } + + void setShadowMap(sk_sp shadowMap) { + fShadowMap = std::move(shadowMap); + } + + SkImage* getShadowMap() const { + return fShadowMap.get(); + } + + bool isRadial() const { return fIsRadial; } + + Light& operator= (const Light& b) { + if (this == &b) { + return *this; + } + + fColor = b.fColor; + fType = b.fType; + fDirOrPos = b.fDirOrPos; + fIntensity = b.fIntensity; + fShadowMap = b.fShadowMap; + fIsRadial = b.fIsRadial; + return *this; + } + + bool operator== (const Light& b) { + if (this == &b) { + return true; + } + + return (fColor == b.fColor) && + (fType == b.fType) && + (fDirOrPos == b.fDirOrPos) && + (fShadowMap == b.fShadowMap) && + (fIntensity == b.fIntensity) && + (fIsRadial == b.fIsRadial); + } + + bool operator!= (const Light& b) { return !(this->operator==(b)); } + + private: + 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. + sk_sp fShadowMap; + bool fIsRadial; // Whether the light is radial or not. Radial lights will + // cast shadows and lights radially outwards. + + Light(LightType type, const SkColor3f& color, const SkVector3& dirOrPos, + SkScalar intensity = 0.0f, bool isRadial = false) { + fType = type; + fColor = color; + fDirOrPos = dirOrPos; + fIntensity = intensity; + fIsRadial = isRadial; + } + }; + + 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; + }; + + int numLights() const { + return fLights.count(); + } + + const Light& light(int index) const { + return fLights[index]; + } + + Light& light(int index) { + return fLights[index]; + } + + const SkColor3f& ambientLightColor() const { + return fAmbientLightColor; + } + + static sk_sp MakeFromBuffer(SkReadBuffer& buf); + + void flatten(SkWriteBuffer& buf) const; + +private: + SkLights() { + fAmbientLightColor.set(0.0f, 0.0f, 0.0f); + } + SkTArray fLights; + SkColor3f fAmbientLightColor; + typedef SkRefCnt INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/core/SkMaskFilter.h b/gfx/skia/skia/include/core/SkMaskFilter.h index 8d3d1caa6765..95a663d56db2 100644 --- a/gfx/skia/skia/include/core/SkMaskFilter.h +++ b/gfx/skia/skia/include/core/SkMaskFilter.h @@ -14,8 +14,10 @@ #include "SkFlattenable.h" #include "SkMask.h" #include "SkPaint.h" +#include "SkStrokeRec.h" class GrClip; +class GrContext; class GrDrawContext; class GrPaint; class GrRenderTarget; @@ -27,7 +29,6 @@ class SkMatrix; class SkPath; class SkRasterClip; class SkRRect; -class SkStrokeRec; /** \class SkMaskFilter @@ -122,27 +123,26 @@ public: * Try to directly render a rounded rect mask filter into the target. Returns * true if drawing was successful. */ - virtual bool directFilterRRectMaskGPU(GrTextureProvider* texProvider, + virtual bool directFilterRRectMaskGPU(GrContext*, GrDrawContext* drawContext, GrPaint* grp, const GrClip&, const SkMatrix& viewMatrix, const SkStrokeRec& strokeRec, - const SkRRect& rrect) const; + const SkRRect& rrect, + const SkRRect& devRRect) const; /** * This function is used to implement filters that require an explicit src mask. It should only * be called if canFilterMaskGPU returned true and the maskRect param should be the output from - * that call. canOverwriteSrc indicates whether the implementation may treat src as a scratch - * texture and overwrite its contents. When true it is also legal to return src as the result. + * that call. * Implementations are free to get the GrContext from the src texture in order to create * additional textures and perform multiple passes. */ virtual bool filterMaskGPU(GrTexture* src, const SkMatrix& ctm, - const SkRect& maskRect, - GrTexture** result, - bool canOverwriteSrc) const; + const SkIRect& maskRect, + GrTexture** result) const; #endif /** @@ -228,14 +228,14 @@ private: This method is not exported to java. */ bool filterPath(const SkPath& devPath, const SkMatrix& ctm, const SkRasterClip&, SkBlitter*, - SkPaint::Style) const; + SkStrokeRec::InitStyle) const; /** Helper method that, given a roundRect in device space, will rasterize it into a kA8_Format mask and then call filterMask(). If this returns true, the specified blitter will be called to render that mask. Returns false if filterMask() returned false. */ bool filterRRect(const SkRRect& devRRect, const SkMatrix& ctm, const SkRasterClip&, - SkBlitter*, SkPaint::Style style) const; + SkBlitter*) const; typedef SkFlattenable INHERITED; }; diff --git a/gfx/skia/skia/include/core/SkMath.h b/gfx/skia/skia/include/core/SkMath.h index abb685f6daa3..6e252306df07 100644 --- a/gfx/skia/skia/include/core/SkMath.h +++ b/gfx/skia/skia/include/core/SkMath.h @@ -52,13 +52,6 @@ static inline int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom) { return sk_64_asS32(tmp); } -/** - * Computes (numer1 << shift) / denom in full 64 intermediate precision. - * It is an error for denom to be 0. There is no special handling if - * the result overflows 32bits. - */ -int32_t SkDivBits(int32_t numer, int32_t denom, int shift); - /** * Return the integer square root of value, with a bias of bitBias */ @@ -68,35 +61,6 @@ int32_t SkSqrtBits(int32_t value, int bitBias); */ #define SkSqrt32(n) SkSqrtBits(n, 15) -//! Returns the number of leading zero bits (0...32) -int SkCLZ_portable(uint32_t); - -#ifndef SkCLZ - #if defined(_MSC_VER) - #include - - static inline int SkCLZ(uint32_t mask) { - if (mask) { - DWORD index; - _BitScanReverse(&index, mask); - // Suppress this bogus /analyze warning. The check for non-zero - // guarantees that _BitScanReverse will succeed. -#pragma warning(suppress : 6102) // Using 'index' from failed function call - return index ^ 0x1F; - } else { - return 32; - } - } - #elif defined(SK_CPU_ARM32) || defined(__GNUC__) || defined(__clang__) - static inline int SkCLZ(uint32_t mask) { - // __builtin_clz(0) is undefined, so we have to detect that case. - return mask ? __builtin_clz(mask) : 32; - } - #else - #define SkCLZ(x) SkCLZ_portable(x) - #endif -#endif - /** * Returns (value < 0 ? 0 : value) efficiently (i.e. no compares or branches) */ @@ -122,35 +86,11 @@ static inline int SkClampMax(int value, int max) { return value; } -/** - * Returns the smallest power-of-2 that is >= the specified value. If value - * is already a power of 2, then it is returned unchanged. It is undefined - * if value is <= 0. - */ -static inline int SkNextPow2(int value) { - SkASSERT(value > 0); - return 1 << (32 - SkCLZ(value - 1)); -} - -/** - * Returns the log2 of the specified value, were that value to be rounded up - * to the next power of 2. It is undefined to pass 0. Examples: - * SkNextLog2(1) -> 0 - * SkNextLog2(2) -> 1 - * SkNextLog2(3) -> 2 - * SkNextLog2(4) -> 2 - * SkNextLog2(5) -> 3 - */ -static inline int SkNextLog2(uint32_t value) { - SkASSERT(value != 0); - return 32 - SkCLZ(value - 1); -} - /** * Returns true if value is a power of 2. Does not explicitly check for * value <= 0. */ -template inline bool SkIsPow2(T value) { +template constexpr inline bool SkIsPow2(T value) { return (value & (value - 1)) == 0; } diff --git a/gfx/skia/skia/include/core/SkMatrix.h b/gfx/skia/skia/include/core/SkMatrix.h index adebada44591..f565a537ba42 100644 --- a/gfx/skia/skia/include/core/SkMatrix.h +++ b/gfx/skia/skia/include/core/SkMatrix.h @@ -80,7 +80,7 @@ public: /** Returns true if will map a rectangle to another rectangle. This can be true if the matrix is identity, scale-only, or rotates a multiple of - 90 degrees. + 90 degrees, or mirrors in x or y. */ bool rectStaysRect() const { if (fTypeMask & kUnknown_Mask) { @@ -561,6 +561,12 @@ public: this->mapPoints(dst, 4); } + /** + * Maps a rect to another rect, asserting (in debug mode) that the matrix only contains + * scale and translate elements. If it contains other elements, the results are undefined. + */ + void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const; + /** Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in perspective this value assumes the circle has its center at the origin. @@ -704,6 +710,37 @@ public: this->setTypeMask(kUnknown_Mask); } + /** + * Initialize the matrix to be scale + post-translate. + */ + 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); + } + + /** + * Are all elements of the matrix finite? + */ + bool isFinite() const { return SkScalarsAreFinite(fMat, 9); } + private: enum { /** Set if the matrix will map a rectangle to another rectangle. This @@ -736,35 +773,8 @@ private: SkScalar fMat[9]; mutable uint32_t fTypeMask; - /** Are all elements of the matrix finite? - */ - bool isFinite() const { return SkScalarsAreFinite(fMat, 9); } - static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp); - 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); - } - uint8_t computeTypeMask() const; uint8_t computePerspectiveTypeMask() const; @@ -833,6 +843,7 @@ private: static const MapPtsProc gMapPtsProcs[]; friend class SkPerspIter; + friend class SkMatrixPriv; }; SK_END_REQUIRE_DENSE diff --git a/gfx/skia/skia/include/utils/SkMatrix44.h b/gfx/skia/skia/include/core/SkMatrix44.h similarity index 93% rename from gfx/skia/skia/include/utils/SkMatrix44.h rename to gfx/skia/skia/include/core/SkMatrix44.h index 2a698f52a23f..9820ee58cd6e 100644 --- a/gfx/skia/skia/include/utils/SkMatrix44.h +++ b/gfx/skia/skia/include/core/SkMatrix44.h @@ -136,8 +136,15 @@ public: kIdentity_Constructor }; - SkMatrix44(Uninitialized_Constructor) { } - SkMatrix44(Identity_Constructor) { this->setIdentity(); } + SkMatrix44(Uninitialized_Constructor) {} + + constexpr SkMatrix44(Identity_Constructor) + : fMat{{ 1, 0, 0, 0, }, + { 0, 1, 0, 0, }, + { 0, 0, 1, 0, }, + { 0, 0, 0, 1, }} + , fTypeMask(kIdentity_Mask) + {} SK_ATTR_DEPRECATED("use the constructors that take an enum") SkMatrix44() { this->setIdentity(); } @@ -281,6 +288,10 @@ public: * 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; @@ -291,6 +302,11 @@ public: * 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[]); @@ -306,10 +322,12 @@ public: #endif /* This sets the top-left of the matrix and clears the translation and - * perspective components (with [3][3] set to 1). */ + * perspective components (with [3][3] set to 1). mXY is interpreted + * as the matrix entry at col = X, row = Y. */ void set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02, SkMScalar m10, SkMScalar m11, SkMScalar m12, SkMScalar m20, SkMScalar m21, SkMScalar m22); + void set3x3RowMajorf(const float[]); void setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); void preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz); @@ -429,6 +447,7 @@ public: double determinant() const; private: + /* This is indexed by [col][row]. */ SkMScalar fMat[4][4]; mutable unsigned fTypeMask; @@ -438,6 +457,9 @@ private: 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]; } @@ -468,6 +490,8 @@ private: inline bool isTriviallyIdentity() const { return 0 == fTypeMask; } + + friend class SkColorSpace; }; #endif diff --git a/gfx/skia/skia/include/core/SkMilestone.h b/gfx/skia/skia/include/core/SkMilestone.h index 1b93a7b84db5..4c7988ecda44 100644 --- a/gfx/skia/skia/include/core/SkMilestone.h +++ b/gfx/skia/skia/include/core/SkMilestone.h @@ -5,5 +5,5 @@ * found in the LICENSE file. */ #ifndef SK_MILESTONE -#define SK_MILESTONE 51 +#define SK_MILESTONE 55 #endif diff --git a/gfx/skia/skia/include/core/SkPaint.h b/gfx/skia/skia/include/core/SkPaint.h index 57122550b303..ddc90ae19c78 100644 --- a/gfx/skia/skia/include/core/SkPaint.h +++ b/gfx/skia/skia/include/core/SkPaint.h @@ -8,11 +8,14 @@ #ifndef SkPaint_DEFINED #define SkPaint_DEFINED +#include "SkBlendMode.h" #include "SkColor.h" #include "SkFilterQuality.h" #include "SkMatrix.h" #include "SkXfermode.h" +//#define SK_SUPPORT_LEGACY_XFERMODE_OBJECT + class SkAutoDescriptor; class SkAutoGlyphCache; class SkColorFilter; @@ -30,8 +33,10 @@ class SkPath; class SkPathEffect; struct SkPoint; class SkRasterizer; +struct SkScalerContextEffects; class SkShader; class SkSurfaceProps; +class SkTextBlob; class SkTypeface; #define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag @@ -408,9 +413,10 @@ public: kRound_Cap, //!< begin/end contours with a semi-circle extension kSquare_Cap, //!< begin/end contours with a half square extension - kCapCount, + kLast_Cap = kSquare_Cap, kDefault_Cap = kButt_Cap }; + static constexpr int kCapCount = kLast_Cap + 1; /** Join enum specifies the settings for the paint's strokejoin. This is the treatment that is applied to corners in paths and rectangles. @@ -420,9 +426,10 @@ public: kRound_Join, //!< connect path segments with a round join kBevel_Join, //!< connect path segments with a flat bevel join - kJoinCount, + kLast_Join = kBevel_Join, kDefault_Join = kMiter_Join }; + static constexpr int kJoinCount = kLast_Join + 1; /** Return the paint's stroke cap type, controlling how the start and end of stroked lines and paths are treated. @@ -521,12 +528,13 @@ public: #endif void setColorFilter(sk_sp); +#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT /** Get the paint's xfermode object.

The xfermode's reference count is not affected. @return the paint's xfermode (or NULL) */ - SkXfermode* getXfermode() const { return fXfermode.get(); } + SkXfermode* getXfermode() const; /** Set or clear the xfermode object.

@@ -548,6 +556,11 @@ public: the paint's xfermode is set to null. */ SkXfermode* setXfermodeMode(SkXfermode::Mode); +#endif + + SkBlendMode getBlendMode() const { return (SkBlendMode)fBlendMode; } + bool isSrcOver() const { return (SkBlendMode)fBlendMode == SkBlendMode::kSrcOver; } + void setBlendMode(SkBlendMode mode) { fBlendMode = (unsigned)mode; } /** Get the paint's patheffect object.

@@ -613,8 +626,10 @@ public: paint @return typeface */ - SkTypeface* setTypeface(SkTypeface* typeface); void setTypeface(sk_sp); +#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR + SkTypeface* setTypeface(SkTypeface* typeface); +#endif /** Get the paint's rasterizer (or NULL).

@@ -647,19 +662,18 @@ public: * Return the paint's SkDrawLooper (if any). Does not affect the looper's * reference count. */ - SkDrawLooper* getLooper() const { return fLooper.get(); } - + SkDrawLooper* getDrawLooper() const { return fDrawLooper.get(); } + SkDrawLooper* getLooper() const { return fDrawLooper.get(); } /** * Set or clear the looper object. *

* Pass NULL to clear any previous looper. - * As a convenience, the parameter passed is also returned. * If a previous looper exists in the paint, its reference count is * decremented. If looper is not NULL, its reference count is * incremented. * @param looper May be NULL. The new looper to be installed in the paint. - * @return looper */ + void setDrawLooper(sk_sp); #ifdef SK_SUPPORT_LEGACY_MINOR_EFFECT_PTR SkDrawLooper* setLooper(SkDrawLooper* looper); #endif @@ -816,7 +830,7 @@ public: is returned. */ int textToGlyphs(const void* text, size_t byteLength, - uint16_t glyphs[]) const; + SkGlyphID glyphs[]) const; /** Return true if all of the specified text has a corresponding non-zero glyph ID. If any of the code-points in the text are not supported in @@ -831,7 +845,7 @@ public: to zero. Note: this does not look at the text-encoding setting in the paint, only at the typeface. */ - void glyphsToUnichars(const uint16_t glyphs[], int count, SkUnichar text[]) const; + void glyphsToUnichars(const SkGlyphID glyphs[], int count, SkUnichar text[]) const; /** Return the number of drawable units in the specified text buffer. This looks at the current TextEncoding field of the paint. If you also @@ -959,6 +973,40 @@ public: int getPosTextIntercepts(const void* text, size_t length, const SkPoint pos[], const SkScalar bounds[2], SkScalar* intervals) const; + /** Return the number of intervals that intersect the intercept along the axis of the advance. + * The return count is zero or a multiple of two, and is at most the number of glyphs * 2 in + * string. The caller may pass nullptr for intervals to determine the size of the interval + * array, or may conservatively pre-allocate an array with length * 2 entries. The computed + * intervals are cached by glyph to improve performance for multiple calls. + * This permits constructing an underline that skips the descenders. + * + * @param text The text. + * @param length Number of bytes of text. + * @param xpos Array of x-positions, used to position each character. + * @param constY The shared Y coordinate for all of the positions. + * @param bounds The lower and upper line parallel to the advance. + * @param array If not null, the glyph bounds contained by the advance parallel lines. + * + * @return The number of intersections, which may be zero. + */ + int getPosTextHIntercepts(const void* text, size_t length, const SkScalar xpos[], + SkScalar constY, const SkScalar bounds[2], SkScalar* intervals) const; + + /** Return the number of intervals that intersect the intercept along the axis of the advance. + * The return count is zero or a multiple of two, and is at most the number of glyphs * 2 in + * text blob. The caller may pass nullptr for intervals to determine the size of the interval + * array. The computed intervals are cached by glyph to improve performance for multiple calls. + * This permits constructing an underline that skips the descenders. + * + * @param blob The text blob. + * @param bounds The lower and upper line parallel to the advance. + * @param array If not null, the glyph bounds contained by the advance parallel lines. + * + * @return The number of intersections, which may be zero. + */ + int getTextBlobIntercepts(const SkTextBlob* blob, const SkScalar bounds[2], + SkScalar* intervals) const; + /** * Return a rectangle that represents the union of the bounds of all * of the glyphs, but each one positioned at (0,0). This may be conservatively large, and @@ -1051,11 +1099,10 @@ private: sk_sp fTypeface; sk_sp fPathEffect; sk_sp fShader; - sk_sp fXfermode; sk_sp fMaskFilter; sk_sp fColorFilter; sk_sp fRasterizer; - sk_sp fLooper; + sk_sp fDrawLooper; sk_sp fImageFilter; SkScalar fTextSize; @@ -1064,6 +1111,7 @@ private: SkColor fColor; SkScalar fWidth; SkScalar fMiterLimit; + uint32_t fBlendMode; // just need 5-6 bits for SkXfermode::Mode union { struct { // all of these bitfields should add up to 32 @@ -1080,28 +1128,38 @@ private: uint32_t fBitfieldsUInt; }; - GlyphCacheProc getGlyphCacheProc(bool needFullMetrics) const; + static GlyphCacheProc GetGlyphCacheProc(TextEncoding encoding, + bool isDevKern, + bool needFullMetrics); SkScalar measure_text(SkGlyphCache*, const char* text, size_t length, int* count, SkRect* bounds) const; - enum class FakeGamma { - Off = 0, On + enum ScalerContextFlags : uint32_t { + kNone_ScalerContextFlags = 0, + + kFakeGamma_ScalerContextFlag = 1 << 0, + kBoostContrast_ScalerContextFlag = 1 << 1, + + kFakeGammaAndBoostContrast_ScalerContextFlags = + kFakeGamma_ScalerContextFlag | kBoostContrast_ScalerContextFlag, }; /* * Allocs an SkDescriptor on the heap and return it to the caller as a refcnted * SkData. Caller is responsible for managing the lifetime of this object. */ - void getScalerContextDescriptor(SkAutoDescriptor*, const SkSurfaceProps& surfaceProps, - FakeGamma fakeGamma, const SkMatrix*) const; + void getScalerContextDescriptor(SkScalerContextEffects*, SkAutoDescriptor*, + const SkSurfaceProps& surfaceProps, + uint32_t scalerContextFlags, const SkMatrix*) const; - SkGlyphCache* detachCache(const SkSurfaceProps* surfaceProps, FakeGamma fakeGamma, + SkGlyphCache* detachCache(const SkSurfaceProps* surfaceProps, uint32_t scalerContextFlags, const SkMatrix*) const; - void descriptorProc(const SkSurfaceProps* surfaceProps, FakeGamma fakeGamma, + void descriptorProc(const SkSurfaceProps* surfaceProps, uint32_t scalerContextFlags, const SkMatrix* deviceMatrix, - void (*proc)(SkTypeface*, const SkDescriptor*, void*), + void (*proc)(SkTypeface*, const SkScalerContextEffects&, + const SkDescriptor*, void*), void* context) const; /* diff --git a/gfx/skia/skia/include/core/SkPath.h b/gfx/skia/skia/include/core/SkPath.h index 8df7633d425f..d1af4f31b659 100644 --- a/gfx/skia/skia/include/core/SkPath.h +++ b/gfx/skia/skia/include/core/SkPath.h @@ -26,6 +26,13 @@ class SkWStream; */ class SK_API SkPath { public: + enum Direction { + /** clockwise direction for adding closed contours */ + kCW_Direction, + /** counter-clockwise direction for adding closed contours */ + kCCW_Direction, + }; + SkPath(); SkPath(const SkPath&); ~SkPath(); @@ -166,24 +173,45 @@ public: * * @param rect returns the bounding rect of this oval. It's a circle * if the height and width are the same. - * + * @param dir 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) const { return fPathRef->isOval(rect); } + bool isOval(SkRect* rect, Direction* dir = nullptr, + unsigned* start = nullptr) const { + bool isCCW = false; + bool result = fPathRef->isOval(rect, &isCCW, start); + if (dir && result) { + *dir = isCCW ? kCCW_Direction : kCW_Direction; + } + return result; + } /** Returns true if the path is a round rect. * * @param rrect Returns the bounding rect and radii of this round rect. + * @param dir is the rrect CCW (or CW if false). + * @param start indicates where the contour starts on the rrect (see + * SkPath::addRRect for intepretation of the index). * * @return true if this path is a round rect. * Tracking whether a path is a round rect is considered an * optimization for performance and so some paths that are in * fact round rects can report false. */ - bool isRRect(SkRRect* rrect) const { return fPathRef->isRRect(rrect); } + bool isRRect(SkRRect* rrect, Direction* dir = nullptr, + unsigned* start = nullptr) const { + bool isCCW = false; + bool result = fPathRef->isRRect(rrect, &isCCW, start); + if (dir && result) { + *dir = isCCW ? kCCW_Direction : kCW_Direction; + } + return result; + } /** Clear any lines and curves from the path, making it empty. This frees up internal storage associated with those segments. @@ -526,13 +554,6 @@ public: kLarge_ArcSize, }; - enum Direction { - /** clockwise direction for adding closed contours */ - kCW_Direction, - /** counter-clockwise direction for adding closed contours */ - kCCW_Direction, - }; - /** * Append an elliptical arc from the current point in the format used by SVG. * The center of the ellipse is computed to satisfy the constraints below. @@ -717,7 +738,8 @@ public: void addOval(const SkRect& oval, Direction dir, unsigned start); /** - * Add a closed circle contour to the path + * Add a closed circle contour to the path. The circle contour begins at + * the right-most point (as though 1 were passed to addOval's 'start' param). * * @param x The x-coordinate of the center of a circle to add as a * closed contour to the path diff --git a/gfx/skia/skia/include/core/SkPathEffect.h b/gfx/skia/skia/include/core/SkPathEffect.h index fd5957378ab1..f5ca9183a3ae 100644 --- a/gfx/skia/skia/include/core/SkPathEffect.h +++ b/gfx/skia/skia/include/core/SkPathEffect.h @@ -66,7 +66,7 @@ public: fSize.set(SK_Scalar1, SK_Scalar1); // 'asPoints' needs to initialize/fill-in 'fClipRect' if it sets // the kUseClip flag - }; + } ~PointData() { delete [] fPoints; } @@ -118,6 +118,8 @@ public: struct DashInfo { DashInfo() : fIntervals(NULL), 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 @@ -153,7 +155,7 @@ private: including flattening them. It does nothing in filterPath, and is only useful for managing the lifetimes of its two arguments. */ -class SkPairPathEffect : public SkPathEffect { +class SK_API SkPairPathEffect : public SkPathEffect { protected: SkPairPathEffect(sk_sp pe0, sk_sp pe1); @@ -174,7 +176,7 @@ private: This subclass of SkPathEffect composes its two arguments, to create a compound pathEffect. */ -class SkComposePathEffect : public SkPairPathEffect { +class SK_API SkComposePathEffect : public SkPairPathEffect { public: /** Construct a pathEffect whose effect is to apply first the inner pathEffect and the the outer pathEffect (e.g. outer(inner(path))) @@ -224,7 +226,7 @@ private: This subclass of SkPathEffect applies two pathEffects, one after the other. Its filterPath() returns true if either of the effects succeeded. */ -class SkSumPathEffect : public SkPairPathEffect { +class SK_API SkSumPathEffect : public SkPairPathEffect { public: /** Construct a pathEffect whose effect is to apply two effects, in sequence. (e.g. first(path) + second(path)) diff --git a/gfx/skia/skia/include/core/SkPathMeasure.h b/gfx/skia/skia/include/core/SkPathMeasure.h index 2a512b8c382c..1044f7eeb069 100644 --- a/gfx/skia/skia/include/core/SkPathMeasure.h +++ b/gfx/skia/skia/include/core/SkPathMeasure.h @@ -95,7 +95,8 @@ private: SkScalar fDistance; // total distance up to this point unsigned fPtIndex; // index into the fPts array unsigned fTValue : 30; - unsigned fType : 2; + unsigned fType : 2; // actually the enum SkSegType + // See SkPathMeasurePriv.h SkScalar getScalarT() const; }; diff --git a/gfx/skia/skia/include/core/SkPathRef.h b/gfx/skia/skia/include/core/SkPathRef.h index ce84a91d1ac9..9b15c3e4f2f4 100644 --- a/gfx/skia/skia/include/core/SkPathRef.h +++ b/gfx/skia/skia/include/core/SkPathRef.h @@ -9,6 +9,7 @@ #ifndef SkPathRef_DEFINED #define SkPathRef_DEFINED +#include "../private/SkAtomics.h" #include "../private/SkTDArray.h" #include "SkMatrix.h" #include "SkPoint.h" @@ -35,7 +36,7 @@ class SkWBuffer; * logical verb or the last verb in memory). */ -class SK_API SkPathRef : public ::SkRefCnt { +class SK_API SkPathRef final : public SkNVRefCnt { public: class Editor { public: @@ -57,11 +58,11 @@ public: 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 @@ -99,9 +100,13 @@ public: */ SkPathRef* pathRef() { return fPathRef; } - void setIsOval(bool isOval) { fPathRef->setIsOval(isOval); } + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fPathRef->setIsOval(isOval, isCCW, start); + } - void setIsRRect(bool isRRect) { fPathRef->setIsRRect(isRRect); } + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fPathRef->setIsRRect(isRRect, isCCW, start); + } void setBounds(const SkRect& rect) { fPathRef->setBounds(rect); } @@ -163,23 +168,42 @@ public: * * @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) const { - if (fIsOval && rect) { - *rect = this->getBounds(); + 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) const { - if (fIsRRect && rrect) { - *rrect = this->getRRect(); + 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); } @@ -219,7 +243,7 @@ public: */ static void Rewind(SkAutoTUnref* pathRef); - virtual ~SkPathRef(); + ~SkPathRef(); int countPoints() const { SkDEBUGCODE(this->validate();) return fPointCnt; } int countVerbs() const { SkDEBUGCODE(this->validate();) return fVerbCnt; } int countWeights() const { SkDEBUGCODE(this->validate();) return fConicWeights.count(); } @@ -291,10 +315,12 @@ public: private: enum SerializationOffsets { - kIsRRect_SerializationShift = 26, // requires 1 bit - kIsFinite_SerializationShift = 25, // requires 1 bit - kIsOval_SerializationShift = 24, // requires 1 bit - kSegmentMask_SerializationShift = 0 // requires 4 bits + kRRectOrOvalStartIdx_SerializationShift = 28, // requires 3 bits + kRRectOrOvalIsCCW_SerializationShift = 27, // requires 1 bit + kIsRRect_SerializationShift = 26, // requires 1 bit + kIsFinite_SerializationShift = 25, // requires 1 bit + kIsOval_SerializationShift = 24, // requires 1 bit + kSegmentMask_SerializationShift = 0 // requires 4 bits }; SkPathRef() { @@ -308,6 +334,9 @@ private: 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();) } @@ -453,9 +482,17 @@ private: */ friend SkPathRef* sk_create_empty_pathref(); - void setIsOval(bool isOval) { fIsOval = isOval; } + void setIsOval(bool isOval, bool isCCW, unsigned start) { + fIsOval = isOval; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = start; + } - void setIsRRect(bool isRRect) { fIsRRect = isRRect; } + void setIsRRect(bool isRRect, bool isCCW, unsigned start) { + fIsRRect = isRRect; + fRRectOrOvalIsCCW = isCCW; + fRRectOrOvalStartIdx = start; + } // called only by the editor. Note that this is not a const function. SkPoint* getPoints() { @@ -498,11 +535,14 @@ private: SkBool8 fIsOval; SkBool8 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. + SkBool8 fRRectOrOvalIsCCW; + uint8_t fRRectOrOvalStartIdx; uint8_t fSegmentMask; friend class PathRefTest_Private; friend class ForceIsRRect_Private; // unit test isRRect - typedef SkRefCnt INHERITED; }; #endif diff --git a/gfx/skia/skia/include/core/SkPicture.h b/gfx/skia/skia/include/core/SkPicture.h index 808944b5ef00..c2d05f9c41ef 100644 --- a/gfx/skia/skia/include/core/SkPicture.h +++ b/gfx/skia/skia/include/core/SkPicture.h @@ -16,6 +16,9 @@ class GrContext; class SkBigPicture; class SkBitmap; class SkCanvas; +class SkData; +class SkImage; +class SkImageDeserializer; class SkPath; class SkPictureData; class SkPixelSerializer; @@ -49,6 +52,7 @@ public: */ typedef bool (*InstallPixelRefProc)(const void* src, size_t length, SkBitmap* dst); +#ifdef SK_SUPPORT_LEGACY_PICTUREINSTALLPIXELREF /** * Recreate a picture that was serialized into a stream. * @param SkStream Serialized picture data. Ownership is unchanged by this call. @@ -58,18 +62,22 @@ public: * invalid. */ static sk_sp MakeFromStream(SkStream*, InstallPixelRefProc proc); + static sk_sp MakeFromStream(SkStream* stream, std::nullptr_t) { + return MakeFromStream(stream); + } +#endif /** * Recreate a picture that was serialized into a stream. * - * Any serialized images in the stream will be passed to - * SkImageGenerator::NewFromEncoded. - * - * @param SkStream Serialized picture data. Ownership is unchanged by this call. - * @return A new SkPicture representing the serialized data, or NULL if the stream is - * invalid. + * Any serialized images in the stream will be passed the image-deserializer, or if that is + * null, to the default deserializer that will call SkImage::MakeFromEncoded(). */ + static sk_sp MakeFromStream(SkStream*, SkImageDeserializer*); static sk_sp MakeFromStream(SkStream*); + static sk_sp MakeFromData(const void* data, size_t size, + SkImageDeserializer* = nullptr); + static sk_sp MakeFromData(const SkData* data, SkImageDeserializer* = nullptr); /** * Recreate a picture that was serialized into a buffer. If the creation requires bitmap @@ -116,10 +124,16 @@ public: uint32_t uniqueID() const; /** - * Serialize to a stream. If non NULL, serializer will be used to serialize - * bitmaps and images in the picture. + * Serialize the picture to SkData. If non nullptr, pixel-serializer will be used to + * customize how images reference by the picture are serialized/compressed. */ - void serialize(SkWStream*, SkPixelSerializer* = NULL) const; + sk_sp serialize(SkPixelSerializer* = nullptr) const; + + /** + * Serialize to a stream. If non nullptr, pixel-serializer will be used to + * customize how images reference by the picture are serialized/compressed. + */ + void serialize(SkWStream*, SkPixelSerializer* = nullptr) const; /** * Serialize to a buffer. @@ -139,10 +153,6 @@ public: */ virtual int approximateOpCount() const = 0; - /** Return true if this picture contains text. - */ - virtual bool hasText() const = 0; - /** Returns the approximate byte size of this picture, not including large ref'd objects. */ virtual size_t approximateBytesUsed() const = 0; @@ -157,8 +167,10 @@ public: static bool InternalOnly_StreamIsSKP(SkStream*, SkPictInfo*); static bool InternalOnly_BufferIsSKP(SkReadBuffer*, SkPictInfo*); +#ifdef SK_SUPPORT_LEGACY_PICTURE_GPUVETO /** Return true if the picture is suitable for rendering on the GPU. */ bool suitableForGpuRasterization(GrContext*, const char** whyNot = NULL) const; +#endif // Sent via SkMessageBus from destructor. struct DeletionMessage { int32_t fUniqueID; }; // TODO: -> uint32_t? @@ -190,10 +202,11 @@ private: template friend class SkMiniPicture; void serialize(SkWStream*, SkPixelSerializer*, SkRefCntSet* typefaces) const; - static sk_sp MakeFromStream(SkStream*, InstallPixelRefProc, SkTypefacePlayback*); + static sk_sp MakeFromStream(SkStream*, SkImageDeserializer*, SkTypefacePlayback*); friend class SkPictureData; virtual int numSlowPaths() const = 0; + friend class SkPictureGpuAnalyzer; friend struct SkPathCounter; // V35: Store SkRect (rather then width & height) in header @@ -206,10 +219,16 @@ private: // 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 // Only SKPs within the min/current picture version range (inclusive) can be read. static const uint32_t MIN_PICTURE_VERSION = 35; // Produced by Chrome M39. - static const uint32_t CURRENT_PICTURE_VERSION = 44; + static const uint32_t CURRENT_PICTURE_VERSION = 50; static_assert(MIN_PICTURE_VERSION <= 41, "Remove kFontFileName and related code from SkFontDescriptor.cpp."); @@ -219,9 +238,17 @@ private: static_assert(MIN_PICTURE_VERSION <= 43, "Remove SkBitmapSourceDeserializer."); - + + static_assert(MIN_PICTURE_VERSION <= 45, + "Remove decoding of old SkTypeface::Style from SkFontDescriptor.cpp."); + + static_assert(MIN_PICTURE_VERSION <= 48, + "Remove legacy gradient deserialization code from SkGradientShader.cpp."); + static bool IsValidPictInfo(const SkPictInfo& info); - static sk_sp Forwardport(const SkPictInfo&, const SkPictureData*); + static sk_sp Forwardport(const SkPictInfo&, + const SkPictureData*, + SkReadBuffer* buffer); SkPictInfo createHeader() const; SkPictureData* backport() const; diff --git a/gfx/skia/skia/include/core/SkPictureAnalyzer.h b/gfx/skia/skia/include/core/SkPictureAnalyzer.h new file mode 100644 index 000000000000..62dac30f0104 --- /dev/null +++ b/gfx/skia/skia/include/core/SkPictureAnalyzer.h @@ -0,0 +1,66 @@ +/* + * 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 SkPictureAnalyzer_DEFINED +#define SkPictureAnalyzer_DEFINED + +#include "SkCanvas.h" +#include "SkRefCnt.h" +#include "SkRegion.h" +#include "SkTypes.h" + +#if SK_SUPPORT_GPU +#include "GrContext.h" + +class SkPath; +class SkPicture; + +/** \class SkPictureGpuAnalyzer + + Gathers GPU-related statistics for one or more SkPictures. +*/ +class SK_API SkPictureGpuAnalyzer final : public SkNoncopyable { +public: + explicit SkPictureGpuAnalyzer(sk_sp = nullptr); + explicit SkPictureGpuAnalyzer(const sk_sp& picture, + sk_sp = nullptr); + + /** + * Process the given picture and accumulate its stats. + */ + void analyzePicture(const SkPicture*); + + /** + * Process an explicit clipPath op. + */ + void analyzeClipPath(const SkPath&, SkCanvas::ClipOp, bool doAntiAlias); + + /** + * Reset all accumulated stats. + */ + void reset(); + + /** + * Returns true if the analyzed pictures are suitable for rendering on the GPU. + */ + bool suitableForGpuRasterization(const char** whyNot = nullptr) const; + + /** + * Returns the number of commands which are slow to draw on the GPU, capped at the predicate + * max. + */ + uint32_t numSlowGpuCommands() { return fNumSlowPaths; } + +private: + uint32_t fNumSlowPaths; + + typedef SkNoncopyable INHERITED; +}; + +#endif // SK_SUPPORT_GPU + +#endif // SkPictureAnalyzer_DEFINED diff --git a/gfx/skia/skia/include/core/SkPictureRecorder.h b/gfx/skia/skia/include/core/SkPictureRecorder.h index 3f0cbcc80169..c824189300b1 100644 --- a/gfx/skia/skia/include/core/SkPictureRecorder.h +++ b/gfx/skia/skia/include/core/SkPictureRecorder.h @@ -19,6 +19,7 @@ namespace android { }; #endif +class GrContext; class SkCanvas; class SkDrawable; class SkPictureRecord; @@ -31,13 +32,13 @@ public: ~SkPictureRecorder(); enum RecordFlags { - // This flag indicates that, if some BHH is being computed, saveLayer - // information should also be extracted at the same time. - kComputeSaveLayerInfo_RecordFlag = 0x01, - // 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 = 0x02, + kPlaybackDrawPicture_RecordFlag = 1 << 0, + }; + + enum FinishFlags { + kReturnNullForEmpty_FinishFlag = 1 << 0, // no draw-ops will return nullptr }; /** Returns the canvas that records the drawing commands. @@ -72,7 +73,7 @@ public: * reflect their current state, but will not contain a live reference to the drawables * themselves. */ - sk_sp finishRecordingAsPicture(); + sk_sp finishRecordingAsPicture(uint32_t endFlags = 0); /** * Signal that the caller is done recording, and update the cull rect to use for bounding @@ -83,7 +84,8 @@ public: * and subsequent culling operations. * @return the picture containing the recorded content. */ - sk_sp finishRecordingAsPictureWithCull(const SkRect& cullRect); + sk_sp finishRecordingAsPictureWithCull(const SkRect& cullRect, + uint32_t endFlags = 0); /** * Signal that the caller is done recording. This invalidates the canvas returned by @@ -95,7 +97,7 @@ public: * 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(); + sk_sp finishRecordingAsDrawable(uint32_t endFlags = 0); #ifdef SK_SUPPORT_LEGACY_PICTURE_PTR SkPicture* SK_WARN_UNUSED_RESULT endRecordingAsPicture() { diff --git a/gfx/skia/skia/include/core/SkPixelRef.h b/gfx/skia/skia/include/core/SkPixelRef.h index 651176ebbbba..2677e5f22d72 100644 --- a/gfx/skia/skia/include/core/SkPixelRef.h +++ b/gfx/skia/skia/include/core/SkPixelRef.h @@ -206,10 +206,6 @@ public: bool requestLock(const LockRequest&, LockResult*); - /** Are we really wrapping a texture instead of a bitmap? - */ - virtual GrTexture* getTexture() { return NULL; } - /** * If this can efficiently return YUV data, this should return true. * Otherwise this returns false and does not modify any of the parameters. @@ -238,20 +234,6 @@ public: /** Populates dst with the pixels of this pixelRef, converting them to colorType. */ bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL); - /** - * Makes a deep copy of this PixelRef, respecting the requested config. - * @param colorType Desired colortype. - * @param profileType Desired colorprofiletype. - * @param subset Subset of this PixelRef to copy. Must be fully contained within the bounds of - * of this PixelRef. - * @return A new SkPixelRef, or NULL if either there is an error (e.g. the destination could - * not be created with the given config), or this PixelRef does not support deep - * copies. - */ - virtual SkPixelRef* deepCopy(SkColorType, SkColorProfileType, const SkIRect* /*subset*/) { - return NULL; - } - // 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 @@ -404,6 +386,7 @@ private: void setImmutableWithID(uint32_t genID); friend class SkImage_Gpu; friend class SkImageCacherator; + friend class SkSpecialImage_Gpu; typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/core/SkPixmap.h b/gfx/skia/skia/include/core/SkPixmap.h index 5f90273a97da..699ddb4d4495 100644 --- a/gfx/skia/skia/include/core/SkPixmap.h +++ b/gfx/skia/skia/include/core/SkPixmap.h @@ -44,6 +44,9 @@ public: this->reset(info, NULL, 0, NULL); } + // overrides the colorspace in the SkImageInfo of the pixmap + void setColorSpace(sk_sp); + /** * If supported, set this pixmap to point to the pixels in the specified mask and return true. * On failure, return false and set this pixmap to empty. @@ -80,7 +83,7 @@ public: * Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel * colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType. */ - int shiftPerPixel() const { return fInfo.bytesPerPixel() >> 1; } + int shiftPerPixel() const { return fInfo.shiftPerPixel(); } uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); } uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); } @@ -141,6 +144,9 @@ public: // Writable versions void* writable_addr() const { return const_cast(fPixels); } + void* writable_addr(int x, int y) const { + return const_cast(this->addr(x, y)); + } uint8_t* writable_addr8(int x, int y) const { return const_cast(this->addr8(x, y)); } diff --git a/gfx/skia/skia/include/core/SkPoint.h b/gfx/skia/skia/include/core/SkPoint.h index 52d01ae88ce5..f5ecbab78c4e 100644 --- a/gfx/skia/skia/include/core/SkPoint.h +++ b/gfx/skia/skia/include/core/SkPoint.h @@ -549,4 +549,8 @@ struct SK_API SkPoint { typedef SkPoint SkVector; +static inline bool SkPointsAreFinite(const SkPoint array[], int count) { + return SkScalarsAreFinite(&array[0].fX, count << 1); +} + #endif diff --git a/gfx/skia/skia/include/core/SkPostConfig.h b/gfx/skia/skia/include/core/SkPostConfig.h index a7fbba7c7879..1b1cb3e751e7 100644 --- a/gfx/skia/skia/include/core/SkPostConfig.h +++ b/gfx/skia/skia/include/core/SkPostConfig.h @@ -14,6 +14,14 @@ # define SK_BUILD_FOR_WIN #endif +#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) @@ -78,6 +86,14 @@ #endif #endif +#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + #define SK_VECTORCALL __vectorcall +#elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) + #define SK_VECTORCALL __attribute__((pcs("aapcs-vfp"))) +#else + #define SK_VECTORCALL +#endif + #if !defined(SK_SUPPORT_GPU) # define SK_SUPPORT_GPU 1 #endif @@ -107,26 +123,6 @@ /////////////////////////////////////////////////////////////////////////////// #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 -# # ifndef SK_A32_SHIFT # define SK_A32_SHIFT 24 # define SK_R32_SHIFT 16 @@ -145,10 +141,10 @@ #endif #ifndef SK_ABORT -# define SK_ABORT(msg) \ +# define SK_ABORT(message) \ do { \ SkNO_RETURN_HINT(); \ - SkDebugf("%s:%d: fatal error: \"%s\"\n", __FILE__, __LINE__, #msg); \ + SkDebugf("%s:%d: fatal error: \"%s\"\n", __FILE__, __LINE__, message); \ SK_DUMP_GOOGLE3_STACK(); \ sk_abort_no_print(); \ } while (false) @@ -249,7 +245,11 @@ ////////////////////////////////////////////////////////////////////// #if !defined(SK_UNUSED) -# define SK_UNUSED SK_ATTRIBUTE(unused) +# if defined(_MSC_VER) +# define SK_UNUSED __pragma(warning(suppress:4189)) +# else +# define SK_UNUSED SK_ATTRIBUTE(unused) +# endif #endif #if !defined(SK_ATTR_DEPRECATED) @@ -279,6 +279,18 @@ # 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 @@ -330,12 +342,8 @@ ////////////////////////////////////////////////////////////////////// -#if defined(SK_GAMMA_EXPONENT) && defined(SK_GAMMA_SRGB) -# error "cannot define both SK_GAMMA_EXPONENT and SK_GAMMA_SRGB" -#elif defined(SK_GAMMA_SRGB) -# define SK_GAMMA_EXPONENT (0.0f) -#elif !defined(SK_GAMMA_EXPONENT) -# define SK_GAMMA_EXPONENT (2.2f) +#if !defined(SK_GAMMA_EXPONENT) + #define SK_GAMMA_EXPONENT (0.0f) // SRGB #endif ////////////////////////////////////////////////////////////////////// @@ -346,6 +354,12 @@ ////////////////////////////////////////////////////////////////////// +#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 diff --git a/gfx/skia/skia/include/core/SkPreConfig.h b/gfx/skia/skia/include/core/SkPreConfig.h index b9b46c073a85..b165ae1255b8 100644 --- a/gfx/skia/skia/include/core/SkPreConfig.h +++ b/gfx/skia/skia/include/core/SkPreConfig.h @@ -24,14 +24,14 @@ #include "TargetConditionals.h" #endif - #if defined(WIN32) || defined(__SYMBIAN32__) + #if defined(_WIN32) || defined(__SYMBIAN32__) #define SK_BUILD_FOR_WIN32 - #elif defined(ANDROID) + #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(__GLIBC__) || defined(__GNU__) || \ - defined(__unix__) + 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 @@ -52,14 +52,6 @@ ////////////////////////////////////////////////////////////////////// -#if !defined(SK_DEBUG) && !defined(SK_RELEASE) - #ifdef NDEBUG - #define SK_RELEASE - #else - #define SK_DEBUG - #endif -#endif - #ifdef SK_BUILD_FOR_WIN32 #if !defined(SK_RESTRICT) #define SK_RESTRICT __restrict @@ -69,8 +61,6 @@ #endif #endif -////////////////////////////////////////////////////////////////////// - #if !defined(SK_RESTRICT) #define SK_RESTRICT __restrict__ #endif @@ -118,8 +108,12 @@ #define SK_CPU_SSE_LEVEL_AVX 51 #define SK_CPU_SSE_LEVEL_AVX2 52 -#ifdef SK_BUILD_FOR_IOS - #define SK_CPU_SSE_LEVEL 0 // We're tired of fighting with opts/ and iOS simulator. +// 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? @@ -190,35 +184,41 @@ #endif #endif -// Disable ARM64 optimizations for iOS due to complications regarding gyp and iOS. -#if defined(__aarch64__) && !defined(SK_BUILD_FOR_IOS) +#if 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. -// TODO: Why don't we want NEON on iOS? -#if !defined(SK_ARM_HAS_NEON) && !defined(SK_BUILD_FOR_IOS) && (defined(__ARM_NEON__) || defined(__ARM_NEON)) +#if !defined(SK_ARM_HAS_NEON) && !defined(SK_BUILD_NO_OPTS) && (defined(__ARM_NEON__) || 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(SKIA_DLL) - #if defined(WIN32) - #if SKIA_IMPLEMENTATION - #define SK_API __declspec(dllexport) +#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 __declspec(dllimport) + #define SK_API __attribute__((visibility("default"))) #endif #else - #define SK_API __attribute__((visibility("default"))) + #define SK_API #endif -#else - #define SK_API #endif ////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/include/core/SkRRect.h b/gfx/skia/skia/include/core/SkRRect.h index 5564ce0d7ee9..3b691aab1b11 100644 --- a/gfx/skia/skia/include/core/SkRRect.h +++ b/gfx/skia/skia/include/core/SkRRect.h @@ -16,7 +16,6 @@ class SkMatrix; // Path forward: // core work -// add validate method (all radii positive, all radii sums < rect size, etc.) // add contains(SkRect&) - for clip stack // add contains(SkRRect&) - for clip stack // add heart rect computation (max rect inside RR) @@ -47,6 +46,10 @@ class SkMatrix; */ class SK_API SkRRect { public: + SkRRect() { /* unititialized */ } + SkRRect(const SkRRect&) = default; + SkRRect& operator=(const SkRRect&) = default; + /** * Enum to capture the various possible subtypes of RR. Accessed * by type(). The subtypes become progressively less restrictive. @@ -86,7 +89,7 @@ public: * Returns the RR's sub type. */ Type getType() const { - SkDEBUGCODE(this->validate();) + SkASSERT(this->isValid()); return static_cast(fType); } @@ -120,7 +123,7 @@ public: memset(fRadii, 0, sizeof(fRadii)); fType = kEmpty_Type; - SkDEBUGCODE(this->validate();) + SkASSERT(this->isValid()); } /** @@ -138,7 +141,13 @@ public: memset(fRadii, 0, sizeof(fRadii)); fType = kRect_Type; - SkDEBUGCODE(this->validate();) + SkASSERT(this->isValid()); + } + + static SkRRect MakeEmpty() { + SkRRect rr; + rr.setEmpty(); + return rr; } static SkRRect MakeRect(const SkRect& r) { @@ -146,7 +155,7 @@ public: rr.setRect(r); return rr; } - + static SkRRect MakeOval(const SkRect& oval) { SkRRect rr; rr.setOval(oval); @@ -180,7 +189,7 @@ public: } fType = kOval_Type; - SkDEBUGCODE(this->validate();) + SkASSERT(this->isValid()); } /** @@ -268,13 +277,17 @@ public: fRect.offset(dx, dy); } + SkRRect SK_WARN_UNUSED_RESULT makeOffset(SkScalar dx, SkScalar dy) const { + return SkRRect(fRect.makeOffset(dx, dy), fRadii, fType); + } + /** * Returns true if 'rect' is wholy inside the RR, and both * are not empty. */ bool contains(const SkRect& rect) const; - SkDEBUGCODE(void validate() const;) + bool isValid() const; enum { kSizeInMemory = 12 * sizeof(SkScalar) @@ -316,6 +329,11 @@ public: void dumpHex() const { this->dump(true); } private: + SkRRect(const SkRect& rect, const SkVector radii[4], int32_t type) + : fRect(rect) + , fRadii{radii[0], radii[1], radii[2], radii[3]} + , fType(type) {} + SkRect fRect; // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] SkVector fRadii[4]; diff --git a/gfx/skia/skia/include/core/SkRWBuffer.h b/gfx/skia/skia/include/core/SkRWBuffer.h index 106e572587d8..451933f353ca 100644 --- a/gfx/skia/skia/include/core/SkRWBuffer.h +++ b/gfx/skia/skia/include/core/SkRWBuffer.h @@ -25,7 +25,7 @@ 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 fUsed; } + size_t size() const { return fAvailable; } class SK_API Iter { public: @@ -53,22 +53,25 @@ public: private: const SkBufferBlock* fBlock; size_t fRemaining; + const SkROBuffer* fBuffer; }; private: - SkROBuffer(const SkBufferHead* head, size_t used); + SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* fTail); virtual ~SkROBuffer(); - const SkBufferHead* fHead; - const size_t fUsed; + 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, a RBuffer or StreamAsset can be snapped off, which - * can see the previously stored bytes, but which will be unaware of any future writes. + * 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: @@ -76,8 +79,15 @@ public: ~SkRWBuffer(); size_t size() const { return fTotalUsed; } - void append(const void* buffer, size_t length); - void* append(size_t length); + + /** + * 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); SkROBuffer* newRBufferSnapshot() const; SkStreamAsset* newStreamSnapshot() const; diff --git a/gfx/skia/skia/include/core/SkRect.h b/gfx/skia/skia/include/core/SkRect.h index 3ebe099ae638..27a648feeb93 100644 --- a/gfx/skia/skia/include/core/SkRect.h +++ b/gfx/skia/skia/include/core/SkRect.h @@ -390,10 +390,8 @@ struct SK_API SkIRect { struct SK_API SkRect { SkScalar fLeft, fTop, fRight, fBottom; - static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { - SkRect r; - r.setEmpty(); - return r; + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeEmpty() { + return SkRect{0, 0, 0, 0}; } static SkRect SK_WARN_UNUSED_RESULT MakeLargest() { @@ -420,10 +418,9 @@ struct SK_API SkRect { return r; } - static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { - SkRect rect; - rect.set(l, t, r, b); - return rect; + static constexpr SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, + SkScalar b) { + return SkRect {l, t, r, b}; } static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { @@ -442,6 +439,10 @@ struct SK_API SkRect { return r; } + static SkRect Make(const SkISize& size) { + return MakeIWH(size.width(), size.height()); + } + static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) { SkRect r; r.set(SkIntToScalar(irect.fLeft), @@ -506,7 +507,7 @@ struct SK_API SkRect { /** Set this rectangle to the empty rectangle (0,0,0,0) */ - void setEmpty() { memset(this, 0, sizeof(*this)); } + void setEmpty() { *this = MakeEmpty(); } void set(const SkIRect& src) { fLeft = SkIntToScalar(src.fLeft); diff --git a/gfx/skia/skia/include/core/SkRefCnt.h b/gfx/skia/skia/include/core/SkRefCnt.h index 40eae74fedf3..7e39125b763c 100644 --- a/gfx/skia/skia/include/core/SkRefCnt.h +++ b/gfx/skia/skia/include/core/SkRefCnt.h @@ -8,11 +8,12 @@ #ifndef SkRefCnt_DEFINED #define SkRefCnt_DEFINED -#include "../private/SkAtomics.h" #include "../private/SkTLogic.h" #include "SkTypes.h" +#include #include #include +#include #include #define SK_SUPPORT_TRANSITION_TO_SP_INTERFACES @@ -37,19 +38,28 @@ public: */ virtual ~SkRefCntBase() { #ifdef SK_DEBUG - SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt); - fRefCnt = 0; // illegal value, to catch us if we reuse after delete + SkASSERTF(getRefCnt() == 1, "fRefCnt was %d", getRefCnt()); + // illegal value, to catch us if we reuse after delete + fRefCnt.store(0, std::memory_order_relaxed); #endif } /** Return the reference count. Use only for debugging. */ - int32_t getRefCnt() const { return fRefCnt; } + int32_t getRefCnt() const { + return fRefCnt.load(std::memory_order_relaxed); + } + +#ifdef SK_DEBUG + void validate() const { + SkASSERT(getRefCnt() > 0); + } +#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 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) { + 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(). @@ -66,11 +76,12 @@ public: // go to zero, but not below, prior to reusing the object. This breaks // the use of unique() on such objects and as such should be removed // once the Android code is fixed. - SkASSERT(fRefCnt >= 0); + SkASSERT(getRefCnt() >= 0); #else - SkASSERT(fRefCnt > 0); + SkASSERT(getRefCnt() > 0); #endif - (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); // No barrier required. + // No barrier required. + (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } /** Decrement the reference count. If the reference count is 1 before the @@ -78,33 +89,24 @@ public: the object needs to have been allocated via new, and not on the stack. */ void unref() const { - SkASSERT(fRefCnt > 0); + SkASSERT(getRefCnt() > 0); // A release here acts in place of all releases we "should" have been doing in ref(). - if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { + 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(); } } -#ifdef SK_DEBUG - void validate() const { - SkASSERT(fRefCnt > 0); - } -#endif - protected: /** * Allow subclasses to call this if they've overridden internal_dispose - * so they can reset fRefCnt before the destructor is called. Should only - * be called right before calling through to inherited internal_dispose() - * or before calling the destructor. + * so they can reset fRefCnt before the destructor is called or if they + * choose not to call the destructor (e.g. using a free list). */ void internal_dispose_restore_refcnt_to_1() const { -#ifdef SK_DEBUG - SkASSERT(0 == fRefCnt); - fRefCnt = 1; -#endif + SkASSERT(0 == getRefCnt()); + fRefCnt.store(1, std::memory_order_relaxed); } private: @@ -120,7 +122,7 @@ private: // and conditionally call SkRefCnt::internal_dispose(). friend class SkWeakRefCnt; - mutable int32_t fRefCnt; + mutable std::atomic fRefCnt; typedef SkNoncopyable INHERITED; }; @@ -130,7 +132,13 @@ private: // This SkRefCnt should normally derive from SkRefCntBase. #include SK_REF_CNT_MIXIN_INCLUDE #else -class SK_API SkRefCnt : public SkRefCntBase { }; +class SK_API SkRefCnt : public SkRefCntBase { + // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system. + #if defined(GOOGLE3) + public: + void deref() const { this->unref(); } + #endif +}; #endif /////////////////////////////////////////////////////////////////////////////// @@ -213,25 +221,29 @@ template class SkNVRefCnt : SkNoncopyable { public: SkNVRefCnt() : fRefCnt(1) {} - ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } + ~SkNVRefCnt() { SkASSERTF(1 == getRefCnt(), "NVRefCnt was %d", getRefCnt()); } // 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 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire); } - void ref() const { (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); } + 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 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { - SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's assert + 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 int32_t fRefCnt; + mutable std::atomic fRefCnt; + int32_t getRefCnt() const { + return fRefCnt.load(std::memory_order_relaxed); + } }; /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -249,15 +261,15 @@ template class sk_sp { public: using element_type = T; - sk_sp() : fPtr(nullptr) {} - sk_sp(std::nullptr_t) : fPtr(nullptr) {} + 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>> + template ::value>> sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {} /** @@ -266,7 +278,7 @@ public: * No call to ref() or unref() will be made. */ sk_sp(sk_sp&& that) : fPtr(that.release()) {} - template ::value>> + template ::value>> sk_sp(sk_sp&& that) : fPtr(that.release()) {} /** @@ -294,7 +306,7 @@ public: this->reset(SkSafeRef(that.get())); return *this; } - template ::value>> + template ::value>> sk_sp& operator=(const sk_sp& that) { this->reset(SkSafeRef(that.get())); return *this; @@ -309,7 +321,7 @@ public: this->reset(that.release()); return *this; } - template ::value>> + template ::value>> sk_sp& operator=(sk_sp&& that) { this->reset(that.release()); return *this; @@ -391,7 +403,7 @@ template inline bool operator<(const sk_sp& a, const // Provide defined total order on sk_sp. // http://wg21.cmeerw.net/lwg/issue1297 // http://wg21.cmeerw.net/lwg/issue1401 . - return std::less()((void*)a.get(), (void*)b.get()); + return std::less>()(a.get(), b.get()); } template inline bool operator<(const sk_sp& a, std::nullptr_t) { return std::less()(a.get(), nullptr); @@ -432,7 +444,7 @@ template inline bool operator>=(std::nullptr_t, const sk_sp& b) template sk_sp sk_make_sp(Args&&... args) { - return sk_sp(new T(std__forward(args)...)); + return sk_sp(new T(std::forward(args)...)); } #ifdef SK_SUPPORT_TRANSITION_TO_SP_INTERFACES diff --git a/gfx/skia/skia/include/core/SkRegion.h b/gfx/skia/skia/include/core/SkRegion.h index eb0f1367aba4..a0f0e4ad3c68 100644 --- a/gfx/skia/skia/include/core/SkRegion.h +++ b/gfx/skia/skia/include/core/SkRegion.h @@ -255,7 +255,15 @@ public: * specified rectangle: this = (this op rect). * Return true if the resulting region is non-empty. */ - bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } + 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); + } /** * Set this region to the result of applying the Op to this region and the diff --git a/gfx/skia/skia/include/core/SkScalar.h b/gfx/skia/skia/include/core/SkScalar.h index b2d966cb3bbf..922840fd1af5 100644 --- a/gfx/skia/skia/include/core/SkScalar.h +++ b/gfx/skia/skia/include/core/SkScalar.h @@ -101,6 +101,7 @@ typedef double SkScalar; ////////////////////////////////////////////////////////////////////////////////////////////////// #define SkIntToScalar(x) static_cast(x) +#define SkIntToFloat(x) static_cast(x) #define SkScalarTruncToInt(x) static_cast(x) #define SkScalarToFloat(x) static_cast(x) diff --git a/gfx/skia/skia/include/core/SkShader.h b/gfx/skia/skia/include/core/SkShader.h index 0de53ad65240..efd9aa075937 100644 --- a/gfx/skia/skia/include/core/SkShader.h +++ b/gfx/skia/skia/include/core/SkShader.h @@ -17,6 +17,8 @@ #include "../gpu/GrColor.h" class SkColorFilter; +class SkColorSpace; +class SkImage; class SkPath; class SkPicture; class SkXfermode; @@ -227,6 +229,7 @@ public: */ size_t contextSize(const ContextRec&) const; +#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP /** * Returns true if this shader is just a bitmap, and if not null, returns the bitmap, * localMatrix, and tilemodes. If this is not a bitmap, returns false and ignores the @@ -239,6 +242,19 @@ public: bool isABitmap() const { return this->isABitmap(nullptr, nullptr, nullptr); } +#endif + + /** + * 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 { + return this->onIsAImage(localMatrix, xy); + } + + bool isAImage() const { + return this->isAImage(nullptr, nullptr) != nullptr; + } /** * If the shader subclass can be represented as a gradient, asAGradient @@ -309,6 +325,28 @@ public: virtual bool asACompose(ComposeRec*) const { return false; } +#if SK_SUPPORT_GPU + struct AsFPArgs { + AsFPArgs(GrContext* context, + const SkMatrix* viewMatrix, + const SkMatrix* localMatrix, + SkFilterQuality filterQuality, + SkColorSpace* dstColorSpace, + SkSourceGammaTreatment gammaTreatment) + : fContext(context) + , fViewMatrix(viewMatrix) + , fLocalMatrix(localMatrix) + , fFilterQuality(filterQuality) + , fDstColorSpace(dstColorSpace) + , fGammaTreatment(gammaTreatment) {} + + GrContext* fContext; + const SkMatrix* fViewMatrix; + const SkMatrix* fLocalMatrix; + SkFilterQuality fFilterQuality; + SkColorSpace* fDstColorSpace; + SkSourceGammaTreatment fGammaTreatment; + }; /** * Returns a GrFragmentProcessor that implements the shader for the GPU backend. NULL is @@ -323,10 +361,8 @@ public: * The returned GrFragmentProcessor should expect an unpremultiplied input color and * produce a premultiplied output. */ - virtual const GrFragmentProcessor* asFragmentProcessor(GrContext*, - const SkMatrix& viewMatrix, - const SkMatrix* localMatrix, - SkFilterQuality) const; + virtual sk_sp asFragmentProcessor(const AsFPArgs&) const; +#endif /** * If the shader can represent its "average" luminance in a single color, return true and @@ -375,6 +411,14 @@ public: */ 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); + static sk_sp MakeComposeShader(sk_sp dst, sk_sp src, SkXfermode::Mode); @@ -457,6 +501,7 @@ public: SK_TO_STRING_VIRT() SK_DEFINE_FLATTENABLE_TYPE(SkShader) + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() protected: void flatten(SkWriteBuffer&) const override; @@ -479,9 +524,15 @@ protected: return false; } +#ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP virtual bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode[2]) const { return false; } +#endif + + virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const { + return nullptr; + } private: // This is essentially const, but not officially so it can be modified in @@ -490,7 +541,7 @@ private: // So the SkLocalMatrixShader can whack fLocalMatrix in its SkReadBuffer constructor. friend class SkLocalMatrixShader; - friend class SkBitmapProcShader; // for computeTotalInverse() + friend class SkBitmapProcLegacyShader; // for computeTotalInverse() typedef SkFlattenable INHERITED; }; diff --git a/gfx/skia/skia/include/core/SkStream.h b/gfx/skia/skia/include/core/SkStream.h index a6a62c42ba1b..7afce712401c 100644 --- a/gfx/skia/skia/include/core/SkStream.h +++ b/gfx/skia/skia/include/core/SkStream.h @@ -40,11 +40,9 @@ public: virtual ~SkStream() {} /** - * Attempts to open the specified file, and return a stream to it (using - * mmap if available). On success, the caller is responsible for deleting. - * On failure, returns NULL. + * Attempts to open the specified file as a stream, returns nullptr on failure. */ - static SkStreamAsset* NewFromFile(const char path[]); + 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. @@ -200,7 +198,10 @@ public: bool write16(U16CPU); bool write32(uint32_t); - bool writeText(const char text[]); + bool writeText(const char text[]) { + SkASSERT(text); + return this->write(text, strlen(text)); + } bool writeDecAsText(int32_t); bool writeBigDecAsText(int64_t, int minDigits = 0); bool writeHexAsText(uint32_t, int minDigits = 0); @@ -288,11 +289,13 @@ public: /** If copyData is true, the stream makes a private copy of the data. */ SkMemoryStream(const void* data, size_t length, bool copyData = false); +#ifdef SK_SUPPORT_LEGACY_STREAM_DATA /** Use the specified data as the memory for this stream. * The stream will call ref() on the data (assuming it is not NULL). * DEPRECATED */ SkMemoryStream(SkData*); +#endif /** Creates the stream to read from the specified data */ SkMemoryStream(sk_sp); @@ -309,17 +312,24 @@ public: */ void setMemoryOwned(const void* data, size_t length); + sk_sp asData() const { return fData; } + void setData(sk_sp); +#ifdef SK_SUPPORT_LEGACY_STREAM_DATA /** Return the stream's data in a SkData. * The caller must call unref() when it is finished using the data. */ - SkData* copyToData() const; + SkData* copyToData() const { return asData().release(); } /** * Use the specified data as the memory for this stream. * The stream will call ref() on the data (assuming it is not NULL). * The function returns the data parameter as a convenience. */ - SkData* setData(SkData*); + SkData* setData(SkData* data) { + this->setData(sk_ref_sp(data)); + return data; + } +#endif void skipToAlign4(); const void* getAtPos(); @@ -401,11 +411,18 @@ public: void copyTo(void* dst) const; void writeToStream(SkWStream* dst) const; + sk_sp snapshotAsData() const; + // Return the contents as SkData, and then reset the stream. + sk_sp detachAsData(); +#ifdef SK_SUPPORT_LEGACY_STREAM_DATA /** * Return a copy of the data written so far. This call is responsible for * calling unref() when they are finished with the data. */ - SkData* copyToData() const; + SkData* copyToData() const { + return snapshotAsData().release(); + } +#endif /** Reset, returning a reader stream with the current content. */ SkStreamAsset* detachAsStream(); diff --git a/gfx/skia/skia/include/core/SkStrokeRec.h b/gfx/skia/skia/include/core/SkStrokeRec.h index 22981a5d9e44..9a49a3da7d06 100644 --- a/gfx/skia/skia/include/core/SkStrokeRec.h +++ b/gfx/skia/skia/include/core/SkStrokeRec.h @@ -98,6 +98,22 @@ public: */ 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); + /** * Compare if two SkStrokeRecs have an equal effect on a path. * Equal SkStrokeRecs produce equal paths. Equality of produced diff --git a/gfx/skia/skia/include/core/SkSurface.h b/gfx/skia/skia/include/core/SkSurface.h index ec76d268882e..8e7e148cb9ee 100644 --- a/gfx/skia/skia/include/core/SkSurface.h +++ b/gfx/skia/skia/include/core/SkSurface.h @@ -36,6 +36,8 @@ public: * * If the requested surface cannot be created, or the request is not a * supported configuration, NULL will be returned. + * + * Callers are responsible for initialiazing the surface pixels. */ static sk_sp MakeRasterDirect(const SkImageInfo&, void* pixels, size_t rowBytes, const SkSurfaceProps* = nullptr); @@ -49,11 +51,15 @@ public: void* context, const SkSurfaceProps* = nullptr); /** - * Return a new surface, with the memory for the pixels automatically allocated, but respecting + * Return a new surface, with the memory for the pixels automatically allocated but respecting * the specified rowBytes. If rowBytes==0, then a default value will be chosen. If a non-zero - * rowBytes is specified, then any images snapped off of this surface (via newImageSnapshot()) + * rowBytes is specified, then any images snapped off of this surface (via makeImageSnapshot()) * are guaranteed to have the same rowBytes. * + * If the requested alpha type is not opaque, then the surface's pixel memory will be + * zero-initialized. If it is opaque, then it will be left uninitialized, and the caller is + * responsible for initially clearing the surface. + * * If the requested surface cannot be created, or the request is not a * supported configuration, NULL will be returned. */ @@ -62,7 +68,10 @@ public: /** * Allocate a new surface, automatically computing the rowBytes. */ - static sk_sp MakeRaster(const SkImageInfo&, const SkSurfaceProps* = nullptr); + static sk_sp MakeRaster(const SkImageInfo& info, + const SkSurfaceProps* props = nullptr) { + return MakeRaster(info, 0, props); + } /** * Helper version of NewRaster. It creates a SkImageInfo with the @@ -74,12 +83,6 @@ public: return MakeRaster(SkImageInfo::MakeN32Premul(width, height), props); } - /** - * Return a new surface using the specified render target. - */ - static sk_sp MakeRenderTargetDirect(GrRenderTarget*, - const SkSurfaceProps* = nullptr); - /** * Used to wrap a pre-existing backend 3D API texture as a SkSurface. The kRenderTarget flag * must be set on GrBackendTextureDesc for this to succeed. Skia will not assume ownership @@ -87,7 +90,7 @@ public: * SkSurface. */ static sk_sp MakeFromBackendTexture(GrContext*, const GrBackendTextureDesc&, - const SkSurfaceProps*); + sk_sp, const SkSurfaceProps*); /** * Used to wrap a pre-existing 3D API rendering target as a SkSurface. Skia will not assume @@ -96,6 +99,7 @@ public: */ static sk_sp MakeFromBackendRenderTarget(GrContext*, const GrBackendRenderTargetDesc&, + sk_sp, const SkSurfaceProps*); /** @@ -107,21 +111,46 @@ public: * SkSurface. */ static sk_sp MakeFromBackendTextureAsRenderTarget( - GrContext*, const GrBackendTextureDesc&, const SkSurfaceProps*); + GrContext*, const GrBackendTextureDesc&, sk_sp, const SkSurfaceProps*); + + /** + * Legacy versions of the above factories, without color space support. These create "legacy" + * surfaces that operate without gamma correction or color management. + */ + static sk_sp MakeFromBackendTexture(GrContext* ctx, const GrBackendTextureDesc& desc, + const SkSurfaceProps* props) { + return MakeFromBackendTexture(ctx, desc, nullptr, props); + } + + static sk_sp MakeFromBackendRenderTarget(GrContext* ctx, + const GrBackendRenderTargetDesc& desc, + const SkSurfaceProps* props) { + return MakeFromBackendRenderTarget(ctx, desc, nullptr, props); + } + + static sk_sp MakeFromBackendTextureAsRenderTarget( + GrContext* ctx, const GrBackendTextureDesc& desc, const SkSurfaceProps* props) { + return MakeFromBackendTextureAsRenderTarget(ctx, desc, nullptr, props); + } + /** * Return a new surface whose contents will be drawn to an offscreen * render target, allocated by the surface. - * - * The GrTextureStorageAllocator will be reused if SkImage snapshots create - * additional textures. */ - static sk_sp MakeRenderTarget( - GrContext*, SkBudgeted, const SkImageInfo&, int sampleCount, const SkSurfaceProps*, - GrTextureStorageAllocator = GrTextureStorageAllocator()); + static sk_sp MakeRenderTarget(GrContext*, SkBudgeted, const SkImageInfo&, + int sampleCount, GrSurfaceOrigin, + const SkSurfaceProps*); + + static sk_sp MakeRenderTarget(GrContext* context, SkBudgeted budgeted, + const SkImageInfo& info, int sampleCount, + const SkSurfaceProps* props) { + return MakeRenderTarget(context, budgeted, info, sampleCount, + kBottomLeft_GrSurfaceOrigin, props); + } static sk_sp MakeRenderTarget(GrContext* gr, SkBudgeted b, const SkImageInfo& info) { - return MakeRenderTarget(gr, b, info, 0, nullptr); + return MakeRenderTarget(gr, b, info, 0, kBottomLeft_GrSurfaceOrigin, nullptr); } #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API @@ -147,12 +176,6 @@ public: const SkSurfaceProps* props = NULL) { return NewRaster(SkImageInfo::MakeN32Premul(width, height), props); } - static SkSurface* NewRenderTargetDirect(GrRenderTarget* rt, const SkSurfaceProps* props) { - return MakeRenderTargetDirect(rt, props).release(); - } - static SkSurface* NewRenderTargetDirect(GrRenderTarget* target) { - return NewRenderTargetDirect(target, NULL); - } static SkSurface* NewFromBackendTexture(GrContext* ctx, const GrBackendTextureDesc& desc, const SkSurfaceProps* props) { return MakeFromBackendTexture(ctx, desc, props).release(); @@ -172,9 +195,8 @@ public: return MakeFromBackendTextureAsRenderTarget(ctx, desc, props).release(); } static SkSurface* NewRenderTarget(GrContext* ctx, SkBudgeted b, const SkImageInfo& info, - int sampleCount, const SkSurfaceProps* props = NULL, - GrTextureStorageAllocator a = GrTextureStorageAllocator()) { - return MakeRenderTarget(ctx, b, info, sampleCount, props, a).release(); + int sampleCount, const SkSurfaceProps* props = NULL) { + return MakeRenderTarget(ctx, b, info, sampleCount, props).release(); } static SkSurface* NewRenderTarget(GrContext* gr, SkBudgeted b, const SkImageInfo& info) { return NewRenderTarget(gr, b, info, 0); diff --git a/gfx/skia/skia/include/core/SkSurfaceProps.h b/gfx/skia/skia/include/core/SkSurfaceProps.h index bd4fa8e7fcd6..da04d1fe9298 100644 --- a/gfx/skia/skia/include/core/SkSurfaceProps.h +++ b/gfx/skia/skia/include/core/SkSurfaceProps.h @@ -51,20 +51,7 @@ static inline bool SkPixelGeometryIsV(SkPixelGeometry geo) { class SK_API SkSurfaceProps { public: enum Flags { - kDisallowAntiAlias_Flag = 1 << 0, - kDisallowDither_Flag = 1 << 1, - kUseDeviceIndependentFonts_Flag = 1 << 2, - - /** - * This flag causes sRGB inputs to the color pipeline (images and other sRGB-tagged - * colors) to be gamma-corrected (converted to linear) before use. Without this flag, - * texture scaling and filtering is not gamma correct, preserving the behavior of Skia - * up through 2015. - * - * It is recommended to enable this flag when rendering to an sRGB or floating point - * surface. - */ - kAllowSRGBInputs_Flag = 1 << 3, + kUseDeviceIndependentFonts_Flag = 1 << 0, }; /** Deprecated alias used by Chromium. Will be removed. */ static const Flags kUseDistanceFieldFonts_Flag = kUseDeviceIndependentFonts_Flag; @@ -81,12 +68,9 @@ public: uint32_t flags() const { return fFlags; } SkPixelGeometry pixelGeometry() const { return fPixelGeometry; } - bool isDisallowAA() const { return SkToBool(fFlags & kDisallowAntiAlias_Flag); } - bool isDisallowDither() const { return SkToBool(fFlags & kDisallowDither_Flag); } bool isUseDeviceIndependentFonts() const { return SkToBool(fFlags & kUseDeviceIndependentFonts_Flag); } - bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); } private: SkSurfaceProps(); diff --git a/gfx/skia/skia/include/core/SkTLazy.h b/gfx/skia/skia/include/core/SkTLazy.h index 790f9579169e..cb08387bb9fe 100644 --- a/gfx/skia/skia/include/core/SkTLazy.h +++ b/gfx/skia/skia/include/core/SkTLazy.h @@ -19,21 +19,12 @@ */ template class SkTLazy { public: - SkTLazy() : fPtr(NULL) {} + SkTLazy() : fPtr(nullptr) {} - explicit SkTLazy(const T* src) : fPtr(NULL) { - if (src) { - fPtr = new (fStorage.get()) T(*src); - } - } + explicit SkTLazy(const T* src) + : fPtr(src ? new (fStorage.get()) T(*src) : nullptr) {} - SkTLazy(const SkTLazy& src) : fPtr(NULL) { - if (src.isValid()) { - fPtr = new (fStorage.get()) T(*src.get()); - } else { - fPtr = NULL; - } - } + SkTLazy(const SkTLazy& src) : fPtr(nullptr) { *this = src; } ~SkTLazy() { if (this->isValid()) { @@ -41,6 +32,15 @@ public: } } + SkTLazy& operator=(const SkTLazy& src) { + if (src.isValid()) { + this->set(*src.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 @@ -51,7 +51,7 @@ public: if (this->isValid()) { fPtr->~T(); } - fPtr = new (SkTCast(fStorage.get())) T(std__forward(args)...); + fPtr = new (SkTCast(fStorage.get())) T(std::forward(args)...); return fPtr; } @@ -76,7 +76,7 @@ public: void reset() { if (this->isValid()) { fPtr->~T(); - fPtr = NULL; + fPtr = nullptr; } } @@ -94,13 +94,13 @@ public: /** * Like above but doesn't assert if object isn't initialized (in which case - * NULL is returned). + * nullptr is returned). */ T* getMaybeNull() const { return fPtr; } private: - T* fPtr; // NULL or fStorage SkAlignedSTStorage<1, T> fStorage; + T* fPtr; // nullptr or fStorage }; /** @@ -134,11 +134,11 @@ public: SkTCopyOnFirstWrite(const T* initial) : fObj(initial) {} // Constructor for delayed initialization. - SkTCopyOnFirstWrite() : fObj(NULL) {} + SkTCopyOnFirstWrite() : fObj(nullptr) {} // Should only be called once, and only if the default constructor was used. void init(const T& initial) { - SkASSERT(NULL == fObj); + SkASSERT(nullptr == fObj); SkASSERT(!fLazy.isValid()); fObj = &initial; } diff --git a/gfx/skia/skia/include/core/SkTextBlob.h b/gfx/skia/skia/include/core/SkTextBlob.h index e43ff74a85f2..35d5dc41738f 100644 --- a/gfx/skia/skia/include/core/SkTextBlob.h +++ b/gfx/skia/skia/include/core/SkTextBlob.h @@ -10,6 +10,7 @@ #include "../private/SkTemplates.h" #include "SkPaint.h" +#include "SkString.h" #include "SkRefCnt.h" class SkReadBuffer; @@ -19,7 +20,7 @@ class SkWriteBuffer; SkTextBlob combines multiple text runs into an immutable, ref-counted structure. */ -class SK_API SkTextBlob : public SkRefCnt { +class SK_API SkTextBlob final : public SkNVRefCnt { public: /** * Returns a conservative blob bounding box. @@ -43,20 +44,25 @@ public: * @return A new SkTextBlob representing the serialized data, or NULL if the buffer is * invalid. */ - static const SkTextBlob* CreateFromBuffer(SkReadBuffer&); + static sk_sp MakeFromBuffer(SkReadBuffer&); - enum GlyphPositioning { + static const SkTextBlob* CreateFromBuffer(SkReadBuffer& buffer) { + return MakeFromBuffer(buffer).release(); + } + + enum GlyphPositioning : uint8_t { kDefault_Positioning = 0, // Default glyph advances -- zero scalars per glyph. kHorizontal_Positioning = 1, // Horizontal positioning -- one scalar per glyph. kFull_Positioning = 2 // Point positioning -- two scalars per glyph. }; private: + friend class SkNVRefCnt; class RunRecord; SkTextBlob(int runCount, const SkRect& bounds); - virtual ~SkTextBlob(); + ~SkTextBlob(); // Memory for objects of this class is created with sk_malloc rather than operator new and must // be freed with sk_free. @@ -98,16 +104,40 @@ public: * Returns an immutable SkTextBlob for the current runs/glyphs. The builder is reset and * can be reused. */ - const SkTextBlob* build(); + sk_sp make(); + +#ifdef SK_SUPPORT_LEGACY_TEXTBLOB_BUILDER + const SkTextBlob* build() { + return this->make().release(); + } +#endif /** * Glyph and position buffers associated with a run. * - * A run is a sequence of glyphs sharing the same font metrics and positioning mode. + * A run is a sequence of glyphs sharing the same font metrics + * and positioning mode. + * + * If textByteCount is 0, utf8text and clusters will be NULL (no + * character information will be associated with the glyphs). + * + * utf8text will point to a buffer of size textByteCount bytes. + * + * clusters (if not NULL) will point to an array of size count. + * For each glyph, give the byte-offset into the text for the + * first byte in the first character in that glyph's cluster. + * Each value in the array should be an integer less than + * textByteCount. Values in the array should either be + * monotonically increasing (left-to-right text) or monotonically + * decreasing (right-to-left text). This definiton is conviently + * the same as used by Harfbuzz's hb_glyph_info_t::cluster field, + * except that Harfbuzz interleaves glyphs and clusters. */ struct RunBuffer { - uint16_t* glyphs; + SkGlyphID* glyphs; SkScalar* pos; + char* utf8text; + uint32_t* clusters; }; /** @@ -117,14 +147,27 @@ public: * @param font The font to be used for this run. * @param count Number of glyphs. * @param x,y Position within the blob. + * @param textByteCount length of the original UTF-8 text that + * corresponds to this sequence of glyphs. If 0, + * text will not be included in the textblob. + * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * * @return A writable glyph buffer, valid until the next allocRun() or * build() call. The buffer is guaranteed to hold @count@ glyphs. */ + const RunBuffer& allocRunText(const SkPaint& font, + int count, + SkScalar x, + SkScalar y, + int textByteCount, + SkString lang, + const SkRect* bounds = NULL); const RunBuffer& allocRun(const SkPaint& font, int count, SkScalar x, SkScalar y, - const SkRect* bounds = NULL); + const SkRect* bounds = NULL) { + return this->allocRunText(font, count, x, y, 0, SkString(), bounds); + } /** * Allocates a new horizontally-positioned run and returns its writable glyph and position @@ -133,14 +176,23 @@ public: * @param font The font to be used for this run. * @param count Number of glyphs. * @param y Vertical offset within the blob. + * @param textByteCount length of the original UTF-8 text that + * corresponds to this sequence of glyphs. If 0, + * text will not be included in the textblob. + * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * * @return Writable glyph and position buffers, valid until the next allocRun() * or build() call. The buffers are guaranteed to hold @count@ elements. */ + const RunBuffer& allocRunTextPosH(const SkPaint& font, int count, SkScalar y, + int textByteCount, SkString lang, + const SkRect* bounds = NULL); const RunBuffer& allocRunPosH(const SkPaint& font, int count, SkScalar y, - const SkRect* bounds = NULL); + const SkRect* bounds = NULL) { + return this->allocRunTextPosH(font, count, y, 0, SkString(), bounds); + } /** * Allocates a new fully-positioned run and returns its writable glyph and position @@ -148,6 +200,10 @@ public: * * @param font The font to be used for this run. * @param count Number of glyphs. + * @param textByteCount length of the original UTF-8 text that + * corresponds to this sequence of glyphs. If 0, + * text will not be included in the textblob. + * @param lang Language code, currently unimplemented. * @param bounds Optional run bounding box. If known in advance (!= NULL), it will * be used when computing the blob bounds, to avoid re-measuring. * @@ -155,12 +211,18 @@ public: * or build() call. The glyph buffer and position buffer are * guaranteed to hold @count@ and 2 * @count@ elements, respectively. */ - const RunBuffer& allocRunPos(const SkPaint& font, int count, const SkRect* bounds = NULL); + const RunBuffer& allocRunTextPos(const SkPaint& font, int count, + int textByteCount, SkString lang, + const SkRect* bounds = NULL); + const RunBuffer& allocRunPos(const SkPaint& font, int count, + const SkRect* bounds = NULL) { + return this->allocRunTextPos(font, count, 0, SkString(), bounds); + } private: void reserve(size_t size); void allocInternal(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, - int count, SkPoint offset, const SkRect* bounds); + int count, int textBytes, SkPoint offset, const SkRect* bounds); bool mergeRun(const SkPaint& font, SkTextBlob::GlyphPositioning positioning, int count, SkPoint offset); void updateDeferredBounds(); diff --git a/gfx/skia/skia/include/core/SkTime.h b/gfx/skia/skia/include/core/SkTime.h index 8a8224a82a56..e9a894812b83 100644 --- a/gfx/skia/skia/include/core/SkTime.h +++ b/gfx/skia/skia/include/core/SkTime.h @@ -17,7 +17,7 @@ class SkString; /** \class SkTime Platform-implemented utilities to return time of day, and millisecond counter. */ -class SkTime { +class SK_API SkTime { public: struct DateTime { int16_t fTimeZoneMinutes; // The number of minutes that GetDateTime() diff --git a/gfx/skia/skia/include/core/SkTypeface.h b/gfx/skia/skia/include/core/SkTypeface.h index 80aa5fe03d12..c25552a2d001 100644 --- a/gfx/skia/skia/include/core/SkTypeface.h +++ b/gfx/skia/skia/include/core/SkTypeface.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,11 +5,11 @@ * found in the LICENSE file. */ - #ifndef SkTypeface_DEFINED #define SkTypeface_DEFINED -#include "../private/SkOncePtr.h" +#include "../private/SkBitmaskEnum.h" +#include "../private/SkOnce.h" #include "../private/SkWeakRefCnt.h" #include "SkFontStyle.h" #include "SkRect.h" @@ -21,6 +20,7 @@ class SkFontData; class SkFontDescriptor; class SkScalerContext; struct SkScalerContextRec; +struct SkScalerContextEffects; class SkStream; class SkStreamAsset; class SkAdvancedTypefaceMetrics; @@ -93,51 +93,66 @@ public: */ static bool Equal(const SkTypeface* facea, const SkTypeface* faceb); - /** - * Returns a ref() to the default typeface. The caller must call unref() - * when they are done referencing the object. Never returns NULL. - */ - static SkTypeface* RefDefault(Style style = SkTypeface::kNormal); + /** Returns the default typeface, which is never nullptr. */ + static sk_sp MakeDefault(Style style = SkTypeface::kNormal); +#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR + static SkTypeface* RefDefault(Style style = SkTypeface::kNormal) { + return MakeDefault(style).release(); + } +#endif - /** Return a new reference to the typeface that most closely matches the - requested familyName and style. Pass null as the familyName to return - the default font for the requested style. Will never return null + /** 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 style The style (normal, bold, italic) of the typeface. - @return reference to the closest-matching typeface. Call must call - unref() when they are done. + @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 SkTypeface* CreateFromName(const char familyName[], Style style); + static sk_sp MakeFromName(const char familyName[], SkFontStyle fontStyle); - /** Return a new reference to the typeface that most closely matches the - requested typeface and specified Style. Use this call if you want to - pick a new style from the same family of the existing typeface. - If family is NULL, this selects from the default font's family. +#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR + static SkTypeface* CreateFromName(const char familyName[], Style style) { + return MakeFromName(familyName, SkFontStyle::FromOldStyle(style)).release(); + } +#endif + + /** Return the typeface that most closely matches the requested typeface and style. + Use this to pick a new style from the same family of the existing typeface. + If family is nullptr, this selects from the default font's family. @param family May be NULL. The name of the existing type face. @param s The style (normal, bold, italic) of the type face. - @return reference to the closest-matching typeface. Call must call - unref() when they are done. + @return the closest-matching typeface. */ - static SkTypeface* CreateFromTypeface(const SkTypeface* family, Style s); + static sk_sp MakeFromTypeface(SkTypeface* family, Style); /** Return a new typeface given a file. If the file does not exist, or is - not a valid font file, returns null. + not a valid font file, returns nullptr. */ - static SkTypeface* CreateFromFile(const char path[], int index = 0); + static sk_sp MakeFromFile(const char path[], int index = 0); +#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR + static SkTypeface* CreateFromFile(const char path[], int index = 0) { + return MakeFromFile(path, index).release(); + } +#endif /** Return a new typeface given a stream. If the stream is - not a valid font file, returns null. Ownership of 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 SkTypeface* CreateFromStream(SkStreamAsset* stream, int index = 0); + static sk_sp MakeFromStream(SkStreamAsset* stream, int index = 0); +#ifdef SK_SUPPORT_LEGACY_TYPEFACE_PTR + static SkTypeface* CreateFromStream(SkStreamAsset* stream, int index = 0) { + return MakeFromStream(stream, index).release(); + } +#endif /** Return a new typeface given font data and configuration. If the data - is not valid font data, returns null. Ownership of the font data is - transferred, so the caller must not reference it again. + is not valid font data, returns nullptr. */ - static SkTypeface* CreateFromFontData(SkFontData*); + static sk_sp MakeFromFontData(std::unique_ptr); /** Write a unique signature to a stream, sufficient to reconstruct a typeface referencing the same font when Deserialize is called. @@ -145,12 +160,11 @@ public: void serialize(SkWStream*) const; /** Given the data previously written by serialize(), return a new instance - to a typeface referring to the same font. If that font is not available, - return null. If an instance is returned, the caller is responsible for - calling unref() when they are done with it. + of a typeface referring to the same font. If that font is not available, + return nullptr. Does not affect ownership of SkStream. */ - static SkTypeface* Deserialize(SkStream*); + static sk_sp MakeDeserialize(SkStream*); enum Encoding { kUTF8_Encoding, @@ -174,7 +188,7 @@ public: * from the beginning of chars. This value is valid, even if the * glyphs parameter is NULL. */ - int charsToGlyphs(const void* chars, Encoding encoding, uint16_t glyphs[], + int charsToGlyphs(const void* chars, Encoding encoding, SkGlyphID glyphs[], int glyphCount) const; /** @@ -248,7 +262,7 @@ public: * 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 uint16_t glyphs[], int count, + bool getKerningPairAdjustments(const SkGlyphID glyphs[], int count, int32_t adjustments[]) const; struct LocalizedString { @@ -285,17 +299,16 @@ public: SkStreamAsset* openStream(int* ttcIndex) const; /** - * Return the font data, or NULL on failure. - * The caller is responsible for deleting the font data. + * Return the font data, or nullptr on failure. */ - SkFontData* createFontData() const; + 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. */ - SkScalerContext* createScalerContext(const SkDescriptor*, + SkScalerContext* createScalerContext(const SkScalerContextEffects&, const SkDescriptor*, bool allowFailure = false) const; /** @@ -324,25 +337,26 @@ protected: // The type of advance data wanted. enum PerGlyphInfo { kNo_PerGlyphInfo = 0x0, // Don't populate any per glyph info. - kHAdvance_PerGlyphInfo = 0x1, // Populate horizontal advance data. - kVAdvance_PerGlyphInfo = 0x2, // Populate vertical advance data. - kGlyphNames_PerGlyphInfo = 0x4, // Populate glyph names (Type 1 only). - kToUnicode_PerGlyphInfo = 0x8 // Populate ToUnicode table, ignored - // for Type 1 fonts + kGlyphNames_PerGlyphInfo = 0x1, // Populate glyph names (Type 1 only). + kToUnicode_PerGlyphInfo = 0x2 // Populate ToUnicode table, ignored + // for Type 1 fonts }; /** uniqueID must be unique and non-zero */ - SkTypeface(const SkFontStyle& style, SkFontID uniqueID, bool isFixedPitch = false); + SkTypeface(const SkFontStyle& style, bool isFixedPitch = false); virtual ~SkTypeface(); /** 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; } friend class SkScalerContext; static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal); - virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const = 0; + virtual SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const = 0; virtual void onFilterRec(SkScalerContextRec*) const = 0; virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( PerGlyphInfo, @@ -351,16 +365,16 @@ protected: virtual SkStreamAsset* onOpenStream(int* ttcIndex) const = 0; // TODO: make pure virtual. - virtual SkFontData* onCreateFontData() const; + virtual std::unique_ptr onMakeFontData() const; virtual void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const = 0; - virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], + 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 uint16_t glyphs[], int count, + 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. @@ -381,7 +395,6 @@ private: friend class SkGTypeface; friend class SkRandomTypeface; friend class SkPDFFont; - friend class SkPDFCIDFont; friend class GrPathRendering; friend class GrGLPathRendering; @@ -401,12 +414,10 @@ private: uint32_t glyphIDsCount = 0) const; private: - static SkTypeface* CreateDefault(int style); // SkLazyPtr requires an int, not a Style. - static void DeleteDefault(SkTypeface*); - - SkOncePtr fLazyBounds; SkFontID fUniqueID; SkFontStyle fStyle; + mutable SkRect fBounds; + mutable SkOnce fBoundsOnce; bool fIsFixedPitch; friend class SkPaint; @@ -415,4 +426,8 @@ private: typedef SkWeakRefCnt INHERITED; }; +namespace skstd { +template <> struct is_bitmask_enum : std::true_type {}; +} + #endif diff --git a/gfx/skia/skia/include/core/SkTypes.h b/gfx/skia/skia/include/core/SkTypes.h index ae36f7d07371..0cef8a125702 100644 --- a/gfx/skia/skia/include/core/SkTypes.h +++ b/gfx/skia/skia/include/core/SkTypes.h @@ -17,7 +17,11 @@ // before #including . This makes no sense. I'm not very interested in // understanding why... these are old, bizarre platform configuration that we // should just let die. -#if defined(MOZ_B2G) && defined(__GNUC__) && __GNUC__ == 4 +// See https://llvm.org/bugs/show_bug.cgi?id=25608 . +#include // Include something innocuous to define _LIBCPP_VERISON if it's libc++. +#if defined(__GNUC__) && __GNUC__ == 4 \ + && ((defined(__arm__) && (defined(__ARM_NEON__) || defined(__ARM_NEON))) || defined(__aarch64__)) \ + && defined(_LIBCPP_VERSION) typedef float float32_t; #include #endif @@ -27,12 +31,6 @@ #include "SkPostConfig.h" #include #include - -#if defined(SK_ARM_HAS_NEON) - #include -#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - #include -#endif // IWYU pragma: end_exports #include @@ -141,45 +139,45 @@ inline void operator delete(void* p) { SK_API void SkDebugf(const char format[], ...); #endif -#define SkASSERT_RELEASE(cond) if(!(cond)) { SK_ABORT(#cond); } +#define SkREQUIRE_SEMICOLON_AFTER(code) do { code } while (false) + +#define SkASSERT_RELEASE(cond) \ + SkREQUIRE_SEMICOLON_AFTER(if (!(cond)) { SK_ABORT(#cond); } ) #ifdef SK_DEBUG - #define SkASSERT(cond) SkASSERT_RELEASE(cond) - #define SkDEBUGFAIL(message) SkASSERT(false && message) + #define SkASSERT(cond) \ + SkREQUIRE_SEMICOLON_AFTER(if (!(cond)) { SK_ABORT("assert(" #cond ")"); }) + #define SkASSERTF(cond, fmt, ...) \ + SkREQUIRE_SEMICOLON_AFTER(if (!(cond)) { \ + 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(code) code + #define SkDEBUGCODE(...) __VA_ARGS__ #define SkDECLAREPARAM(type, var) , type var #define SkPARAM(var) , var -// #define SkDEBUGF(args ) SkDebugf##args #define SkDEBUGF(args ) SkDebugf args #define SkAssertResult(cond) SkASSERT(cond) #else #define SkASSERT(cond) + #define SkASSERTF(cond, fmt, ...) #define SkDEBUGFAIL(message) - #define SkDEBUGCODE(code) + #define SkDEBUGFAILF(fmt, ...) + #define SkDEBUGCODE(...) #define SkDEBUGF(args) #define SkDECLAREPARAM(type, var) #define SkPARAM(var) - // unlike SkASSERT, this guy executes its condition in the non-debug build - #define SkAssertResult(cond) cond + // unlike SkASSERT, this guy 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 // Legacy macro names for SK_ABORT #define SkFAIL(message) SK_ABORT(message) #define sk_throw() SK_ABORT("sk_throw") -// We want to evaluate cond only once, and inside the SkASSERT somewhere so we see its string form. -// So we use the comma operator to make an SkDebugf that always returns false: we'll evaluate cond, -// and if it's true the assert passes; if it's false, we'll print the message and the assert fails. -#define SkASSERTF(cond, fmt, ...) SkASSERT((cond) || (SkDebugf(fmt"\n", __VA_ARGS__), false)) - -#ifdef SK_DEVELOPER - #define SkDEVCODE(code) code -#else - #define SkDEVCODE(code) -#endif - #ifdef SK_IGNORE_TO_STRING #define SK_TO_STRING_NONVIRT() #define SK_TO_STRING_VIRT() @@ -286,7 +284,7 @@ template D SkTo(S s) { /** Returns 0 or 1 based on the condition */ -#define SkToBool(cond) (!!(cond)) +#define SkToBool(cond) ((cond) != 0) #define SK_MaxS16 32767 #define SK_MinS16 -32767 @@ -356,6 +354,10 @@ typedef uint32_t SkFourByteTag; */ 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. */ @@ -387,7 +389,7 @@ typedef uint32_t SkMSec; /** Faster than SkToBool for integral conditions. Returns 0 or 1 */ -static inline int Sk32ToBool(uint32_t n) { +static inline constexpr int Sk32ToBool(uint32_t n) { return (n | (0-n)) >> 31; } @@ -426,11 +428,11 @@ static inline int32_t SkMin32(int32_t a, int32_t b) { return a; } -template const T& SkTMin(const T& a, const T& b) { +template constexpr const T& SkTMin(const T& a, const T& b) { return (a < b) ? a : b; } -template const T& SkTMax(const T& a, const T& b) { +template constexpr const T& SkTMax(const T& a, const T& b) { return (b < a) ? a : b; } @@ -446,7 +448,7 @@ static inline int32_t SkFastMin32(int32_t value, int32_t max) { } /** Returns value pinned between min and max, inclusively. */ -template static inline const T& SkTPin(const T& value, const T& min, const T& max) { +template static constexpr const T& SkTPin(const T& value, const T& min, const T& max) { return SkTMax(SkTMin(value, max), min); } @@ -461,6 +463,15 @@ enum class SkBudgeted : bool { 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 +}; + /////////////////////////////////////////////////////////////////////////////// /** Use to combine multiple bits in a bitmask in a type safe way. diff --git a/gfx/skia/skia/include/core/SkWriteBuffer.h b/gfx/skia/skia/include/core/SkWriteBuffer.h index 3ae82d014aee..29f923fedd18 100644 --- a/gfx/skia/skia/include/core/SkWriteBuffer.h +++ b/gfx/skia/skia/include/core/SkWriteBuffer.h @@ -16,85 +16,120 @@ #include "SkPixelSerializer.h" #include "SkRefCnt.h" #include "SkWriter32.h" +#include "../private/SkTHash.h" class SkBitmap; -class SkBitmapHeap; +class SkDeduper; class SkFactorySet; class SkFlattenable; -class SkNamedFactorySet; class SkRefCntSet; class SkWriteBuffer { +public: + SkWriteBuffer() {} + virtual ~SkWriteBuffer() {} + + virtual bool isCrossProcess() const = 0; + + virtual void writeByteArray(const void* data, size_t size) = 0; + void writeDataAsByteArray(SkData* data) { + this->writeByteArray(data->data(), data->size()); + } + virtual void writeBool(bool value) = 0; + virtual void writeScalar(SkScalar value) = 0; + virtual void writeScalarArray(const SkScalar* value, uint32_t count) = 0; + virtual void writeInt(int32_t value) = 0; + virtual void writeIntArray(const int32_t* value, uint32_t count) = 0; + virtual void writeUInt(uint32_t value) = 0; + void write32(int32_t value) { + this->writeInt(value); + } + virtual void writeString(const char* value) = 0; + + virtual void writeFlattenable(const SkFlattenable* flattenable) = 0; + virtual void writeColor(SkColor color) = 0; + virtual void writeColorArray(const SkColor* color, uint32_t count) = 0; + virtual void writeColor4f(const SkColor4f& color) = 0; + virtual void writeColor4fArray(const SkColor4f* color, uint32_t count) = 0; + virtual void writePoint(const SkPoint& point) = 0; + virtual void writePointArray(const SkPoint* point, uint32_t count) = 0; + virtual void writeMatrix(const SkMatrix& matrix) = 0; + virtual void writeIRect(const SkIRect& rect) = 0; + virtual void writeRect(const SkRect& rect) = 0; + virtual void writeRegion(const SkRegion& region) = 0; + virtual void writePath(const SkPath& path) = 0; + virtual size_t writeStream(SkStream* stream, size_t length) = 0; + virtual void writeBitmap(const SkBitmap& bitmap) = 0; + virtual void writeImage(const SkImage*) = 0; + virtual void writeTypeface(SkTypeface* typeface) = 0; + virtual void writePaint(const SkPaint& paint) = 0; + + void setDeduper(SkDeduper* deduper) { fDeduper = deduper; } + +protected: + SkDeduper* fDeduper = nullptr; +}; + +/** + * Concrete implementation that serializes to a flat binary blob. + */ +class SkBinaryWriteBuffer : public SkWriteBuffer { public: enum Flags { - kCrossProcess_Flag = 1 << 0, - kValidation_Flag = 1 << 1, + kCrossProcess_Flag = 1 << 0, }; - SkWriteBuffer(uint32_t flags = 0); - SkWriteBuffer(void* initialStorage, size_t storageSize, uint32_t flags = 0); - ~SkWriteBuffer(); + SkBinaryWriteBuffer(uint32_t flags = 0); + SkBinaryWriteBuffer(void* initialStorage, size_t storageSize, uint32_t flags = 0); + ~SkBinaryWriteBuffer(); - bool isCrossProcess() const { - return this->isValidating() || SkToBool(fFlags & kCrossProcess_Flag); + bool isCrossProcess() const override { + return SkToBool(fFlags & kCrossProcess_Flag); + } + + void write(const void* buffer, size_t bytes) { + fWriter.write(buffer, bytes); } - SkWriter32* getWriter32() { return &fWriter; } void reset(void* storage = NULL, size_t storageSize = 0) { fWriter.reset(storage, storageSize); } - uint32_t* reserve(size_t size) { return fWriter.reserve(size); } - size_t bytesWritten() const { return fWriter.bytesWritten(); } - void writeByteArray(const void* data, size_t size); - void writeDataAsByteArray(SkData* data) { this->writeByteArray(data->data(), data->size()); } - void writeBool(bool value); - void writeScalar(SkScalar value); - void writeScalarArray(const SkScalar* value, uint32_t count); - void writeInt(int32_t value); - void writeIntArray(const int32_t* value, uint32_t count); - void writeUInt(uint32_t value); - void write32(int32_t value); - void writeString(const char* value); - void writeEncodedString(const void* value, size_t byteLength, SkPaint::TextEncoding encoding); - void writeFunctionPtr(void* ptr) { fWriter.writePtr(ptr); } + void writeByteArray(const void* data, size_t size) override; + void writeBool(bool value) override; + void writeScalar(SkScalar value) override; + void writeScalarArray(const SkScalar* value, uint32_t count) override; + void writeInt(int32_t value) override; + void writeIntArray(const int32_t* value, uint32_t count) override; + void writeUInt(uint32_t value) override; + void writeString(const char* value) override; - void writeFlattenable(const SkFlattenable* flattenable); - void writeColor(const SkColor& color); - void writeColorArray(const SkColor* color, uint32_t count); - void writePoint(const SkPoint& point); - void writePointArray(const SkPoint* point, uint32_t count); - void writeMatrix(const SkMatrix& matrix); - void writeIRect(const SkIRect& rect); - void writeRect(const SkRect& rect); - void writeRegion(const SkRegion& region); - void writePath(const SkPath& path); - size_t writeStream(SkStream* stream, size_t length); - void writeBitmap(const SkBitmap& bitmap); - void writeImage(const SkImage*); - void writeTypeface(SkTypeface* typeface); - void writePaint(const SkPaint& paint) { paint.flatten(*this); } + void writeFlattenable(const SkFlattenable* flattenable) override; + void writeColor(SkColor color) override; + void writeColorArray(const SkColor* color, uint32_t count) override; + void writeColor4f(const SkColor4f& color) override; + void writeColor4fArray(const SkColor4f* color, uint32_t count) override; + void writePoint(const SkPoint& point) override; + void writePointArray(const SkPoint* point, uint32_t count) override; + void writeMatrix(const SkMatrix& matrix) override; + void writeIRect(const SkIRect& rect) override; + void writeRect(const SkRect& rect) override; + void writeRegion(const SkRegion& region) override; + void writePath(const SkPath& path) override; + size_t writeStream(SkStream* stream, size_t length) override; + void writeBitmap(const SkBitmap& bitmap) override; + void writeImage(const SkImage*) override; + void writeTypeface(SkTypeface* typeface) override; + void writePaint(const SkPaint& paint) override; bool writeToStream(SkWStream*); void writeToMemory(void* dst) { fWriter.flatten(dst); } SkFactorySet* setFactoryRecorder(SkFactorySet*); - SkNamedFactorySet* setNamedFactoryRecorder(SkNamedFactorySet*); - - SkRefCntSet* getTypefaceRecorder() const { return fTFSet; } SkRefCntSet* setTypefaceRecorder(SkRefCntSet*); - /** - * Set an SkBitmapHeap to store bitmaps rather than flattening. - * - * Incompatible with an SkPixelSerializer. If an SkPixelSerializer is set, - * setting an SkBitmapHeap will set the SkPixelSerializer to NULL in release - * and crash in debug. - */ - void setBitmapHeap(SkBitmapHeap*); - /** * Set an SkPixelSerializer to store an encoded representation of pixels, * e.g. SkBitmaps. @@ -102,25 +137,21 @@ public: * Calls ref() on the serializer. * * TODO: Encode SkImage pixels as well. - * - * Incompatible with the SkBitmapHeap. If an encoder is set fBitmapHeap will - * be set to NULL in release and crash in debug. */ void setPixelSerializer(SkPixelSerializer*); SkPixelSerializer* getPixelSerializer() const { return fPixelSerializer; } private: - bool isValidating() const { return SkToBool(fFlags & kValidation_Flag); } - const uint32_t fFlags; SkFactorySet* fFactorySet; - SkNamedFactorySet* fNamedFactorySet; SkWriter32 fWriter; - SkBitmapHeap* fBitmapHeap; SkRefCntSet* fTFSet; SkAutoTUnref fPixelSerializer; + + // Only used if we do not have an fFactorySet + SkTHashMap fFlattenableDict; }; #endif // SkWriteBuffer_DEFINED diff --git a/gfx/skia/skia/include/core/SkWriter32.h b/gfx/skia/skia/include/core/SkWriter32.h index 26388cd37ea9..a5ecb3f24a2c 100644 --- a/gfx/skia/skia/include/core/SkWriter32.h +++ b/gfx/skia/skia/include/core/SkWriter32.h @@ -51,12 +51,6 @@ public: fExternal = external; } - // Returns the current buffer. - // The pointer may be invalidated by any future write calls. - const uint32_t* contiguousArray() const { - return (uint32_t*)fData; - } - // size MUST be multiple of 4 uint32_t* reserve(size_t size) { SkASSERT(SkAlign4(size) == size); diff --git a/gfx/skia/skia/include/core/SkXfermode.h b/gfx/skia/skia/include/core/SkXfermode.h index db8d570ce0c3..253ee1b4089a 100644 --- a/gfx/skia/skia/include/core/SkXfermode.h +++ b/gfx/skia/skia/include/core/SkXfermode.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,18 +5,21 @@ * found in the LICENSE file. */ - #ifndef SkXfermode_DEFINED #define SkXfermode_DEFINED -#include "SkFlattenable.h" +#include "SkBlendMode.h" #include "SkColor.h" +#include "SkFlattenable.h" class GrFragmentProcessor; class GrTexture; class GrXPFactory; +class SkRasterPipeline; class SkString; +struct SkArithmeticParams; + struct SkPM4f; typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst); @@ -113,6 +115,9 @@ public: * Gets the name of the Mode as a string. */ static const char* ModeName(Mode); + static const char* ModeName(SkBlendMode mode) { + return ModeName(Mode(mode)); + } /** * If the xfermode is one of the modes in the Mode enum, then asMode() @@ -158,6 +163,31 @@ public: } #endif + /** + * Skia maintains global xfermode objects corresponding to each BlendMode. This returns a + * ptr to that global xfermode (or null if the mode is srcover). Thus the caller may use + * the returned ptr, but it should leave its refcnt untouched. + */ + static SkXfermode* Peek(SkBlendMode mode) { + sk_sp xfer = Make(mode); + if (!xfer) { + SkASSERT(SkBlendMode::kSrcOver == mode); + return nullptr; + } + SkASSERT(!xfer->unique()); + return xfer.get(); + } + + static sk_sp Make(SkBlendMode bm) { + return Make((Mode)bm); + } + + SkBlendMode blend() const { + Mode mode; + SkAssertResult(this->asMode(&mode)); + return (SkBlendMode)mode; + } + /** Return a function pointer to a routine that applies the specified porter-duff transfer mode. */ @@ -166,6 +196,8 @@ public: virtual SkXfermodeProc4f getProc4f() const; + bool appendStages(SkRasterPipeline*) const; + /** * If the specified mode can be represented by a pair of Coeff, then return * true and set (if not NULL) the corresponding coeffs. If the mode is @@ -214,22 +246,23 @@ public: static bool IsOpaque(const sk_sp& xfer, SrcColorOpacity opacityType) { return IsOpaque(xfer.get(), opacityType); } + static bool IsOpaque(SkBlendMode, SrcColorOpacity); #if SK_SUPPORT_GPU /** Used by the SkXfermodeImageFilter to blend two colors via a GrFragmentProcessor. The input to the returned FP is the src color. The dst color is - provided by the dst param which becomes a child FP of the returned FP. + provided by the dst param which becomes a child FP of the returned FP. It is legal for the function to return a null output. This indicates that the output of the blend is simply the src color. */ - virtual const GrFragmentProcessor* getFragmentProcessorForImageFilter( - const GrFragmentProcessor* dst) const; + virtual sk_sp makeFragmentProcessorForImageFilter( + sk_sp dst) const; - /** A subclass must implement this factory function to work with the GPU backend. - The xfermode will return a factory for which the caller will get a ref. It is up + /** A subclass must implement this factory function to work with the GPU backend. + The xfermode will return a factory for which the caller will get a ref. It is up to the caller to install it. XferProcessors cannot use a background texture. */ - virtual GrXPFactory* asXPFactory() const; + virtual sk_sp asXPFactory() const; #endif SK_TO_STRING_PUREVIRT() @@ -248,27 +281,28 @@ public: return GetD32Proc(xfer.get(), flags); } - enum D64Flags { - kSrcIsOpaque_D64Flag = 1 << 0, - kSrcIsSingle_D64Flag = 1 << 1, - kDstIsFloat16_D64Flag = 1 << 2, // else U16 bit components + enum F16Flags { + kSrcIsOpaque_F16Flag = 1 << 0, + kSrcIsSingle_F16Flag = 1 << 1, }; - typedef void (*D64Proc)(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, + typedef void (*F16Proc)(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, const SkAlpha coverage[]); - static D64Proc GetD64Proc(SkXfermode*, uint32_t flags); - static D64Proc GetD64Proc(const sk_sp& xfer, uint32_t flags) { - return GetD64Proc(xfer.get(), flags); + static F16Proc GetF16Proc(SkXfermode*, uint32_t flags); + static F16Proc GetF16Proc(const sk_sp& xfer, uint32_t flags) { + return GetF16Proc(xfer.get(), flags); } enum LCDFlags { kSrcIsOpaque_LCDFlag = 1 << 0, // else src(s) may have alpha < 1 kSrcIsSingle_LCDFlag = 1 << 1, // else src[count] - kDstIsLinearInt_LCDFlag = 1 << 2, // else srgb/half-float + kDstIsSRGB_LCDFlag = 1 << 2, // else l32 or f16 }; typedef void (*LCD32Proc)(uint32_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]); - typedef void (*LCD64Proc)(uint64_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]); + typedef void (*LCDF16Proc)(uint64_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]); static LCD32Proc GetLCD32Proc(uint32_t flags); - static LCD64Proc GetLCD64Proc(uint32_t) { return nullptr; } + static LCDF16Proc GetLCDF16Proc(uint32_t) { return nullptr; } + + virtual bool isArithmetic(SkArithmeticParams*) const { return false; } protected: SkXfermode() {} @@ -283,7 +317,8 @@ protected: virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const; virtual D32Proc onGetD32Proc(uint32_t flags) const; - virtual D64Proc onGetD64Proc(uint32_t flags) const; + virtual F16Proc onGetF16Proc(uint32_t flags) const; + virtual bool onAppendStages(SkRasterPipeline*) const; private: enum { diff --git a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h index aee365f99986..18b760fc9f81 100644 --- a/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h +++ b/gfx/skia/skia/include/effects/SkAlphaThresholdFilter.h @@ -9,7 +9,8 @@ #define SkAlphaThresholdFilter_DEFINED #include "SkImageFilter.h" -#include "SkRegion.h" + +class SkRegion; class SK_API SkAlphaThresholdFilter { public: @@ -21,7 +22,8 @@ public: * source image. */ static sk_sp Make(const SkRegion& region, SkScalar innerMin, - SkScalar outerMax, sk_sp input); + SkScalar outerMax, sk_sp input, + const SkImageFilter::CropRect* cropRect = nullptr); #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR diff --git a/gfx/skia/skia/include/effects/SkArithmeticMode.h b/gfx/skia/skia/include/effects/SkArithmeticMode.h index b160dc7e9bf2..81b9f85394d0 100644 --- a/gfx/skia/skia/include/effects/SkArithmeticMode.h +++ b/gfx/skia/skia/include/effects/SkArithmeticMode.h @@ -12,6 +12,8 @@ #include "SkScalar.h" #include "SkXfermode.h" +#ifdef SK_SUPPORT_LEGACY_ARITHMETICMODE + class SK_API SkArithmeticMode { public: /** @@ -38,3 +40,5 @@ private: }; #endif + +#endif diff --git a/gfx/skia/skia/include/effects/SkBlurImageFilter.h b/gfx/skia/skia/include/effects/SkBlurImageFilter.h index 607e76de513e..e2109d05616a 100644 --- a/gfx/skia/skia/include/effects/SkBlurImageFilter.h +++ b/gfx/skia/skia/include/effects/SkBlurImageFilter.h @@ -9,44 +9,23 @@ #define SkBlurImageFilter_DEFINED #include "SkImageFilter.h" -#include "SkSize.h" -class SK_API SkBlurImageFilter : public SkImageFilter { +class SK_API SkBlurImageFilter { public: - static sk_sp Make(SkScalar sigmaX, SkScalar sigmaY, sk_sp input, - const CropRect* cropRect = nullptr) { - if (0 == sigmaX && 0 == sigmaY && nullptr == cropRect) { - return input; - } - return sk_sp(new SkBlurImageFilter(sigmaX, sigmaY, input, cropRect)); + static sk_sp Make(SkScalar sigmaX, SkScalar sigmaY, + sk_sp input, + const SkImageFilter::CropRect* cropRect = nullptr) { + return SkImageFilter::MakeBlur(sigmaX, sigmaY, input, cropRect); } - SkRect computeFastBounds(const SkRect&) const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurImageFilter) - #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input = nullptr, - const CropRect* cropRect = nullptr) { - return Make(sigmaX, sigmaY, sk_ref_sp(input), cropRect).release(); + static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, + SkImageFilter * input = nullptr, + const SkImageFilter::CropRect* cropRect = nullptr) { + return SkImageFilter::MakeBlur(sigmaX, sigmaY, sk_ref_sp(input), + cropRect).release(); } #endif - -protected: - void flatten(SkWriteBuffer&) const override; - sk_sp onFilterImage(SkSpecialImage* source, const Context&, - SkIPoint* offset) const override; - SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; - -private: - SkBlurImageFilter(SkScalar sigmaX, - SkScalar sigmaY, - sk_sp input, - const CropRect* cropRect); - - SkSize fSigma; - typedef SkImageFilter INHERITED; }; #endif diff --git a/gfx/skia/skia/include/effects/SkBlurMaskFilter.h b/gfx/skia/skia/include/effects/SkBlurMaskFilter.h index 3ba91774f05b..dfbae6b689a2 100644 --- a/gfx/skia/skia/include/effects/SkBlurMaskFilter.h +++ b/gfx/skia/skia/include/effects/SkBlurMaskFilter.h @@ -32,13 +32,21 @@ 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 flags Flags to use - defaults to none + * @param style The SkBlurStyle to use + * @param sigma Standard deviation of the Gaussian blur to apply. Must be > 0. + * @param occluder The rect for which no pixels need be drawn (b.c. it will be overdrawn + * with some opaque object. This is just a hint which backends are free to + * ignore. + * @param flags Flags to use - defaults to none * @return The new blur maskfilter */ static sk_sp Make(SkBlurStyle style, SkScalar sigma, - uint32_t flags = kNone_BlurFlag); + const SkRect& occluder, uint32_t flags = kNone_BlurFlag); + + static sk_sp Make(SkBlurStyle style, SkScalar sigma, + uint32_t flags = kNone_BlurFlag) { + return Make(style, sigma, SkRect::MakeEmpty(), flags); + } /** Create an emboss maskfilter @param blurSigma standard deviation of the Gaussian blur to apply @@ -65,6 +73,28 @@ public: SkScalar blurRadius); #endif + static const int kMaxDivisions = 6; + + // This method computes all the parameters for drawing a partially occluded nine-patched + // blurred rrect mask: + // rrectToDraw - the integerized rrect to draw in the mask + // widthHeight - how large to make the mask (rrectToDraw will be centered in this coord sys) + // rectXs, rectYs - the x & y coordinates of the covering geometry lattice + // texXs, texYs - the texture coordinate at each point in rectXs & rectYs + // numXs, numYs - number of coordinates in the x & y directions + // skipMask - bit mask that contains a 1-bit whenever one of the cells is occluded + // It returns true if 'devRRect' is nine-patchable + static bool ComputeBlurredRRectParams(const SkRRect& srcRRect, const SkRRect& devRRect, + const SkRect& occluder, + SkScalar sigma, SkScalar xformedSigma, + SkRRect* rrectToDraw, + SkISize* widthHeight, + SkScalar rectXs[kMaxDivisions], + SkScalar rectYs[kMaxDivisions], + SkScalar texXs[kMaxDivisions], + SkScalar texYs[kMaxDivisions], + int* numXs, int* numYs, uint32_t* skipMask); + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() private: diff --git a/gfx/skia/skia/include/effects/SkColorCubeFilter.h b/gfx/skia/skia/include/effects/SkColorCubeFilter.h index 8b621292b03b..fbfe698ba812 100644 --- a/gfx/skia/skia/include/effects/SkColorCubeFilter.h +++ b/gfx/skia/skia/include/effects/SkColorCubeFilter.h @@ -10,7 +10,7 @@ #include "SkColorFilter.h" #include "SkData.h" -#include "../private/SkMutex.h" +#include "../private/SkOnce.h" #include "../private/SkTemplates.h" class SK_API SkColorCubeFilter : public SkColorFilter { @@ -30,7 +30,7 @@ public: uint32_t getFlags() const override; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*) const override; #endif SK_TO_STRING_OVERRIDE() @@ -65,8 +65,7 @@ private: const int fCubeDimension; // Make sure we only initialize the caches once. - SkMutex fLutsMutex; - bool fLutsInited; + SkOnce fLutsInitOnce; static void initProcessingLuts(ColorCubeProcesingCache* cache); }; diff --git a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h index 2aa04d1644b0..4d438e351972 100644 --- a/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h +++ b/gfx/skia/skia/include/effects/SkColorFilterImageFilter.h @@ -33,9 +33,10 @@ public: protected: void flatten(SkWriteBuffer&) const override; - bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, - SkIPoint* loc) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; bool onIsColorFilterNode(SkColorFilter**) const override; + bool onCanHandleComplexCTM() const override { return true; } bool affectsTransparentBlack() const override; private: diff --git a/gfx/skia/skia/include/effects/SkComposeImageFilter.h b/gfx/skia/skia/include/effects/SkComposeImageFilter.h index 49c768541514..378b90471b87 100644 --- a/gfx/skia/skia/include/effects/SkComposeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkComposeImageFilter.h @@ -12,16 +12,8 @@ class SK_API SkComposeImageFilter : public SkImageFilter { public: - static sk_sp Make(sk_sp outer, sk_sp inner) { - if (!outer) { - return inner; - } - if (!inner) { - return outer; - } - sk_sp inputs[2] = { std::move(outer), std::move(inner) }; - return sk_sp(new SkComposeImageFilter(inputs)); - } + static sk_sp Make(sk_sp outer, sk_sp inner); + SkRect computeFastBounds(const SkRect& src) const override; SK_TO_STRING_OVERRIDE() @@ -42,6 +34,7 @@ protected: sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; + bool onCanHandleComplexCTM() const override { return true; } private: typedef SkImageFilter INHERITED; diff --git a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h index a5b81e85851f..f93f2c445481 100644 --- a/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h +++ b/gfx/skia/skia/include/effects/SkDisplacementMapEffect.h @@ -9,7 +9,6 @@ #define SkDisplacementMapEffect_DEFINED #include "SkImageFilter.h" -#include "SkBitmap.h" class SK_API SkDisplacementMapEffect : public SkImageFilter { public: @@ -21,39 +20,45 @@ public: kA_ChannelSelectorType }; - ~SkDisplacementMapEffect(); + ~SkDisplacementMapEffect() override; - static SkImageFilter* Create(ChannelSelectorType xChannelSelector, - ChannelSelectorType yChannelSelector, - SkScalar scale, SkImageFilter* displacement, - SkImageFilter* color = NULL, - const CropRect* cropRect = NULL); + static sk_sp Make(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, + sk_sp displacement, + sk_sp color, + const CropRect* cropRect = nullptr); SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDisplacementMapEffect) - bool onFilterImageDeprecated(Proxy* proxy, - const SkBitmap& src, - const Context& ctx, - SkBitmap* dst, - SkIPoint* offset) const override; SkRect computeFastBounds(const SkRect& src) const override; virtual SkIRect onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; -#if SK_SUPPORT_GPU - bool canFilterImageGPU() const override { return true; } - bool filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, - SkBitmap* result, SkIPoint* offset) const override; -#endif - SK_TO_STRING_OVERRIDE() +#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR + static SkImageFilter* Create(ChannelSelectorType xChannelSelector, + ChannelSelectorType yChannelSelector, + SkScalar scale, SkImageFilter* displacement, + SkImageFilter* color = nullptr, + const CropRect* cropRect = nullptr) { + return Make(xChannelSelector, yChannelSelector, scale, + sk_ref_sp(displacement), + sk_ref_sp(color), + cropRect).release(); + } +#endif + protected: + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, ChannelSelectorType yChannelSelector, - SkScalar scale, SkImageFilter* inputs[2], + SkScalar scale, sk_sp inputs[2], const CropRect* cropRect); void flatten(SkWriteBuffer&) const override; diff --git a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h index a4726f3247f8..87e74068298b 100644 --- a/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h +++ b/gfx/skia/skia/include/effects/SkDropShadowImageFilter.h @@ -26,12 +26,7 @@ public: static sk_sp Make(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, ShadowMode shadowMode, sk_sp input, - const CropRect* cropRect = nullptr) { - return sk_sp(new SkDropShadowImageFilter(dx, dy, sigmaX, sigmaY, - color, shadowMode, - std::move(input), - cropRect)); - } + const CropRect* cropRect = nullptr); SkRect computeFastBounds(const SkRect&) const override; SK_TO_STRING_OVERRIDE() diff --git a/gfx/skia/skia/include/effects/SkGammaColorFilter.h b/gfx/skia/skia/include/effects/SkGammaColorFilter.h new file mode 100644 index 000000000000..308926a3ab49 --- /dev/null +++ b/gfx/skia/skia/include/effects/SkGammaColorFilter.h @@ -0,0 +1,48 @@ +/* + * 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 SkGammaColorFilter_DEFINED +#define SkGammaColorFilter_DEFINED + +#include "SkColorFilter.h" +#include "SkRefCnt.h" + +// This colorfilter can be used to perform pixel-by-pixel conversion between linear and +// power-law color spaces. A gamma of 2.2 is interpreted to mean convert from sRGB to linear +// while a gamma of 1/2.2 is interpreted to mean convert from linear to sRGB. Any other +// values are just directly applied (i.e., out = in^gamma) +// +// More complicated color space mapping (i.e., ICC profiles) should be handled via the +// SkColorSpace object. +class SK_API SkGammaColorFilter : public SkColorFilter { +public: + static sk_sp Make(SkScalar gamma); + +#ifdef SK_SUPPORT_LEGACY_COLORFILTER_PTR + static SkColorFilter* Create(SkScalar gamma) { return Make(gamma).release(); } +#endif + + void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(GrContext*) const override; +#endif + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLumaColorFilter) + +protected: + void flatten(SkWriteBuffer&) const override; + +private: + SkGammaColorFilter(SkScalar gamma); + + SkScalar fGamma; + typedef SkColorFilter INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkGaussianEdgeShader.h b/gfx/skia/skia/include/effects/SkGaussianEdgeShader.h new file mode 100644 index 000000000000..ef54ece56ea5 --- /dev/null +++ b/gfx/skia/skia/include/effects/SkGaussianEdgeShader.h @@ -0,0 +1,27 @@ +/* + * 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 SkGaussianEdgeShader_DEFINED +#define SkGaussianEdgeShader_DEFINED + +#include "SkShader.h" + +class SK_API SkGaussianEdgeShader { +public: + /** Returns a shader that applies a Gaussian blur depending on distance to the edge + * Currently this is only useable with Circle and RRect shapes on the GPU backend. + * Raster will draw nothing. + */ + static sk_sp Make(); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +private: + SkGaussianEdgeShader(); // can't be instantiated +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkGradientShader.h b/gfx/skia/skia/include/effects/SkGradientShader.h index e474f38a4e2e..2fcce75c30ec 100644 --- a/gfx/skia/skia/include/effects/SkGradientShader.h +++ b/gfx/skia/skia/include/effects/SkGradientShader.h @@ -26,13 +26,9 @@ public: kInterpolateColorsInPremul_Flag = 1 << 0, }; - /** Returns a shader that generates a linear gradient between the two - specified points. + /** Returns a shader that generates a linear gradient between the two specified points.

- CreateLinear returns a shader with a reference count of 1. - The caller should decrement the shader's reference count when done with the shader. - It is an error for count to be < 2. - @param pts The start and end points for the gradient. + @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, @@ -52,11 +48,30 @@ public: return MakeLinear(pts, colors, pos, count, mode, 0, NULL); } + /** 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, NULL); + } + /** Returns a shader that generates a radial gradient given the center and radius.

- CreateRadial returns a shader with a reference count of 1. - The caller should decrement the shader's reference count when done with the shader. - It is an error for colorCount to be < 2, or for radius to be <= 0. @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 @@ -78,6 +93,29 @@ public: return MakeRadial(center, radius, colors, pos, count, mode, 0, NULL); } + /** 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, NULL); + } + /** * Returns a shader that generates a conical gradient given two circles, or * returns NULL if the inputs are invalid. The gradient interprets the @@ -97,11 +135,29 @@ public: 0, NULL); } + /** + * 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, NULL); + } + /** Returns a shader that generates a sweep gradient given a center.

- CreateSweep returns a shader with a reference count of 1. - The caller should decrement the shader's reference count when done with the shader. - It is an error for colorCount to be < 2. @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. @@ -120,6 +176,28 @@ public: return MakeSweep(cx, cy, colors, pos, count, 0, NULL); } + /** 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. + @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 + */ + 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); + 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, NULL); + } + #ifdef SK_SUPPORT_LEGACY_CREATESHADER_PTR static SkShader* CreateLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, diff --git a/gfx/skia/skia/include/effects/SkImageSource.h b/gfx/skia/skia/include/effects/SkImageSource.h index 0b4fecd776e3..4ceff95668ee 100644 --- a/gfx/skia/skia/include/effects/SkImageSource.h +++ b/gfx/skia/skia/include/effects/SkImageSource.h @@ -13,25 +13,11 @@ class SK_API SkImageSource : public SkImageFilter { public: - static sk_sp Make(sk_sp image) { - if (!image) { - return nullptr; - } - - return sk_sp(new SkImageSource(std::move(image))); - } + static sk_sp Make(sk_sp image); static sk_sp Make(sk_sp image, const SkRect& srcRect, const SkRect& dstRect, - SkFilterQuality filterQuality) { - if (!image) { - return nullptr; - } - - return sk_sp(new SkImageSource(std::move(image), - srcRect, dstRect, - filterQuality)); - } + SkFilterQuality filterQuality); SkRect computeFastBounds(const SkRect& src) const override; diff --git a/gfx/skia/skia/include/effects/SkLightingImageFilter.h b/gfx/skia/skia/include/effects/SkLightingImageFilter.h index fb356c52e434..4d4785da2eb6 100644 --- a/gfx/skia/skia/include/effects/SkLightingImageFilter.h +++ b/gfx/skia/skia/include/effects/SkLightingImageFilter.h @@ -17,34 +17,77 @@ struct SkPoint3; class SK_API SkLightingImageFilter : public SkImageFilter { public: - static SkImageFilter* CreateDistantLitDiffuse(const SkPoint3& direction, + static sk_sp MakeDistantLitDiffuse(const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - static SkImageFilter* CreatePointLitDiffuse(const SkPoint3& location, + sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakePointLitDiffuse(const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar kd, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - static SkImageFilter* CreateSpotLitDiffuse(const SkPoint3& location, + 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, - SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - static SkImageFilter* CreateDistantLitSpecular(const SkPoint3& direction, + sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakeDistantLitSpecular(const SkPoint3& direction, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, - SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - static SkImageFilter* CreatePointLitSpecular(const SkPoint3& location, + SkScalar shininess, sk_sp input, const CropRect* cropRect = nullptr); + static sk_sp MakePointLitSpecular(const SkPoint3& location, SkColor lightColor, SkScalar surfaceScale, SkScalar ks, - SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - static SkImageFilter* CreateSpotLitSpecular(const SkPoint3& location, + 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, SkImageFilter* input = NULL, const CropRect* cropRect = NULL); - ~SkLightingImageFilter(); + SkScalar shininess, sk_sp input, const CropRect* cropRect = nullptr); + ~SkLightingImageFilter() override; SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() +#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR + static SkImageFilter* CreateDistantLitDiffuse(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakeDistantLitDiffuse(direction, lightColor, surfaceScale, kd, + sk_ref_sp(input), cropRect).release(); + } + static SkImageFilter* CreatePointLitDiffuse(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakePointLitDiffuse(location, lightColor, surfaceScale, kd, + sk_ref_sp(input), cropRect).release(); + } + static SkImageFilter* CreateSpotLitDiffuse(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar kd, + SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakeSpotLitDiffuse(location, target, specularExponent, cutoffAngle, + lightColor, surfaceScale, kd, + sk_ref_sp(input), cropRect).release(); + } + static SkImageFilter* CreateDistantLitSpecular(const SkPoint3& direction, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakeDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess, + sk_ref_sp(input), cropRect).release(); + } + static SkImageFilter* CreatePointLitSpecular(const SkPoint3& location, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakePointLitSpecular(location, lightColor, surfaceScale, ks, shininess, + sk_ref_sp(input), cropRect).release(); + } + static SkImageFilter* CreateSpotLitSpecular(const SkPoint3& location, + const SkPoint3& target, SkScalar specularExponent, SkScalar cutoffAngle, + SkColor lightColor, SkScalar surfaceScale, SkScalar ks, + SkScalar shininess, SkImageFilter* input = NULL, const CropRect* cropRect = NULL) { + return MakeSpotLitSpecular(location, target, specularExponent, cutoffAngle, + lightColor, surfaceScale, ks, shininess, + sk_ref_sp(input), cropRect).release(); + } +#endif + protected: - SkLightingImageFilter(SkImageFilterLight* light, + SkLightingImageFilter(sk_sp light, SkScalar surfaceScale, - SkImageFilter* input, + sk_sp input, const CropRect* cropRect); void flatten(SkWriteBuffer&) const override; const SkImageFilterLight* light() const { return fLight.get(); } @@ -52,9 +95,10 @@ protected: bool affectsTransparentBlack() const override { return true; } private: - typedef SkImageFilter INHERITED; - SkAutoTUnref fLight; + sk_sp fLight; SkScalar fSurfaceScale; + + typedef SkImageFilter INHERITED; }; #endif diff --git a/gfx/skia/skia/include/effects/SkLumaColorFilter.h b/gfx/skia/skia/include/effects/SkLumaColorFilter.h index 3a68607b1977..1ffaa733b2f3 100644 --- a/gfx/skia/skia/include/effects/SkLumaColorFilter.h +++ b/gfx/skia/skia/include/effects/SkLumaColorFilter.h @@ -9,6 +9,7 @@ #define SkLumaColorFilter_DEFINED #include "SkColorFilter.h" +#include "SkRefCnt.h" /** * Luminance-to-alpha color filter, as defined in @@ -32,7 +33,7 @@ public: void filterSpan(const SkPMColor src[], int count, SkPMColor[]) const override; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*) const override; #endif SK_TO_STRING_OVERRIDE() diff --git a/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h b/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h index 739f1eec7331..6e20297ff4a6 100644 --- a/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMagnifierImageFilter.h @@ -14,7 +14,9 @@ class SK_API SkMagnifierImageFilter : public SkImageFilter { public: - static sk_sp Make(const SkRect& src, SkScalar inset, sk_sp input); + static sk_sp Make(const SkRect& src, SkScalar inset, + sk_sp input, + const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMagnifierImageFilter) @@ -27,15 +29,14 @@ public: #endif protected: - SkMagnifierImageFilter(const SkRect& srcRect, SkScalar inset, sk_sp input); + SkMagnifierImageFilter(const SkRect& srcRect, + SkScalar inset, + sk_sp input, + const CropRect* cropRect); void flatten(SkWriteBuffer&) const override; - bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* offset) const override; -#if SK_SUPPORT_GPU - bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, - const SkIRect& bounds) const override; -#endif + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; private: SkRect fSrcRect; diff --git a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h index 092af08f0c84..9a45486d8896 100644 --- a/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMatrixConvolutionImageFilter.h @@ -13,6 +13,8 @@ #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 @@ -29,7 +31,7 @@ public: kMax_TileMode = kClampToBlack_TileMode }; - virtual ~SkMatrixConvolutionImageFilter(); + ~SkMatrixConvolutionImageFilter() override; /** Construct a matrix convolution image filter. @param kernelSize The kernel size in pixels, in each dimension (N by M). @@ -52,6 +54,20 @@ public: 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); + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter) + +#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR static SkImageFilter* Create(const SkISize& kernelSize, const SkScalar* kernel, SkScalar gain, @@ -60,10 +76,11 @@ public: TileMode tileMode, bool convolveAlpha, SkImageFilter* input = NULL, - const CropRect* cropRect = NULL); - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMatrixConvolutionImageFilter) + const CropRect* cropRect = NULL) { + return Make(kernelSize, kernel, gain, bias, kernelOffset, tileMode, convolveAlpha, + sk_ref_sp(input), cropRect).release(); + } +#endif protected: SkMatrixConvolutionImageFilter(const SkISize& kernelSize, @@ -73,20 +90,15 @@ protected: const SkIPoint& kernelOffset, TileMode tileMode, bool convolveAlpha, - SkImageFilter* input, + sk_sp input, const CropRect* cropRect); void flatten(SkWriteBuffer&) const override; - bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, - SkBitmap* result, SkIPoint* loc) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; bool affectsTransparentBlack() const override; -#if SK_SUPPORT_GPU - bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, - const SkIRect& bounds) const override; -#endif - private: SkISize fKernelSize; SkScalar* fKernel; @@ -95,7 +107,6 @@ private: SkIPoint fKernelOffset; TileMode fTileMode; bool fConvolveAlpha; - typedef SkImageFilter INHERITED; template void filterPixels(const SkBitmap& src, @@ -115,6 +126,8 @@ private: SkBitmap* result, const SkIRect& rect, const SkIRect& bounds) const; + + typedef SkImageFilter INHERITED; }; #endif diff --git a/gfx/skia/skia/include/effects/SkMergeImageFilter.h b/gfx/skia/skia/include/effects/SkMergeImageFilter.h index e85cc1f97fd4..20620d6d7e75 100644 --- a/gfx/skia/skia/include/effects/SkMergeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMergeImageFilter.h @@ -18,18 +18,11 @@ public: static sk_sp Make(sk_sp first, sk_sp second, SkXfermode::Mode mode = SkXfermode::kSrcOver_Mode, - const CropRect* cropRect = nullptr) { - sk_sp inputs[2] = { first, second }; - SkXfermode::Mode modes[2] = { mode, mode }; - return sk_sp(new SkMergeImageFilter(inputs, 2, modes, cropRect)); - } - + const CropRect* cropRect = nullptr); static sk_sp Make(sk_sp filters[], int count, const SkXfermode::Mode modes[] = nullptr, - const CropRect* cropRect = nullptr) { - return sk_sp(new SkMergeImageFilter(filters, count, modes, cropRect)); - } + const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMergeImageFilter) @@ -58,6 +51,7 @@ protected: void flatten(SkWriteBuffer&) const override; sk_sp onFilterImage(SkSpecialImage* source, const Context&, SkIPoint* offset) const override; + bool onCanHandleComplexCTM() const override { return true; } private: SkMergeImageFilter(sk_sp filters[], int count, const SkXfermode::Mode modes[], diff --git a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h index 27608ecd07f8..fbbbe207ab02 100644 --- a/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h +++ b/gfx/skia/skia/include/effects/SkMorphologyImageFilter.h @@ -57,14 +57,7 @@ class SK_API SkDilateImageFilter : public SkMorphologyImageFilter { public: static sk_sp Make(int radiusX, int radiusY, sk_sp input, - const CropRect* cropRect = nullptr) { - if (radiusX < 0 || radiusY < 0) { - return nullptr; - } - return sk_sp(new SkDilateImageFilter(radiusX, radiusY, - std::move(input), - cropRect)); - } + const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDilateImageFilter) @@ -96,14 +89,7 @@ class SK_API SkErodeImageFilter : public SkMorphologyImageFilter { public: static sk_sp Make(int radiusX, int radiusY, sk_sp input, - const CropRect* cropRect = nullptr) { - if (radiusX < 0 || radiusY < 0) { - return nullptr; - } - return sk_sp(new SkErodeImageFilter(radiusX, radiusY, - std::move(input), - cropRect)); - } + const CropRect* cropRect = nullptr); SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkErodeImageFilter) diff --git a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h index cf2ff96ada53..c1005ef78081 100644 --- a/gfx/skia/skia/include/effects/SkOffsetImageFilter.h +++ b/gfx/skia/skia/include/effects/SkOffsetImageFilter.h @@ -15,13 +15,7 @@ class SK_API SkOffsetImageFilter : public SkImageFilter { public: static sk_sp Make(SkScalar dx, SkScalar dy, sk_sp input, - const CropRect* cropRect = nullptr) { - if (!SkScalarIsFinite(dx) || !SkScalarIsFinite(dy)) { - return nullptr; - } - - return sk_sp(new SkOffsetImageFilter(dx, dy, std::move(input), cropRect)); - } + const CropRect* cropRect = nullptr); SkRect computeFastBounds(const SkRect& src) const override; diff --git a/gfx/skia/skia/include/effects/SkPaintImageFilter.h b/gfx/skia/skia/include/effects/SkPaintImageFilter.h index 35a76b80fbf4..8a59da6c664f 100644 --- a/gfx/skia/skia/include/effects/SkPaintImageFilter.h +++ b/gfx/skia/skia/include/effects/SkPaintImageFilter.h @@ -22,9 +22,7 @@ public: * not specified, the source primitive's bounds are used * instead. */ - static sk_sp Make(const SkPaint& paint, const CropRect* cropRect = nullptr) { - return sk_sp(new SkPaintImageFilter(paint, cropRect)); - } + static sk_sp Make(const SkPaint& paint, const CropRect* cropRect = nullptr); bool affectsTransparentBlack() const override; diff --git a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h index d652e5dcad2e..60dc53a6a2b1 100644 --- a/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h +++ b/gfx/skia/skia/include/effects/SkPerlinNoiseShader.h @@ -102,8 +102,7 @@ public: }; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext* context, const SkMatrix& viewM, - const SkMatrix*, SkFilterQuality) const override; + sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif SK_TO_STRING_OVERRIDE() diff --git a/gfx/skia/skia/include/effects/SkPictureImageFilter.h b/gfx/skia/skia/include/effects/SkPictureImageFilter.h index 59097ddf59e3..2ca1c5b4fde4 100644 --- a/gfx/skia/skia/include/effects/SkPictureImageFilter.h +++ b/gfx/skia/skia/include/effects/SkPictureImageFilter.h @@ -16,20 +16,13 @@ public: /** * Refs the passed-in picture. */ - static sk_sp Make(sk_sp picture) { - return sk_sp(new SkPictureImageFilter(std::move(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) { - return sk_sp(new SkPictureImageFilter(std::move(picture), - cropRect, - kDeviceSpace_PictureResolution, - kLow_SkFilterQuality)); - } + static sk_sp Make(sk_sp picture, const SkRect& cropRect); /** * Refs the passed-in picture. The picture is rasterized at a resolution that matches the @@ -40,12 +33,7 @@ public: */ static sk_sp MakeForLocalSpace(sk_sp picture, const SkRect& cropRect, - SkFilterQuality filterQuality) { - return sk_sp(new SkPictureImageFilter(std::move(picture), - cropRect, - kLocalSpace_PictureResolution, - filterQuality)); - } + SkFilterQuality filterQuality); #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR static SkImageFilter* Create(const SkPicture* picture) { @@ -79,17 +67,20 @@ protected: * @param SkReadBuffer Serialized picture data. */ void flatten(SkWriteBuffer&) const override; - bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&, SkBitmap* result, - SkIPoint* offset) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; private: explicit SkPictureImageFilter(sk_sp picture); SkPictureImageFilter(sk_sp picture, const SkRect& cropRect, PictureResolution, SkFilterQuality); - void drawPictureAtDeviceResolution(SkBaseDevice*, const SkIRect& deviceBounds, + void drawPictureAtDeviceResolution(SkCanvas* canvas, + const SkIRect& deviceBounds, const Context&) const; - void drawPictureAtLocalResolution(Proxy*, SkBaseDevice*, const SkIRect& deviceBounds, + void drawPictureAtLocalResolution(SkSpecialImage* source, + SkCanvas*, + const SkIRect& deviceBounds, const Context&) const; sk_sp fPicture; diff --git a/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h b/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h new file mode 100644 index 000000000000..087e7c25f63a --- /dev/null +++ b/gfx/skia/skia/include/effects/SkRRectsGaussianEdgeShader.h @@ -0,0 +1,37 @@ +/* + * 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 SkRRectsGaussianEdgeShader_DEFINED +#define SkRRectsGaussianEdgeShader_DEFINED + +#include "SkShader.h" + +class SkRRect; + +class SK_API SkRRectsGaussianEdgeShader { +public: + /** Returns a shader that applies a Gaussian blur depending on distance to the edge + * of the intersection of two round rects. + * Currently this is only useable with round rects that have the same radii at + * all the corners and for which the x & y radii are equal. + * Raster will draw nothing. + * + * The coverage geometry that should be drawn should be no larger than the intersection + * of the bounding boxes of the two round rects. Ambitious users can omit the center + * area of the coverage geometry if it is known to be occluded. + */ + static sk_sp Make(const SkRRect& first, + const SkRRect& second, + SkScalar radius, SkScalar unused = 0.0f); + + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() + +private: + SkRRectsGaussianEdgeShader(); // can't be instantiated +}; + +#endif diff --git a/gfx/skia/skia/include/effects/SkTestImageFilters.h b/gfx/skia/skia/include/effects/SkTestImageFilters.h deleted file mode 100644 index 0f89759c1c8d..000000000000 --- a/gfx/skia/skia/include/effects/SkTestImageFilters.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 _SkTestImageFilters_h -#define _SkTestImageFilters_h - -#include "SkImageFilter.h" -#include "SkPoint.h" - -// Fun mode that scales down (only) and then scales back up to look pixelated -class SK_API SkDownSampleImageFilter : public SkImageFilter { -public: - static sk_sp Make(SkScalar scale, sk_sp input) { - if (!SkScalarIsFinite(scale)) { - return nullptr; - } - // we don't support scale in this range - if (scale > SK_Scalar1 || scale <= 0) { - return nullptr; - } - return sk_sp(new SkDownSampleImageFilter(scale, std::move(input))); - } - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDownSampleImageFilter) - -#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR - static SkImageFilter* Create(SkScalar scale, SkImageFilter* input = nullptr) { - return Make(scale, sk_ref_sp(input)).release(); - } -#endif - -protected: - void flatten(SkWriteBuffer&) const override; - - sk_sp onFilterImage(SkSpecialImage* source, const Context&, - SkIPoint* offset) const override; - -private: - SkDownSampleImageFilter(SkScalar scale, sk_sp input) - : INHERITED(&input, 1, nullptr), fScale(scale) {} - - SkScalar fScale; - - typedef SkImageFilter INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/effects/SkTileImageFilter.h b/gfx/skia/skia/include/effects/SkTileImageFilter.h index ad334a3cc1e7..ae951e318b7b 100644 --- a/gfx/skia/skia/include/effects/SkTileImageFilter.h +++ b/gfx/skia/skia/include/effects/SkTileImageFilter.h @@ -11,18 +11,16 @@ #include "SkImageFilter.h" class SK_API SkTileImageFilter : public SkImageFilter { - typedef SkImageFilter INHERITED; - 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 SkImageFilter* Create(const SkRect& src, const SkRect& dst, SkImageFilter* input); + static sk_sp Make(const SkRect& src, + const SkRect& dst, + sk_sp input); - bool onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, - SkBitmap* dst, SkIPoint* offset) const override; SkIRect onFilterBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; SkIRect onFilterNodeBounds(const SkIRect&, const SkMatrix&, MapDirection) const override; SkRect computeFastBounds(const SkRect& src) const override; @@ -30,15 +28,26 @@ public: SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTileImageFilter) +#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR + static SkImageFilter* Create(const SkRect& src, const SkRect& dst, SkImageFilter* input) { + return Make(src, dst, sk_ref_sp(input)).release(); + } +#endif + protected: void flatten(SkWriteBuffer& buffer) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + private: - SkTileImageFilter(const SkRect& srcRect, const SkRect& dstRect, SkImageFilter* input) - : INHERITED(1, &input, NULL), fSrcRect(srcRect), fDstRect(dstRect) {} + 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/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h index 634422747a9b..fa9c857a7ea3 100644 --- a/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h +++ b/gfx/skia/skia/include/effects/SkXfermodeImageFilter.h @@ -8,29 +8,51 @@ #ifndef SkXfermodeImageFilter_DEFINED #define SkXfermodeImageFilter_DEFINED +#include "SkBlendMode.h" #include "SkImageFilter.h" -class SkBitmap; class SkXfermode; -class SK_API SkXfermodeImageFilter : public SkImageFilter { - /** - * This filter takes an xfermode, and uses it to composite the foreground - * over the background. If foreground or background is NULL, the input - * bitmap (src) is used instead. - */ - +/** + * This filter takes an xfermode, 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 sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background, + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); + static sk_sp MakeArithmetic(float k1, float k2, float k3, float k4, + bool enforcePMColor, + sk_sp background) { + return MakeArithmetic(k1, k2, k3, k4, enforcePMColor, std::move(background), + nullptr, nullptr); + } + +#ifdef SK_SUPPORT_LEGACY_XFERMODE_OBJECT static sk_sp Make(sk_sp mode, sk_sp background, - sk_sp foreground, const CropRect* cropRect); + sk_sp foreground, + const SkImageFilter::CropRect* cropRect); static sk_sp Make(sk_sp mode, sk_sp background) { return Make(std::move(mode), std::move(background), nullptr, nullptr); } +#endif + #ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR static SkImageFilter* Create(SkXfermode* mode, SkImageFilter* background, SkImageFilter* foreground = NULL, - const CropRect* cropRect = NULL) { + const SkImageFilter::CropRect* cropRect = NULL) { return Make(sk_ref_sp(mode), sk_ref_sp(background), sk_ref_sp(foreground), @@ -39,7 +61,8 @@ public: #endif #ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR static sk_sp Make(sk_sp mode, SkImageFilter* background, - SkImageFilter* foreground, const CropRect* cropRect) { + SkImageFilter* foreground, + const SkImageFilter::CropRect* cropRect) { return Make(std::move(mode), sk_ref_sp(background), sk_ref_sp(foreground), @@ -50,28 +73,10 @@ public: } #endif - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkXfermodeImageFilter) - - bool onFilterImageDeprecated(Proxy* proxy, - const SkBitmap& src, - const Context& ctx, - SkBitmap* dst, - SkIPoint* offset) const override; -#if SK_SUPPORT_GPU - bool canFilterImageGPU() const override; - bool filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, - SkBitmap* result, SkIPoint* offset) const override; -#endif - -protected: - SkXfermodeImageFilter(sk_sp mode, sk_sp inputs[2], - const CropRect* cropRect); - void flatten(SkWriteBuffer&) const override; + SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP(); private: - sk_sp fMode; - typedef SkImageFilter INHERITED; + SkXfermodeImageFilter(); // can't instantiate }; #endif diff --git a/gfx/skia/skia/src/gpu/GrBuffer.h b/gfx/skia/skia/include/gpu/GrBuffer.h similarity index 59% rename from gfx/skia/skia/src/gpu/GrBuffer.h rename to gfx/skia/skia/include/gpu/GrBuffer.h index 7e04577543f2..b2201a140fa3 100644 --- a/gfx/skia/skia/src/gpu/GrBuffer.h +++ b/gfx/skia/skia/include/gpu/GrBuffer.h @@ -15,30 +15,26 @@ class GrGpu; class GrBuffer : public GrGpuResource { public: /** - * Computes a scratch key for a buffer with a "dynamic" access pattern. (Buffers with "static" - * and "stream" access patterns are disqualified by nature from being cached and reused.) + * Creates a client-side buffer. */ - static void ComputeScratchKeyForDynamicBuffer(size_t size, GrBufferType intendedType, - GrScratchKey* key) { - static const GrScratchKey::ResourceType kType = GrScratchKey::GenerateResourceType(); - GrScratchKey::Builder builder(key, kType, 1 + (sizeof(size_t) + 3) / 4); - // TODO: There's not always reason to cache a buffer by type. In some (all?) APIs it's just - // a chunk of memory we can use/reuse for any type of data. We really only need to - // differentiate between the "read" types (e.g. kGpuToCpu_BufferType) and "draw" types. - builder[0] = intendedType; - builder[1] = (uint32_t)size; - if (sizeof(size_t) > 4) { - builder[2] = (uint32_t)((uint64_t)size >> 32); - } - } + static SK_WARN_UNUSED_RESULT GrBuffer* CreateCPUBacked(GrGpu*, size_t sizeInBytes, GrBufferType, + const void* data = nullptr); + + /** + * Computes a scratch key for a GPU-side buffer with a "dynamic" access pattern. (Buffers with + * "static" and "stream" patterns are disqualified by nature from being cached and reused.) + */ + static void ComputeScratchKeyForDynamicVBO(size_t size, GrBufferType, GrScratchKey*); GrAccessPattern accessPattern() const { return fAccessPattern; } + size_t sizeInBytes() const { return fSizeInBytes; } /** * Returns true if the buffer is a wrapper around a CPU array. If true it * indicates that map will always succeed and will be free. */ - bool isCPUBacked() const { return fCPUBacked; } + bool isCPUBacked() const { return SkToBool(fCPUData); } + size_t baseOffset() const { return reinterpret_cast(fCPUData); } /** * Maps the buffer to be written by the CPU. @@ -103,37 +99,36 @@ public: */ bool updateData(const void* src, size_t srcSizeInBytes) { SkASSERT(!this->isMapped()); - SkASSERT(srcSizeInBytes <= fGpuMemorySize); + SkASSERT(srcSizeInBytes <= fSizeInBytes); return this->onUpdateData(src, srcSizeInBytes); } -protected: - GrBuffer(GrGpu* gpu, size_t gpuMemorySize, GrBufferType intendedType, - GrAccessPattern accessPattern, bool cpuBacked) - : INHERITED(gpu, kCached_LifeCycle), - fMapPtr(nullptr), - fGpuMemorySize(gpuMemorySize), // TODO: Zero for cpu backed buffers? - fAccessPattern(accessPattern), - fCPUBacked(cpuBacked) { - if (!fCPUBacked && SkIsPow2(fGpuMemorySize) && kDynamic_GrAccessPattern == fAccessPattern) { - GrScratchKey key; - ComputeScratchKeyForDynamicBuffer(fGpuMemorySize, intendedType, &key); - this->setScratchKey(key); - } + ~GrBuffer() override { + sk_free(fCPUData); } +protected: + GrBuffer(GrGpu*, size_t sizeInBytes, GrBufferType, GrAccessPattern); + void* fMapPtr; private: - virtual size_t onGpuMemorySize() const { return fGpuMemorySize; } + /** + * Internal constructor to make a CPU-backed buffer. + */ + GrBuffer(GrGpu*, size_t sizeInBytes, GrBufferType, void* cpuData); - virtual void onMap() = 0; - virtual void onUnmap() = 0; - virtual bool onUpdateData(const void* src, size_t srcSizeInBytes) = 0; + virtual void onMap() { SkASSERT(this->isCPUBacked()); fMapPtr = fCPUData; } + virtual void onUnmap() { SkASSERT(this->isCPUBacked()); } + virtual bool onUpdateData(const void* src, size_t srcSizeInBytes); - size_t fGpuMemorySize; + size_t onGpuMemorySize() const override { return fSizeInBytes; } // TODO: zero for cpu backed? + void computeScratchKey(GrScratchKey* key) const override; + + size_t fSizeInBytes; GrAccessPattern fAccessPattern; - bool fCPUBacked; + void* fCPUData; + GrBufferType fIntendedType; typedef GrGpuResource INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrBufferAccess.h b/gfx/skia/skia/include/gpu/GrBufferAccess.h new file mode 100644 index 000000000000..a5d8f0a684b6 --- /dev/null +++ b/gfx/skia/skia/include/gpu/GrBufferAccess.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 GrBufferAccess_DEFINED +#define GrBufferAccess_DEFINED + +#include "GrBuffer.h" +#include "GrGpuResourceRef.h" + +/** + * Used to represent a texel buffer that will be read in a GrProcessor. It holds a GrBuffer along + * with an associated offset and texel config. + */ +class GrBufferAccess : public SkNoncopyable { +public: + /** + * Must be initialized before adding to a GrProcessor's buffer access list. + */ + void reset(GrPixelConfig texelConfig, GrBuffer* buffer, + GrShaderFlags visibility = kFragment_GrShaderFlag) { + fTexelConfig = texelConfig; + fBuffer.set(SkRef(buffer), kRead_GrIOType); + fVisibility = visibility; + } + + bool operator==(const GrBufferAccess& that) const { + return fTexelConfig == that.fTexelConfig && + this->buffer() == that.buffer() && + fVisibility == that.fVisibility; + } + + bool operator!=(const GrBufferAccess& that) const { return !(*this == that); } + + GrPixelConfig texelConfig() const { return fTexelConfig; } + GrBuffer* buffer() const { return fBuffer.get(); } + GrShaderFlags visibility() const { return fVisibility; } + + /** + * For internal use by GrProcessor. + */ + const GrGpuResourceRef* getProgramBuffer() const { return &fBuffer;} + +private: + GrPixelConfig fTexelConfig; + GrTGpuResourceRef fBuffer; + GrShaderFlags fVisibility; + + typedef SkNoncopyable INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/gpu/GrCaps.h b/gfx/skia/skia/include/gpu/GrCaps.h index d698a4142c2b..a97be72c3ff5 100644 --- a/gfx/skia/skia/include/gpu/GrCaps.h +++ b/gfx/skia/skia/include/gpu/GrCaps.h @@ -63,6 +63,7 @@ public: bool dstReadInShaderSupport() const { return fDstReadInShaderSupport; } bool dualSourceBlendingSupport() const { return fDualSourceBlendingSupport; } bool integerSupport() const { return fIntegerSupport; } + bool texelBufferSupport() const { return fTexelBufferSupport; } /** * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a @@ -73,7 +74,7 @@ public: const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType, GrSLPrecision precision) const { return fFloatPrecisions[shaderType][precision]; - }; + } /** * Is there any difference between the float shader variable precision types? If this is true @@ -83,7 +84,7 @@ public: bool floatPrecisionVaries() const { return fShaderPrecisionVaries; } /** - * PLS storage size in bytes (0 when not supported). The PLS spec defines a minimum size of 16 + * PLS storage size in bytes (0 when not supported). The PLS spec defines a minimum size of 16 * bytes whenever PLS is supported. */ int pixelLocalStorageSize() const { return fPixelLocalStorageSize; } @@ -92,7 +93,7 @@ public: * True if this context supports the necessary extensions and features to enable the PLS path * renderer. */ - bool plsPathRenderingSupport() const { + bool plsPathRenderingSupport() const { #if GR_ENABLE_PLS_PATH_RENDERING return fPLSPathRenderingSupport; #else @@ -111,6 +112,7 @@ protected: bool fDstReadInShaderSupport : 1; bool fDualSourceBlendingSupport : 1; bool fIntegerSupport : 1; + bool fTexelBufferSupport : 1; bool fShaderPrecisionVaries; PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][kGrSLPrecisionCount]; @@ -118,7 +120,7 @@ protected: bool fPLSPathRenderingSupport; private: - virtual void onApplyOptionsOverrides(const GrContextOptions&) {}; + virtual void onApplyOptionsOverrides(const GrContextOptions&) {} typedef SkRefCnt INHERITED; }; @@ -142,9 +144,12 @@ public: * Skia convention is that a device only has sRGB support if it supports sRGB formats for both * textures and framebuffers. In addition: * Decoding to linear of an sRGB texture can be disabled. - * Encoding and gamma-correct blending to an sRGB framebuffer can be disabled. */ bool srgbSupport() const { return fSRGBSupport; } + /** + * Is there support for enabling/disabling sRGB writes for sRGB-capable color buffers? + */ + bool srgbWriteControl() const { return fSRGBWriteControl; } bool twoSidedStencilSupport() const { return fTwoSidedStencilSupport; } bool stencilWrapOpsSupport() const { return fStencilWrapOpsSupport; } bool discardRenderTargetSupport() const { return fDiscardRenderTargetSupport; } @@ -153,7 +158,9 @@ public: bool oversizedStencilSupport() const { return fOversizedStencilSupport; } bool textureBarrierSupport() const { return fTextureBarrierSupport; } bool sampleLocationsSupport() const { return fSampleLocationsSupport; } + bool multisampleDisableSupport() const { return fMultisampleDisableSupport; } bool usesMixedSamples() const { return fUsesMixedSamples; } + bool preferClientSideDynamicBuffers() const { return fPreferClientSideDynamicBuffers; } bool useDrawInsteadOfClear() const { return fUseDrawInsteadOfClear; } bool useDrawInsteadOfPartialRenderTargetWrite() const { @@ -166,6 +173,21 @@ public: bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; } + /** + * Indicates the level of support for gr_instanced::* functionality. A higher level includes + * all functionality from the levels below it. + */ + enum class InstancedSupport { + kNone, + kBasic, + kMultisampled, + kMixedSampled + }; + + InstancedSupport instancedSupport() const { return fInstancedSupport; } + + bool avoidInstancedDrawsToFPTargets() const { return fAvoidInstancedDrawsToFPTargets; } + /** * Indicates the capabilities of the fixed function blend unit. */ @@ -242,6 +264,7 @@ public: } } + int maxWindowRectangles() const { return fMaxWindowRectangles; } virtual bool isConfigTexturable(GrPixelConfig config) const = 0; virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0; @@ -250,27 +273,21 @@ public: bool immediateFlush() const { return fImmediateFlush; } - bool drawPathMasksToCompressedTexturesSupport() const { - return fDrawPathMasksToCompressedTextureSupport; - } - size_t bufferMapThreshold() const { SkASSERT(fBufferMapThreshold >= 0); return fBufferMapThreshold; } - bool supportsInstancedDraws() const { - return fSupportsInstancedDraws; - } - bool fullClearIsFree() const { return fFullClearIsFree; } - /** True in environments that will issue errors if memory uploaded to buffers + /** True in environments that will issue errors if memory uploaded to buffers is not initialized (even if not read by draw calls). */ bool mustClearUploadedBufferData() const { return fMustClearUploadedBufferData; } bool sampleShadingSupport() const { return fSampleShadingSupport; } + bool fenceSyncSupport() const { return fFenceSyncSupport; } + protected: /** Subclasses must call this at the end of their constructors in order to apply caps overrides requested by the client. Note that overrides will only reduce the caps never @@ -282,6 +299,7 @@ protected: bool fNPOTTextureTileSupport : 1; bool fMipMapSupport : 1; bool fSRGBSupport : 1; + bool fSRGBWriteControl : 1; bool fTwoSidedStencilSupport : 1; bool fStencilWrapOpsSupport : 1; bool fDiscardRenderTargetSupport : 1; @@ -292,8 +310,9 @@ protected: bool fOversizedStencilSupport : 1; bool fTextureBarrierSupport : 1; bool fSampleLocationsSupport : 1; + bool fMultisampleDisableSupport : 1; bool fUsesMixedSamples : 1; - bool fSupportsInstancedDraws : 1; + bool fPreferClientSideDynamicBuffers : 1; bool fFullClearIsFree : 1; bool fMustClearUploadedBufferData : 1; @@ -301,11 +320,16 @@ protected: bool fUseDrawInsteadOfClear : 1; bool fUseDrawInsteadOfPartialRenderTargetWrite : 1; bool fUseDrawInsteadOfAllRenderTargetWrites : 1; + bool fAvoidInstancedDrawsToFPTargets : 1; // ANGLE workaround bool fPreferVRAMUseOverFlushes : 1; bool fSampleShadingSupport : 1; + // TODO: this may need to be an enum to support different fence types + bool fFenceSyncSupport : 1; + + InstancedSupport fInstancedSupport; BlendEquationSupport fBlendEquationSupport; uint32_t fAdvBlendEqBlacklist; @@ -321,13 +345,13 @@ protected: int fMaxColorSampleCount; int fMaxStencilSampleCount; int fMaxRasterSamples; + int fMaxWindowRectangles; private: - virtual void onApplyOptionsOverrides(const GrContextOptions&) {}; + virtual void onApplyOptionsOverrides(const GrContextOptions&) {} bool fSuppressPrints : 1; bool fImmediateFlush: 1; - bool fDrawPathMasksToCompressedTextureSupport : 1; typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrClip.h b/gfx/skia/skia/include/gpu/GrClip.h index fd8b970e39dc..96c6291ef751 100644 --- a/gfx/skia/skia/include/gpu/GrClip.h +++ b/gfx/skia/skia/include/gpu/GrClip.h @@ -8,185 +8,139 @@ #ifndef GrClip_DEFINED #define GrClip_DEFINED -#include "SkClipStack.h" +#include "SkRect.h" +#include "SkRRect.h" -struct SkIRect; +class GrAppliedClip; +class GrContext; +class GrDrawContext; /** - * GrClip encapsulates the information required to construct the clip - * masks. 'A GrClip is either wide open, just an IRect, just a Rect, or a full clipstack. - * If the clip is a clipstack than the origin is used to translate the stack with - * respect to device coordinates. This allows us to use a clip stack that is - * specified for a root device with a layer device that is restricted to a subset - * of the original canvas. For other clip types the origin will always be (0,0). - * - * NOTE: GrClip *must* point to a const clipstack + * GrClip is an abstract base class for applying a clip. It constructs a clip mask if necessary, and + * fills out a GrAppliedClip instructing the caller on how to set up the draw state. */ -class GrClip : SkNoncopyable { +class GrClip { public: - GrClip() : fClipType(kWideOpen_ClipType) { - fOrigin.setZero(); + virtual bool quickContains(const SkRect&) const = 0; + virtual bool quickContains(const SkRRect& rrect) const { + return this->quickContains(rrect.getBounds()); + } + virtual void getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects = nullptr) const = 0; + virtual bool apply(GrContext*, GrDrawContext*, bool useHWAA, bool hasUserStencilSettings, + GrAppliedClip* out) const = 0; + + virtual ~GrClip() {} + + /** + * This method quickly and conservatively determines whether the entire clip is equivalent to + * intersection with a rrect. This will only return true if the rrect does not fully contain + * the render target bounds. Moreover, the returned rrect need not be contained by the render + * target bounds. We assume all draws will be implicitly clipped by the render target bounds. + * + * @param rtBounds The bounds of the render target that the clip will be applied to. + * @param rrect If return is true rrect will contain the rrect equivalent to the clip within + * rtBounds. + * @param aa If return is true aa will indicate whether the rrect clip is antialiased. + * @return true if the clip is equivalent to a single rrect, false otherwise. + * + */ + virtual bool isRRect(const SkRect& rtBounds, SkRRect* rrect, bool* aa) const = 0; + + /** + * This is the maximum distance that a draw may extend beyond a clip's boundary and still count + * count as "on the other side". We leave some slack because floating point rounding error is + * likely to blame. The rationale for 1e-3 is that in the coverage case (and barring unexpected + * rounding), as long as coverage stays within 0.5 * 1/256 of its intended value it shouldn't + * have any effect on the final pixel values. + */ + constexpr static SkScalar kBoundsTolerance = 1e-3f; + + /** + * Returns true if the given query bounds count as entirely inside the clip. + * + * @param innerClipBounds device-space rect contained by the clip (SkRect or SkIRect). + * @param queryBounds device-space bounds of the query region. + */ + template constexpr static bool IsInsideClip(const TRect& innerClipBounds, + const SkRect& queryBounds) { + return innerClipBounds.fRight - innerClipBounds.fLeft > kBoundsTolerance && + innerClipBounds.fBottom - innerClipBounds.fTop > kBoundsTolerance && + innerClipBounds.fLeft < queryBounds.fLeft + kBoundsTolerance && + innerClipBounds.fTop < queryBounds.fTop + kBoundsTolerance && + innerClipBounds.fRight > queryBounds.fRight - kBoundsTolerance && + innerClipBounds.fBottom > queryBounds.fBottom - kBoundsTolerance; } - GrClip(const SkIRect& rect) : fClipType(kIRect_ClipType) { - fOrigin.setZero(); - fClip.fIRect = rect; + /** + * Returns true if the given query bounds count as entirely outside the clip. + * + * @param outerClipBounds device-space rect that contains the clip (SkRect or SkIRect). + * @param queryBounds device-space bounds of the query region. + */ + template constexpr static bool IsOutsideClip(const TRect& outerClipBounds, + const SkRect& queryBounds) { + return outerClipBounds.fRight - outerClipBounds.fLeft <= kBoundsTolerance || + outerClipBounds.fBottom - outerClipBounds.fTop <= kBoundsTolerance || + outerClipBounds.fLeft >= queryBounds.fRight - kBoundsTolerance || + outerClipBounds.fTop >= queryBounds.fBottom - kBoundsTolerance || + outerClipBounds.fRight <= queryBounds.fLeft + kBoundsTolerance || + outerClipBounds.fBottom <= queryBounds.fTop + kBoundsTolerance; } - GrClip(const SkRect& rect) : fClipType(kIRect_ClipType) { - fOrigin.setZero(); - fClip.fIRect.fLeft = SkScalarRoundToInt(rect.fLeft); - fClip.fIRect.fTop = SkScalarRoundToInt(rect.fTop); - fClip.fIRect.fRight = SkScalarRoundToInt(rect.fRight); - fClip.fIRect.fBottom = SkScalarRoundToInt(rect.fBottom); + /** + * Returns the minimal integer rect that counts as containing a given set of bounds. + */ + static SkIRect GetPixelIBounds(const SkRect& bounds) { + return SkIRect::MakeLTRB(SkScalarFloorToInt(bounds.fLeft + kBoundsTolerance), + SkScalarFloorToInt(bounds.fTop + kBoundsTolerance), + SkScalarCeilToInt(bounds.fRight - kBoundsTolerance), + SkScalarCeilToInt(bounds.fBottom - kBoundsTolerance)); } - ~GrClip() { this->reset(); } - - const GrClip& operator=(const GrClip& other) { - this->reset(); - fClipType = other.fClipType; - switch (other.fClipType) { - case kWideOpen_ClipType: - fOrigin.setZero(); - break; - case kClipStack_ClipType: - fClip.fStack = SkRef(other.clipStack()); - fOrigin = other.origin(); - break; - case kIRect_ClipType: - fClip.fIRect = other.irect(); - fOrigin.setZero(); - break; - } - return *this; + /** + * Returns the minimal pixel-aligned rect that counts as containing a given set of bounds. + */ + static SkRect GetPixelBounds(const SkRect& bounds) { + return SkRect::MakeLTRB(SkScalarFloorToScalar(bounds.fLeft + kBoundsTolerance), + SkScalarFloorToScalar(bounds.fTop + kBoundsTolerance), + SkScalarCeilToScalar(bounds.fRight - kBoundsTolerance), + SkScalarCeilToScalar(bounds.fBottom - kBoundsTolerance)); } - bool operator==(const GrClip& other) const { - if (this->clipType() != other.clipType()) { - return false; - } - - switch (fClipType) { - case kWideOpen_ClipType: - return true; - case kClipStack_ClipType: - if (this->origin() != other.origin()) { - return false; - } - - if (this->clipStack() && other.clipStack()) { - return *this->clipStack() == *other.clipStack(); - } else { - return this->clipStack() == other.clipStack(); - } - break; - case kIRect_ClipType: - return this->irect() == other.irect(); - break; - } - SkFAIL("This should not occur\n"); - return false; + /** + * Returns true if the given rect counts as aligned with pixel boundaries. + */ + static bool IsPixelAligned(const SkRect& rect) { + return SkScalarAbs(SkScalarRoundToScalar(rect.fLeft) - rect.fLeft) <= kBoundsTolerance && + SkScalarAbs(SkScalarRoundToScalar(rect.fTop) - rect.fTop) <= kBoundsTolerance && + SkScalarAbs(SkScalarRoundToScalar(rect.fRight) - rect.fRight) <= kBoundsTolerance && + SkScalarAbs(SkScalarRoundToScalar(rect.fBottom) - rect.fBottom) <= kBoundsTolerance; } +}; - bool operator!=(const GrClip& other) const { - return !(*this == other); - } - - const SkClipStack* clipStack() const { - SkASSERT(kClipStack_ClipType == fClipType); - return fClip.fStack; - } - - void setClipStack(const SkClipStack* clipStack, const SkIPoint* origin = NULL) { - this->reset(); - if (clipStack->isWideOpen()) { - fClipType = kWideOpen_ClipType; - fOrigin.setZero(); - } else { - fClipType = kClipStack_ClipType; - fClip.fStack = SkRef(clipStack); - if (origin) { - fOrigin = *origin; - } else { - fOrigin.setZero(); - } - } - } - - void setIRect(const SkIRect& irect) { - this->reset(); - fClipType = kIRect_ClipType; - fOrigin.setZero(); - fClip.fIRect = irect; - } - - const SkIRect& irect() const { - SkASSERT(kIRect_ClipType == fClipType); - return fClip.fIRect; - } - - void reset() { - if (kClipStack_ClipType == fClipType) { - fClip.fStack->unref(); - fClip.fStack = NULL; - } - fClipType = kWideOpen_ClipType; - fOrigin.setZero(); - } - - // We support this for all cliptypes to simplify the logic a bit in clip mask manager. - // non clipstack clip types MUST have a (0,0) origin - const SkIPoint& origin() const { - SkASSERT(fClipType == kClipStack_ClipType || (fOrigin.fX == 0 && fOrigin.fY == 0)); - return fOrigin; - } - - bool isWideOpen(const SkRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); - } - - bool isWideOpen(const SkIRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); - } - - bool isWideOpen() const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->isWideOpen()); - } - - bool quickContains(const SkRect& rect) const { - return (kWideOpen_ClipType == fClipType) || - (kClipStack_ClipType == fClipType && this->clipStack()->quickContains(rect)) || - (kIRect_ClipType == fClipType && this->irect().contains(rect)); - } - - void getConservativeBounds(int width, int height, - SkIRect* devResult, - bool* isIntersectionOfRects = NULL) const; - - static const GrClip& WideOpen(); - - enum ClipType { - kClipStack_ClipType, - kWideOpen_ClipType, - kIRect_ClipType, - }; - - ClipType clipType() const { return fClipType; } - +/** + * Specialized implementation for no clip. + */ +class GrNoClip final : public GrClip { private: - union Clip { - const SkClipStack* fStack; - SkIRect fIRect; - } fClip; - - SkIPoint fOrigin; - ClipType fClipType; + bool quickContains(const SkRect&) const final { + return true; + } + bool quickContains(const SkRRect&) const final { + return true; + } + void getConservativeBounds(int width, int height, SkIRect* devResult, + bool* isIntersectionOfRects) const final { + devResult->setXYWH(0, 0, width, height); + if (isIntersectionOfRects) { + *isIntersectionOfRects = true; + } + } + bool apply(GrContext*, GrDrawContext*, bool, bool, GrAppliedClip*) const final { + return true; + } + bool isRRect(const SkRect&, SkRRect*, bool*) const override { return false; } }; #endif diff --git a/gfx/skia/skia/include/gpu/GrColor.h b/gfx/skia/skia/include/gpu/GrColor.h index 77f1a6cb0841..f52671732a8e 100644 --- a/gfx/skia/skia/include/gpu/GrColor.h +++ b/gfx/skia/skia/include/gpu/GrColor.h @@ -169,6 +169,65 @@ static inline GrColor GrUnpremulColor(GrColor color) { return GrColorPackRGBA(r, g, b, a); } + +/** +* Similarly, GrColor4f is 4 floats for R, G, B, A, in that order. And like GrColor, whether +* the color is premultiplied or not depends on the context. +*/ +struct GrColor4f { + float fRGBA[4]; + + GrColor4f() {} + GrColor4f(float r, float g, float b, float a) { + fRGBA[0] = r; + fRGBA[1] = g; + fRGBA[2] = b; + fRGBA[3] = a; + } + + static GrColor4f FromGrColor(GrColor color) { + GrColor4f result; + GrColorToRGBAFloat(color, result.fRGBA); + return result; + } + + static GrColor4f FromSkColor4f(const SkColor4f& color) { + return GrColor4f(color.fR, color.fG, color.fB, color.fA); + } + + bool operator==(const GrColor4f& other) const { + return + fRGBA[0] == other.fRGBA[0] && + fRGBA[1] == other.fRGBA[1] && + fRGBA[2] == other.fRGBA[2] && + fRGBA[3] == other.fRGBA[3]; + } + bool operator!=(const GrColor4f& other) const { + return !(*this == other); + } + + GrColor toGrColor() const { + return GrColorPackRGBA( + SkTPin(static_cast(fRGBA[0] * 255.0f + 0.5f), 0, 255), + SkTPin(static_cast(fRGBA[1] * 255.0f + 0.5f), 0, 255), + SkTPin(static_cast(fRGBA[2] * 255.0f + 0.5f), 0, 255), + SkTPin(static_cast(fRGBA[3] * 255.0f + 0.5f), 0, 255)); + } + + SkColor4f toSkColor4f() const { + return SkColor4f { fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3] }; + } + + GrColor4f opaque() const { + return GrColor4f(fRGBA[0], fRGBA[1], fRGBA[2], 1.0f); + } + + GrColor4f premul() const { + float a = fRGBA[3]; + return GrColor4f(fRGBA[0] * a, fRGBA[1] * a, fRGBA[2] * a, a); + } +}; + /** * Flags used for bitfields of color components. They are defined so that the bit order reflects the * GrColor shift order. diff --git a/gfx/skia/skia/include/gpu/GrColorSpaceXform.h b/gfx/skia/skia/include/gpu/GrColorSpaceXform.h new file mode 100644 index 000000000000..7c88c628507c --- /dev/null +++ b/gfx/skia/skia/include/gpu/GrColorSpaceXform.h @@ -0,0 +1,45 @@ +/* + * 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 GrColorSpaceXform_DEFINED +#define GrColorSpaceXform_DEFINED + +#include "GrColor.h" +#include "SkMatrix44.h" +#include "SkRefCnt.h" + +class SkColorSpace; + + /** + * Represents a color gamut transformation (as a 4x4 color matrix) + */ +class GrColorSpaceXform : public SkRefCnt { +public: + GrColorSpaceXform(const SkMatrix44& srcToDst); + + static sk_sp Make(SkColorSpace* src, SkColorSpace* dst); + + const SkMatrix44& srcToDst() const { return fSrcToDst; } + + /** + * GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its + * computed key. + */ + static uint32_t XformKey(GrColorSpaceXform* xform) { + // Code generation changes if there is an xform, but it otherwise constant + return SkToBool(xform) ? 1 : 0; + } + + static bool Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b); + + GrColor4f apply(const GrColor4f& srcColor); + +private: + SkMatrix44 fSrcToDst; +}; + +#endif diff --git a/gfx/skia/skia/include/gpu/GrConfig.h b/gfx/skia/skia/include/gpu/GrConfig.h index 8e0efbd4725a..acdff3af2bcf 100644 --- a/gfx/skia/skia/include/gpu/GrConfig.h +++ b/gfx/skia/skia/include/gpu/GrConfig.h @@ -33,7 +33,7 @@ */ #if !defined(GR_CACHE_STATS) - #if defined(SK_DEVELOPER) || defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) #define GR_CACHE_STATS 1 #else #define GR_CACHE_STATS 0 @@ -41,7 +41,7 @@ #endif #if !defined(GR_GPU_STATS) - #if defined(SK_DEVELOPER) || defined(SK_DEBUG) || defined(SK_DUMP_STATS) + #if defined(SK_DEBUG) || defined(SK_DUMP_STATS) #define GR_GPU_STATS 1 #else #define GR_GPU_STATS 0 diff --git a/gfx/skia/skia/include/gpu/GrContext.h b/gfx/skia/skia/include/gpu/GrContext.h index d59b2a28f0c7..996b77f2dbf0 100644 --- a/gfx/skia/skia/include/gpu/GrContext.h +++ b/gfx/skia/skia/include/gpu/GrContext.h @@ -24,14 +24,13 @@ struct GrBatchAtlasConfig; class GrBatchFontCache; struct GrContextOptions; +class GrContextPriv; class GrContextThreadSafeProxy; class GrDrawingManager; class GrDrawContext; -class GrDrawTarget; class GrFragmentProcessor; class GrGpu; class GrIndexBuffer; -class GrLayerCache; class GrOvalRenderer; class GrPath; class GrPipelineBuilder; @@ -43,7 +42,6 @@ class GrTextBlobCache; class GrTextContext; class GrTextureParams; class GrVertexBuffer; -class GrStrokeInfo; class GrSwizzle; class SkTraceMemoryDump; @@ -183,46 +181,43 @@ public: int getRecommendedSampleCount(GrPixelConfig config, SkScalar dpi) const; /** - * Returns a helper object to orchestrate draws. - * Callers assume the creation ref of the drawContext - * NULL will be returned if the context has been abandoned. - * - * @param rt the render target receiving the draws - * @param surfaceProps the surface properties (mainly defines text drawing) - * - * @return a draw context + * Create both a GrRenderTarget and a matching GrDrawContext to wrap it. + * We guarantee that "asTexture" will succeed for drawContexts created + * via this entry point. */ - GrDrawContext* drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps = NULL); + sk_sp makeDrawContext(SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt = 0, + GrSurfaceOrigin origin = kDefault_GrSurfaceOrigin, + const SkSurfaceProps* surfaceProps = nullptr, + SkBudgeted = SkBudgeted::kYes); + + /* + * This method will attempt to create a drawContext that has, at least, the number of + * channels and precision per channel as requested in 'config' (e.g., A8 and 888 can be + * converted to 8888). It may also swizzle the channels (e.g., BGRA -> RGBA). + * SRGB-ness will be preserved. + */ + sk_sp makeDrawContextWithFallback( + SkBackingFit fit, + int width, int height, + GrPixelConfig config, + sk_sp colorSpace, + int sampleCnt = 0, + GrSurfaceOrigin origin = kDefault_GrSurfaceOrigin, + const SkSurfaceProps* surfaceProps = nullptr, + SkBudgeted budgeted = SkBudgeted::kYes); /////////////////////////////////////////////////////////////////////////// // Misc. - /** - * Flags that affect flush() behavior. - */ - enum FlushBits { - /** - * A client may reach a point where it has partially rendered a frame - * through a GrContext that it knows the user will never see. This flag - * causes the flush to skip submission of deferred content to the 3D API - * during the flush. - */ - kDiscard_FlushBit = 0x2, - }; - /** * Call to ensure all drawing to the context has been issued to the * underlying 3D API. - * @param flagsBitfield flags that control the flushing behavior. See - * FlushBits. */ - void flush(int flagsBitfield = 0); - - void flushIfNecessary() { - if (fFlushToReduceCacheSize || this->caps()->immediateFlush()) { - this->flush(); - } - } + void flush(); /** * These flags can be used with the read/write pixels functions below. @@ -284,7 +279,6 @@ public: /** * Copies a rectangle of texels from src to dst. - * bounds. * @param dst the surface to copy to. * @param src the surface to copy from. * @param srcRect the rectangle of the src that should be copied. @@ -307,6 +301,12 @@ public: */ void flushSurfaceWrites(GrSurface* surface); + /** + * After this returns any pending reads or writes to the surface will have been issued to the + * backend 3D API. + */ + void flushSurfaceIO(GrSurface* surface); + /** * Finalizes all pending reads and writes to the surface and also performs an MSAA resolve * if necessary. @@ -327,15 +327,14 @@ public: GrGpu* getGpu() { return fGpu; } const GrGpu* getGpu() const { return fGpu; } GrBatchFontCache* getBatchFontCache() { return fBatchFontCache; } - GrLayerCache* getLayerCache() { return fLayerCache.get(); } GrTextBlobCache* getTextBlobCache() { return fTextBlobCache; } bool abandoned() const; GrResourceProvider* resourceProvider() { return fResourceProvider; } const GrResourceProvider* resourceProvider() const { return fResourceProvider; } GrResourceCache* getResourceCache() { return fResourceCache; } - // Called by tests that draw directly to the context via GrDrawTarget - void getTestTarget(GrTestTarget*, GrRenderTarget* rt); + // Called by tests that draw directly to the context via GrDrawContext + void getTestTarget(GrTestTarget*, sk_sp); /** Reset GPU stats */ void resetGpuStats() const ; @@ -369,6 +368,10 @@ public: /** This is only useful for debug purposes */ SkDEBUGCODE(GrSingleOwner* debugSingleOwner() const { return &fSingleOwner; } ) + // Provides access to functions that aren't part of the public API. + GrContextPriv contextPriv(); + const GrContextPriv contextPriv() const; + private: GrGpu* fGpu; const GrCaps* fCaps; @@ -383,11 +386,8 @@ private: SkAutoTUnref fThreadSafeProxy; GrBatchFontCache* fBatchFontCache; - SkAutoTDelete fLayerCache; SkAutoTDelete fTextBlobCache; - // Set by OverbudgetCB() to request that GrContext flush before exiting a draw. - bool fFlushToReduceCacheSize; bool fDidTestPMConversions; int fPMToUPMConversion; int fUPMToPMConversion; @@ -422,10 +422,8 @@ private: GrAuditTrail fAuditTrail; - // TODO: have the CMM use drawContexts and rm this friending - friend class GrClipMaskManager; // the CMM is friended just so it can call 'drawingManager' - friend class GrDrawingManager; // for access to drawingManager for ProgramUnitTest - GrDrawingManager* drawingManager() { return fDrawingManager; } + // TODO: have the GrClipStackClip use drawContexts and rm this friending + friend class GrContextPriv; GrContext(); // init must be called after the constructor. bool init(GrBackend, GrBackendContext, const GrContextOptions& options); @@ -438,9 +436,9 @@ private: * of effects that make a readToUPM->writeToPM->readToUPM cycle invariant. Otherwise, they * return NULL. They also can perform a swizzle as part of the draw. */ - const GrFragmentProcessor* createPMToUPMEffect(GrTexture*, const GrSwizzle&, + sk_sp createPMToUPMEffect(GrTexture*, const GrSwizzle&, const SkMatrix&) const; - const GrFragmentProcessor* createUPMToPMEffect(GrTexture*, const GrSwizzle&, + sk_sp createUPMToPMEffect(GrTexture*, const GrSwizzle&, const SkMatrix&) const; /** Called before either of the above two functions to determine the appropriate fragment processors for conversions. This must be called by readSurfacePixels before a mutex is @@ -450,12 +448,6 @@ private: will fail. In such cases fall back to SW conversion. */ bool didFailPMUPMConversionTest() const; - /** - * This callback allows the resource cache to callback into the GrContext - * when the cache is still over budget after a purge. - */ - static void OverBudgetCB(void* data); - /** * 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. diff --git a/gfx/skia/skia/include/gpu/GrContextOptions.h b/gfx/skia/skia/include/gpu/GrContextOptions.h index 4e763405e103..0522b9d20bc5 100644 --- a/gfx/skia/skia/include/gpu/GrContextOptions.h +++ b/gfx/skia/skia/include/gpu/GrContextOptions.h @@ -11,68 +11,77 @@ #include "SkTypes.h" struct GrContextOptions { - GrContextOptions() - : fDrawPathToCompressedTexture(false) - , fSuppressPrints(false) - , fMaxTextureSizeOverride(SK_MaxS32) - , fMaxTileSizeOverride(0) - , fSuppressDualSourceBlending(false) - , fBufferMapThreshold(-1) - , fUseDrawInsteadOfPartialRenderTargetWrite(false) - , fImmediateMode(false) - , fClipBatchToBounds(false) - , fDrawBatchBounds(false) - , fMaxBatchLookback(-1) - , fMaxBatchLookahead(-1) - , fUseShaderSwizzling(false) {} - - // EXPERIMENTAL - // May be removed in the future, or may become standard depending - // on the outcomes of a variety of internal tests. - bool fDrawPathToCompressedTexture; + GrContextOptions() {} // Suppress prints for the GrContext. - bool fSuppressPrints; + 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; + int fMaxTextureSizeOverride = SK_MaxS32; + /** If non-zero, overrides the maximum size of a tile for sw-backed images and bitmaps rendered by SkGpuDevice. */ - int fMaxTileSizeOverride; - bool fSuppressDualSourceBlending; + int fMaxTileSizeOverride = 0; + bool fSuppressDualSourceBlending = false; /** 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; + int fBufferMapThreshold = -1; /** some gpus have problems with partial writes of the rendertarget */ - bool fUseDrawInsteadOfPartialRenderTargetWrite; + bool fUseDrawInsteadOfPartialRenderTargetWrite = false; /** The GrContext operates in immediate mode. It will issue all draws to the backend API immediately. Intended to ease debugging. */ - bool fImmediateMode; + bool fImmediateMode = false; /** For debugging purposes turn each GrBatch's bounds into a clip rect. This is used to verify that the clip bounds are conservative. */ - bool fClipBatchToBounds; + bool fClipBatchToBounds = false; /** For debugging purposes draw a wireframe device bounds rect for each GrBatch. The wire frame rect is draw before the GrBatch in order to visualize batches that draw outside of their dev bounds. */ - bool fDrawBatchBounds; + bool fDrawBatchBounds = false; /** For debugging, override the default maximum look-back or look-ahead window for GrBatch combining. */ - int fMaxBatchLookback; - int fMaxBatchLookahead; + int fMaxBatchLookback = -1; + int fMaxBatchLookahead = -1; /** Force us to do all swizzling manually in the shader and don't rely on extensions to do swizzling. */ - bool fUseShaderSwizzling; + bool fUseShaderSwizzling = false; + + /** 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; + + /** Enable instanced rendering as long as all required functionality is supported by the HW. + Instanced rendering is still experimental at this point and disabled by default. */ + bool fEnableInstancedRendering = 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 = false; + + /** + * Force all path draws to go through through the sw-rasterize-to-texture code path (assuming + * the path is not recognized as a simpler shape (e.g. a rrect). This is intended for testing + * purposes. + */ + bool fForceSWPathMasks = false; }; #endif diff --git a/gfx/skia/skia/include/gpu/GrCoordTransform.h b/gfx/skia/skia/include/gpu/GrCoordTransform.h index 4d96cd9c979f..3080523ebdcf 100644 --- a/gfx/skia/skia/include/gpu/GrCoordTransform.h +++ b/gfx/skia/skia/include/gpu/GrCoordTransform.h @@ -15,82 +15,54 @@ #include "GrShaderVar.h" /** - * Coordinates available to GrProcessor subclasses for requesting transformations. Transformed - * coordinates are made available in the the portion of fragment shader emitted by the effect. - * - * The precision of the shader var that interpolates the transformed coordinates can be specified. - */ -enum GrCoordSet { - /** - * The user-space coordinates that map to the fragment being rendered. This is the space in - * which SkShader operates. It is usually the space in which geometry passed to SkCanvas is - * specified (before the view matrix is applied). However, some draw calls take explicit local - * coords that map onto the geometry (e.g. drawVertices, drawBitmapRectToRect). - */ - kLocal_GrCoordSet, - - /** - * The device space position of the fragment being shaded. - */ - kDevice_GrCoordSet, -}; - -/** - * A class representing a linear transformation from one of the built-in coordinate sets (local or - * position). GrProcessors just define these transformations, and the framework does the rest of the - * work to make the transformed coordinates available in their fragment shader. + * A class representing a linear transformation of local coordinates. GrFragnentProcessors + * these transformations, and the GrGeometryProcessor implements the transformation. */ class GrCoordTransform : SkNoncopyable { public: - GrCoordTransform() : fSourceCoords(kLocal_GrCoordSet) { SkDEBUGCODE(fInProcessor = false); } + GrCoordTransform() { SkDEBUGCODE(fInProcessor = false); } /** * Create a transformation that maps [0, 1] to a texture's boundaries. The precision is inferred * from the texture size and filter. The texture origin also implies whether a y-reversal should * be performed. */ - GrCoordTransform(GrCoordSet sourceCoords, - const GrTexture* texture, - GrTextureParams::FilterMode filter) { + GrCoordTransform(const GrTexture* texture, GrTextureParams::FilterMode filter) { SkASSERT(texture); SkDEBUGCODE(fInProcessor = false); - this->reset(sourceCoords, texture, filter); + this->reset(texture, filter); } /** * Create a transformation from a matrix. The precision is inferred from the texture size and * filter. The texture origin also implies whether a y-reversal should be performed. */ - GrCoordTransform(GrCoordSet sourceCoords, const SkMatrix& m, - const GrTexture* texture, GrTextureParams::FilterMode filter) { + GrCoordTransform(const SkMatrix& m, const GrTexture* texture, + GrTextureParams::FilterMode filter) { SkDEBUGCODE(fInProcessor = false); SkASSERT(texture); - this->reset(sourceCoords, m, texture, filter); + this->reset(m, texture, filter); } /** * Create a transformation that applies the matrix to a coord set. */ - GrCoordTransform(GrCoordSet sourceCoords, const SkMatrix& m, - GrSLPrecision precision = kDefault_GrSLPrecision) { + GrCoordTransform(const SkMatrix& m, GrSLPrecision precision = kDefault_GrSLPrecision) { SkDEBUGCODE(fInProcessor = false); - this->reset(sourceCoords, m, precision); + this->reset(m, precision); } - void reset(GrCoordSet sourceCoords, const GrTexture* texture, - GrTextureParams::FilterMode filter) { + void reset(const GrTexture* texture, GrTextureParams::FilterMode filter) { SkASSERT(!fInProcessor); SkASSERT(texture); - this->reset(sourceCoords, MakeDivByTextureWHMatrix(texture), texture, filter); + this->reset(MakeDivByTextureWHMatrix(texture), texture, filter); } - void reset(GrCoordSet, const SkMatrix&, const GrTexture*, GrTextureParams::FilterMode filter); - void reset(GrCoordSet sourceCoords, const SkMatrix& m, - GrSLPrecision precision = kDefault_GrSLPrecision); + void reset(const SkMatrix&, const GrTexture*, GrTextureParams::FilterMode filter); + void reset(const SkMatrix& m, GrSLPrecision precision = kDefault_GrSLPrecision); GrCoordTransform& operator= (const GrCoordTransform& that) { SkASSERT(!fInProcessor); - fSourceCoords = that.fSourceCoords; fMatrix = that.fMatrix; fReverseY = that.fReverseY; fPrecision = that.fPrecision; @@ -107,15 +79,13 @@ public: } bool operator==(const GrCoordTransform& that) const { - return fSourceCoords == that.fSourceCoords && - fMatrix.cheapEqualTo(that.fMatrix) && + return fMatrix.cheapEqualTo(that.fMatrix) && fReverseY == that.fReverseY && fPrecision == that.fPrecision; } bool operator!=(const GrCoordTransform& that) const { return !(*this == that); } - GrCoordSet sourceCoords() const { return fSourceCoords; } const SkMatrix& getMatrix() const { return fMatrix; } bool reverseY() const { return fReverseY; } GrSLPrecision precision() const { return fPrecision; } @@ -130,7 +100,6 @@ public: } private: - GrCoordSet fSourceCoords; SkMatrix fMatrix; bool fReverseY; GrSLPrecision fPrecision; diff --git a/gfx/skia/skia/include/gpu/GrDrawContext.h b/gfx/skia/skia/include/gpu/GrDrawContext.h index 06954dc1bbf4..72de15deae60 100644 --- a/gfx/skia/skia/include/gpu/GrDrawContext.h +++ b/gfx/skia/skia/include/gpu/GrDrawContext.h @@ -9,30 +9,34 @@ #define GrDrawContext_DEFINED #include "GrColor.h" +#include "GrContext.h" +#include "GrPaint.h" #include "GrRenderTarget.h" #include "SkRefCnt.h" #include "SkRegion.h" #include "SkSurfaceProps.h" +#include "../private/GrInstancedPipelineInfo.h" #include "../private/GrSingleOwner.h" -class GrAtlasTextContext; class GrAuditTrail; class GrClip; -class GrContext; class GrDrawBatch; class GrDrawContextPriv; class GrDrawPathBatchBase; class GrDrawingManager; class GrDrawTarget; +class GrFixedClip; class GrPaint; class GrPathProcessor; class GrPipelineBuilder; class GrRenderTarget; -class GrStrokeInfo; +class GrStyle; class GrSurface; +struct GrUserStencilSettings; class SkDrawFilter; struct SkIPoint; struct SkIRect; +class SkLatticeIter; class SkMatrix; class SkPaint; class SkPath; @@ -53,7 +57,7 @@ public: // TODO: it is odd that we need both the SkPaint in the following 3 methods. // We should extract the text parameters from SkPaint and pass them separately - // akin to GrStrokeInfo (GrTextInfo?) + // akin to GrStyle (GrTextInfo?) virtual void drawText(const GrClip&, const GrPaint&, const SkPaint&, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y, const SkIRect& clipBounds); @@ -90,19 +94,15 @@ public: * Draw the rect using a paint. * @param paint describes how to color pixels. * @param viewMatrix transformation matrix - * @param strokeInfo the stroke information (width, join, cap), and. - * the dash information (intervals, count, phase). - * If strokeInfo == NULL, then the rect is filled. - * Otherwise, if stroke width == 0, then the stroke - * is always a single pixel thick, else the rect is - * mitered/beveled stroked based on stroke width. + * @param style The style to apply. Null means fill. Currently path effects are not + * allowed. * The rects coords are used to access the paint (through texture matrix) */ void drawRect(const GrClip&, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRect&, - const GrStrokeInfo* strokeInfo = nullptr); + const GrStyle* style = nullptr); /** * Maps a rectangle of shader coordinates to a rectangle and fills that rectangle. @@ -133,14 +133,13 @@ public: * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param rrect the roundrect to draw - * @param strokeInfo the stroke information (width, join, cap) and - * the dash information (intervals, count, phase). + * @param style style to apply to the rrect. Currently path effects are not allowed. */ void drawRRect(const GrClip&, const GrPaint&, const SkMatrix& viewMatrix, const SkRRect& rrect, - const GrStrokeInfo&); + const GrStyle& style); /** * Shortcut for drawing an SkPath consisting of nested rrects using a paint. @@ -164,14 +163,13 @@ public: * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param path the path to draw - * @param strokeInfo the stroke information (width, join, cap) and - * the dash information (intervals, count, phase). + * @param style style to apply to the path. */ void drawPath(const GrClip&, const GrPaint&, const SkMatrix& viewMatrix, const SkPath&, - const GrStrokeInfo&); + const GrStyle& style); /** * Draws vertices with a paint. @@ -219,86 +217,172 @@ public: const SkRSXform xform[], const SkRect texRect[], const SkColor colors[]); - + + /** + * Draws a region. + * + * @param paint describes how to color pixels + * @param viewMatrix transformation matrix + * @param region the region to be drawn + * @param style style to apply to the region + */ + void drawRegion(const GrClip&, + const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRegion& region, + const GrStyle& style); + /** * Draws an oval. * * @param paint describes how to color pixels. * @param viewMatrix transformation matrix * @param oval the bounding rect of the oval. - * @param strokeInfo the stroke information (width, join, cap) and - * the dash information (intervals, count, phase). + * @param style style to apply to the oval. Currently path effects are not allowed. */ void drawOval(const GrClip&, const GrPaint& paint, const SkMatrix& viewMatrix, const SkRect& oval, - const GrStrokeInfo& strokeInfo); + const GrStyle& style); + /** + * Draws a partial arc of an oval. + * + * @param paint describes how to color pixels. + * @param viewMatrix transformation matrix. + * @param oval the bounding rect of the oval. + * @param startAngle starting angle in degrees. + * @param sweepAngle angle to sweep in degrees. Must be in (-360, 360) + * @param useCenter true means that the implied path begins at the oval center, connects as a + * line to the point indicated by the start contains the arc indicated by + * the sweep angle. If false the line beginning at the center point is + * omitted. + * @param style style to apply to the oval. + */ + void drawArc(const GrClip&, + const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRect& oval, + SkScalar startAngle, + SkScalar sweepAngle, + bool useCenter, + const GrStyle& style); /** - * Draw the image stretched differentially to fit into dst. - * center is a rect within the image, and logically divides the image - * into 9 sections (3x3). For example, if the middle pixel of a [5x5] - * image is the "center", then the center-rect should be [2, 2, 3, 3]. - * - * If the dst is >= the image size, then... - * - The 4 corners are not stretched at all. - * - The sides are stretched in only one axis. - * - The center is stretched in both axes. - * Else, for each axis where dst < image, - * - The corners shrink proportionally - * - The sides (along the shrink axis) and center are not drawn + * Draw the image as a set of rects, specified by |iter|. */ - void drawImageNine(const GrClip&, - const GrPaint& paint, - const SkMatrix& viewMatrix, - int imageWidth, - int imageHeight, - const SkIRect& center, - const SkRect& dst); + void drawImageLattice(const GrClip&, + const GrPaint& paint, + const SkMatrix& viewMatrix, + int imageWidth, + int imageHeight, + std::unique_ptr iter, + const SkRect& dst); /** - * Draws a batch - * - * @param paint describes how to color pixels. - * @param batch the batch to draw + * After this returns any pending surface IO will be issued to the backend 3D API and + * if the surface has MSAA it will be resolved. */ - void drawBatch(const GrClip&, const GrPaint&, GrDrawBatch*); + void prepareForExternalIO(); /** - * Draws a path batch. This needs to be separate from drawBatch because we install path stencil - * settings late. + * Reads a rectangle of pixels from the draw context. + * @param dstInfo image info for the destination + * @param dstBuffer destination pixels for the read + * @param dstRowBytes bytes in a row of 'dstBuffer' + * @param x x offset w/in the draw context from which to read + * @param y y offset w/in the draw context from which to read * - * TODO: Figure out a better model that allows us to roll this method into drawBatch. + * @return true if the read succeeded, false if not. The read can fail because of an + * unsupported pixel config. */ - void drawPathBatch(const GrPipelineBuilder&, GrDrawPathBatchBase*); + bool readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes, int x, int y); + /** + * Writes a rectangle of pixels [srcInfo, srcBuffer, srcRowbytes] into the + * drawContext at the specified position. + * @param srcInfo image info for the source pixels + * @param srcBuffer source for the write + * @param srcRowBytes bytes in a row of 'srcBuffer' + * @param x x offset w/in the draw context at which to write + * @param y y offset w/in the draw context at which to write + * + * @return true if the write succeeded, false if not. The write can fail because of an + * unsupported pixel config. + */ + bool writePixels(const SkImageInfo& srcInfo, const void* srcBuffer, size_t srcRowBytes, + int x, int y); + + bool isStencilBufferMultisampled() const { + return fRenderTarget->isStencilBufferMultisampled(); + } + bool isUnifiedMultisampled() const { return fRenderTarget->isUnifiedMultisampled(); } + bool hasMixedSamples() const { return fRenderTarget->isMixedSampled(); } + + bool mustUseHWAA(const GrPaint& paint) const { + return paint.isAntiAlias() && fRenderTarget->isUnifiedMultisampled(); + } + + const GrCaps* caps() const { return fContext->caps(); } + const GrSurfaceDesc& desc() const { return fRenderTarget->desc(); } int width() const { return fRenderTarget->width(); } int height() const { return fRenderTarget->height(); } + GrPixelConfig config() const { return fRenderTarget->config(); } int numColorSamples() const { return fRenderTarget->numColorSamples(); } - bool allowSRGBInputs() const { return fSurfaceProps.allowSRGBInputs(); } + bool isGammaCorrect() const { return SkToBool(fColorSpace.get()); } + SkSourceGammaTreatment sourceGammaTreatment() const { + return this->isGammaCorrect() ? SkSourceGammaTreatment::kRespect + : SkSourceGammaTreatment::kIgnore; + } + const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; } + SkColorSpace* getColorSpace() const { return fColorSpace.get(); } + GrColorSpaceXform* getColorXformFromSRGB() const { return fColorXformFromSRGB.get(); } + GrSurfaceOrigin origin() const { return fRenderTarget->origin(); } - GrRenderTarget* accessRenderTarget() { return fRenderTarget; } + bool wasAbandoned() const; + + GrRenderTarget* accessRenderTarget() { return fRenderTarget.get(); } + + sk_sp asTexture() { return sk_ref_sp(fRenderTarget->asTexture()); } // Provides access to functions that aren't part of the public API. GrDrawContextPriv drawContextPriv(); const GrDrawContextPriv drawContextPriv() const; + GrAuditTrail* auditTrail() { return fAuditTrail; } + protected: - GrDrawContext(GrContext*, GrDrawingManager*, GrRenderTarget*, + GrDrawContext(GrContext*, GrDrawingManager*, sk_sp, sk_sp, const SkSurfaceProps* surfaceProps, GrAuditTrail*, GrSingleOwner*); GrDrawingManager* drawingManager() { return fDrawingManager; } - GrAuditTrail* auditTrail() { return fAuditTrail; } - const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; } - + SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; }) SkDEBUGCODE(void validate() const;) private: friend class GrAtlasTextBlob; // for access to drawBatch + friend class GrStencilAndCoverTextContext; // for access to drawBatch + friend class GrDrawingManager; // for ctor friend class GrDrawContextPriv; + friend class GrTestTarget; // for access to getDrawTarget + friend class GrSWMaskHelper; // for access to drawBatch + + // All the path renderers currently make their own batches + friend class GrSoftwarePathRenderer; // for access to drawBatch + friend class GrAAConvexPathRenderer; // for access to drawBatch + friend class GrDashLinePathRenderer; // for access to drawBatch + friend class GrAAHairLinePathRenderer; // for access to drawBatch + friend class GrAALinearizingConvexPathRenderer; // for access to drawBatch + friend class GrAADistanceFieldPathRenderer; // for access to drawBatch + friend class GrDefaultPathRenderer; // for access to drawBatch + friend class GrPLSPathRenderer; // for access to drawBatch + friend class GrMSAAPathRenderer; // for access to drawBatch + friend class GrStencilAndCoverPathRenderer; // for access to drawBatch + friend class GrTessellatingPathRenderer; // for access to drawBatch + + void internalClear(const GrFixedClip&, const GrColor, bool canIgnoreClip); bool drawFilledDRRect(const GrClip& clip, const GrPaint& paint, @@ -306,31 +390,44 @@ private: const SkRRect& origOuter, const SkRRect& origInner); - GrDrawBatch* getFillRectBatch(const GrPaint& paint, - const SkMatrix& viewMatrix, - const SkRect& rect); + bool drawFilledRect(const GrClip& clip, + const GrPaint& paint, + const SkMatrix& viewMatrix, + const SkRect& rect, + const GrUserStencilSettings* ss); + + void drawNonAAFilledRect(const GrClip&, + const GrPaint&, + const SkMatrix& viewMatrix, + const SkRect& rect, + const SkRect* localRect, + const SkMatrix* localMatrix, + const GrUserStencilSettings* ss, + bool useHWAA); void internalDrawPath(const GrClip& clip, const GrPaint& paint, const SkMatrix& viewMatrix, const SkPath& path, - const GrStrokeInfo& strokeInfo); + const GrStyle& style); // This entry point allows the GrTextContext-derived classes to add their batches to // the drawTarget. - void drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch); + void drawBatch(const GrPipelineBuilder& pipelineBuilder, const GrClip&, GrDrawBatch* batch); GrDrawTarget* getDrawTarget(); GrDrawingManager* fDrawingManager; - GrRenderTarget* fRenderTarget; + sk_sp fRenderTarget; // In MDB-mode the drawTarget can be closed by some other drawContext that has picked // it up. For this reason, the drawTarget should only ever be accessed via 'getDrawTarget'. GrDrawTarget* fDrawTarget; - SkAutoTDelete fAtlasTextContext; GrContext* fContext; + GrInstancedPipelineInfo fInstancedPipelineInfo; + sk_sp fColorSpace; + sk_sp fColorXformFromSRGB; SkSurfaceProps fSurfaceProps; GrAuditTrail* fAuditTrail; diff --git a/gfx/skia/skia/include/gpu/GrFragmentProcessor.h b/gfx/skia/skia/include/gpu/GrFragmentProcessor.h index 55b2f905d9c5..d7011f826c84 100644 --- a/gfx/skia/skia/include/gpu/GrFragmentProcessor.h +++ b/gfx/skia/skia/include/gpu/GrFragmentProcessor.h @@ -14,6 +14,7 @@ class GrCoordTransform; class GrGLSLCaps; class GrGLSLFragmentProcessor; class GrInvariantOutput; +class GrPipeline; class GrProcessorKeyBuilder; /** Provides custom fragment shader code. Fragment processors receive an input color (vec4f) and @@ -31,35 +32,42 @@ public: * does so by returning a parent FP that multiplies the passed in FPs output by the parent's * input alpha. The passed in FP will not receive an input color. */ - static const GrFragmentProcessor* MulOutputByInputAlpha(const GrFragmentProcessor*); + static sk_sp MulOutputByInputAlpha(sk_sp); /** * Similar to the above but it modulates the output r,g,b of the child processor by the input * rgb and then multiplies all the components by the input alpha. This effectively modulates * the child processor's premul color by a unpremul'ed input and produces a premul output */ - static const GrFragmentProcessor* MulOutputByInputUnpremulColor(const GrFragmentProcessor*); + static sk_sp MulOutputByInputUnpremulColor(sk_sp); /** * Returns a parent fragment processor that adopts the passed fragment processor as a child. * The parent will ignore its input color and instead feed the passed in color as input to the * child. */ - static const GrFragmentProcessor* OverrideInput(const GrFragmentProcessor*, GrColor); + static sk_sp OverrideInput(sk_sp, GrColor4f); + + /** + * Returns a fragment processor that premuls the input before calling the passed in fragment + * processor. + */ + static sk_sp PremulInput(sk_sp); /** * Returns a fragment processor that runs the passed in array of fragment processors in a * series. The original input is passed to the first, the first's output is passed to the * second, etc. The output of the returned processor is the output of the last processor of the * series. + * + * The array elements with be moved. */ - static const GrFragmentProcessor* RunInSeries(const GrFragmentProcessor*[], int cnt); + static sk_sp RunInSeries(sk_sp*, int cnt); GrFragmentProcessor() : INHERITED() - , fUsesLocalCoords(false) - , fNumTexturesExclChildren(0) - , fNumTransformsExclChildren(0) {} + , fUsesDistanceVectorField(false) + , fUsesLocalCoords(false) {} ~GrFragmentProcessor() override; @@ -72,11 +80,7 @@ public: } } - int numTexturesExclChildren() const { return fNumTexturesExclChildren; } - - int numTransformsExclChildren() const { return fNumTransformsExclChildren; } - - int numTransforms() const { return fCoordTransforms.count(); } + int numCoordTransforms() const { return fCoordTransforms.count(); } /** Returns the coordinate transformation at index. index must be valid according to numTransforms(). */ @@ -86,12 +90,6 @@ public: return fCoordTransforms; } - void gatherCoordTransforms(SkTArray* outTransforms) const { - if (!fCoordTransforms.empty()) { - outTransforms->push_back_n(fCoordTransforms.count(), fCoordTransforms.begin()); - } - } - int numChildProcessors() const { return fChildProcessors.count(); } const GrFragmentProcessor& childProcessor(int index) const { return *fChildProcessors[index]; } @@ -99,6 +97,9 @@ public: /** Do any of the coordtransforms for this processor require local coords? */ bool usesLocalCoords() const { return fUsesLocalCoords; } + /** Does this FP need a vector to the nearest edge? */ + bool usesDistanceVectorField() const { return fUsesDistanceVectorField; } + /** Returns true if this and other processor conservatively draw identically. It can only return true when the two processor are of the same subclass (i.e. they return the same object from from getFactory()). @@ -106,7 +107,7 @@ public: A return value of true from isEqual() should not be used to test whether the processor would generate the same shader code. To test for identical code generation use getGLSLProcessorKey */ - bool isEqual(const GrFragmentProcessor& that, bool ignoreCoordTransforms) const; + bool isEqual(const GrFragmentProcessor& that) const; /** * This function is used to perform optimizations. When called the invarientOuput param @@ -120,8 +121,76 @@ public: this->onComputeInvariantOutput(inout); } + /** + * Pre-order traversal of a FP hierarchy, or of the forest of FPs in a GrPipeline. In the latter + * case the tree rooted at each FP in the GrPipeline is visited successively. + */ + class Iter : public SkNoncopyable { + public: + explicit Iter(const GrFragmentProcessor* fp) { fFPStack.push_back(fp); } + explicit Iter(const GrPipeline& pipeline); + const GrFragmentProcessor* next(); + + private: + SkSTArray<4, const GrFragmentProcessor*, true> fFPStack; + }; + + /** + * Iterates over all the Ts owned by a GrFragmentProcessor and its children or over all the Ts + * owned by the forest of GrFragmentProcessors in a GrPipeline. FPs are visited in the same + * order as Iter and each of an FP's Ts are visited in order. + */ + template + class FPItemIter : public SkNoncopyable { + public: + explicit FPItemIter(const GrFragmentProcessor* fp) + : fCurrFP(nullptr) + , fCTIdx(0) + , fFPIter(fp) { + fCurrFP = fFPIter.next(); + } + explicit FPItemIter(const GrPipeline& pipeline) + : fCurrFP(nullptr) + , fCTIdx(0) + , fFPIter(pipeline) { + fCurrFP = fFPIter.next(); + } + + const T* next() { + if (!fCurrFP) { + return nullptr; + } + while (fCTIdx == (fCurrFP->*COUNT)()) { + fCTIdx = 0; + fCurrFP = fFPIter.next(); + if (!fCurrFP) { + return nullptr; + } + } + return &(fCurrFP->*GET)(fCTIdx++); + } + + private: + const GrFragmentProcessor* fCurrFP; + int fCTIdx; + GrFragmentProcessor::Iter fFPIter; + }; + + using CoordTransformIter = FPItemIter; + + using TextureAccessIter = FPItemIter; + protected: void addTextureAccess(const GrTextureAccess* textureAccess) override; + void addBufferAccess(const GrBufferAccess*) override; /** * Fragment Processor subclasses call this from their constructor to register coordinate @@ -151,7 +220,7 @@ protected: * processors will allow the ProgramBuilder to automatically handle their transformed coords and * texture accesses and mangle their uniform and output color names. */ - int registerChildProcessor(const GrFragmentProcessor* child); + int registerChildProcessor(sk_sp child); /** * Subclass implements this to support getConstantColorComponents(...). @@ -161,6 +230,11 @@ protected: */ virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0; + /* Sub-classes should set this to true in their constructors if they need access to a distance + * vector field to the nearest edge + */ + bool fUsesDistanceVectorField; + private: void notifyRefCntIsZero() const final; @@ -183,35 +257,15 @@ private: bool hasSameTransforms(const GrFragmentProcessor&) const; - bool fUsesLocalCoords; + bool fUsesLocalCoords; + + SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; /** - * fCoordTransforms stores the transforms of this proc, followed by all the transforms of this - * proc's children. In other words, each proc stores all the transforms of its subtree as if - * they were collected using preorder traversal. - * - * Example: - * Suppose we have frag proc A, who has two children B and D. B has a child C, and D has - * two children E and F. Suppose procs A, B, C, D, E, F have 1, 2, 1, 1, 3, 2 transforms - * respectively. The following shows what the fCoordTransforms array of each proc would contain: - * - * (A) - * [a1,b1,b2,c1,d1,e1,e2,e3,f1,f2] - * / \ - * / \ - * (B) (D) - * [b1,b2,c1] [d1,e1,e2,e3,f1,f2] - * / / \ - * / / \ - * (C) (E) (F) - * [c1] [e1,e2,e3] [f1,f2] - * - * The same goes for fTextureAccesses with textures. + * This is not SkSTArray<1, sk_sp> because this class holds strong + * references until notifyRefCntIsZero and then it holds pending executions. */ - SkSTArray<4, const GrCoordTransform*, true> fCoordTransforms; - int fNumTexturesExclChildren; - int fNumTransformsExclChildren; - SkSTArray<1, const GrFragmentProcessor*, true> fChildProcessors; + SkSTArray<1, GrFragmentProcessor*, true> fChildProcessors; typedef GrProcessor INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrGpuResource.h b/gfx/skia/skia/include/gpu/GrGpuResource.h index 8103959984b1..364a886408cf 100644 --- a/gfx/skia/skia/include/gpu/GrGpuResource.h +++ b/gfx/skia/skia/include/gpu/GrGpuResource.h @@ -10,7 +10,6 @@ #include "GrResourceKey.h" #include "GrTypesPriv.h" -#include "SkData.h" class GrContext; class GrGpu; @@ -140,34 +139,6 @@ private: class SK_API GrGpuResource : public GrIORef { public: - - enum LifeCycle { - /** - * The resource is cached and owned by Skia. Resources with this status may be kept alive - * by the cache as either scratch or unique resources even when there are no refs to them. - * The cache may release them whenever there are no refs. - */ - kCached_LifeCycle, - - /** - * The resource is uncached. As soon as there are no more refs to it, it is released. Under - * the hood the cache may opaquely recycle it as a cached resource. - */ - kUncached_LifeCycle, - - /** - * Similar to uncached, but Skia does not manage the lifetime of the underlying backend - * 3D API object(s). The client is responsible for freeing those. Used to inject client- - * created GPU resources into Skia (e.g. to render to a client-created texture). - */ - kBorrowed_LifeCycle, - - /** - * An external resource with ownership transfered into Skia. Skia will free the resource. - */ - kAdopted_LifeCycle, - }; - /** * Tests whether a object has been abandoned or released. All objects will * be in this state after their creating GrContext is destroyed or has @@ -209,26 +180,12 @@ public: * not change when the content of the GrGpuResource object changes. This will never return * 0. */ - uint32_t getUniqueID() const { return fUniqueID; } + uint32_t 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; } - /** - * Attach a custom data object to this resource. The data will remain attached - * for the lifetime of this resource (until it is abandoned or released). - * Takes a ref on data. Previously attached data, if any, is unrefed. - * Returns the data argument, for convenience. - */ - const SkData* setCustomData(const SkData* data); - - /** - * Returns the custom data object that was attached to this resource by - * calling setCustomData. - */ - const SkData* getCustomData() const { return fData.get(); } - /** * Internal-only helper class used for manipulations of the resource by the cache. */ @@ -260,12 +217,19 @@ public: **/ virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; -protected: - // This must be called by every GrGpuObject. It should be called once the object is fully - // initialized (i.e. not in a base class constructor). - void registerWithCache(); + static uint32_t CreateUniqueID(); - GrGpuResource(GrGpu*, LifeCycle); +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(); + + GrGpuResource(GrGpu*); virtual ~GrGpuResource(); GrGpu* getGpu() const { return fGpu; } @@ -277,25 +241,12 @@ protected: backend API calls should be made. */ virtual void onAbandon() { } - bool shouldFreeResources() const { return fLifeCycle != kBorrowed_LifeCycle; } - - bool isExternal() const { - return GrGpuResource::kAdopted_LifeCycle == fLifeCycle || - GrGpuResource::kBorrowed_LifeCycle == fLifeCycle; - } - /** * This entry point should be called whenever gpuMemorySize() should report a different size. * The cache will call gpuMemorySize() to update the current size of the resource. */ void didChangeGpuMemorySize() const; - /** - * Optionally called by the GrGpuResource subclass if the resource can be used as scratch. - * By default resources are not usable as scratch. This should only be called once. - **/ - void setScratchKey(const GrScratchKey& scratchKey); - /** * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by * onMemoryDump. The default implementation adds no backing information. @@ -303,6 +254,14 @@ protected: virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) 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. */ @@ -322,15 +281,13 @@ private: #ifdef SK_DEBUG friend class GrGpu; // for assert in GrGpu to access getGpu #endif - - static uint32_t CreateUniqueID(); - // 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; + uint32_t fExternalFlushCntWhenBecamePurgeable; static const size_t kInvalidGpuMemorySize = ~static_cast(0); GrScratchKey fScratchKey; @@ -341,11 +298,10 @@ private: GrGpu* fGpu; mutable size_t fGpuMemorySize; - LifeCycle fLifeCycle; + SkBudgeted fBudgeted; + bool fRefsWrappedObjects; const uint32_t fUniqueID; - SkAutoTUnref fData; - typedef GrIORef INHERITED; friend class GrIORef; // to access notifyAllCntsAreZero and notifyRefCntIsZero. }; diff --git a/gfx/skia/skia/include/gpu/GrInvariantOutput.h b/gfx/skia/skia/include/gpu/GrInvariantOutput.h index 8cf4bf59c324..6e2cbe84f9a0 100644 --- a/gfx/skia/skia/include/gpu/GrInvariantOutput.h +++ b/gfx/skia/skia/include/gpu/GrInvariantOutput.h @@ -197,6 +197,18 @@ public: SkDEBUGCODE(this->validate()); } + void premulFourChannelColor() { + SkDEBUGCODE(this->validate()); + SkASSERT(!fIsSingleComponent); + fNonMulStageFound = true; + if (!(fValidFlags & kA_GrColorComponentFlag)) { + fValidFlags = kNone_GrColorComponentFlags; + } else { + fColor = GrPremulColor(fColor); + } + SkDEBUGCODE(this->validate()); + } + void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) { SkDEBUGCODE(this->validate()); fValidFlags = (fValidFlags & ~invalidateFlags); diff --git a/gfx/skia/skia/include/gpu/GrPaint.h b/gfx/skia/skia/include/gpu/GrPaint.h index 87e036865585..a8af3c2f172d 100644 --- a/gfx/skia/skia/include/gpu/GrPaint.h +++ b/gfx/skia/skia/include/gpu/GrPaint.h @@ -11,12 +11,14 @@ #define GrPaint_DEFINED #include "GrColor.h" +#include "GrColorSpaceXform.h" #include "GrXferProcessor.h" #include "effects/GrPorterDuffXferProcessor.h" #include "GrFragmentProcessor.h" +#include "SkBlendMode.h" +#include "SkRefCnt.h" #include "SkRegion.h" -#include "SkXfermode.h" /** * The paint describes how color and coverage are computed at each pixel by GrContext draw @@ -42,13 +44,18 @@ public: GrPaint(const GrPaint& paint) { *this = paint; } - ~GrPaint() { this->resetFragmentProcessors(); } + ~GrPaint() { } /** * The initial color of the drawn primitive. Defaults to solid white. */ - void setColor(GrColor color) { fColor = color; } - GrColor getColor() const { return fColor; } + void setColor4f(const GrColor4f& color) { fColor = color; } + const GrColor4f& getColor4f() const { return fColor; } + + /** + * Legacy getter, until all code handles 4f directly. + */ + GrColor getColor() const { return fColor.toGrColor(); } /** * Should primitives be anti-aliased or not. Defaults to false. @@ -70,42 +77,60 @@ public: void setAllowSRGBInputs(bool allowSRGBInputs) { fAllowSRGBInputs = allowSRGBInputs; } bool getAllowSRGBInputs() const { return fAllowSRGBInputs; } - const GrXPFactory* setXPFactory(const GrXPFactory* xpFactory) { - fXPFactory.reset(SkSafeRef(xpFactory)); - return xpFactory; + /** + * Does one of the fragment processors need a field of distance vectors to the nearest edge? + */ + bool usesDistanceVectorField() const { return fUsesDistanceVectorField; } + + /** + * Should rendering be gamma-correct, end-to-end. Causes sRGB render targets to behave + * as such (with linear blending), and sRGB inputs to be filtered and decoded correctly. + */ + void setGammaCorrect(bool gammaCorrect) { + setDisableOutputConversionToSRGB(!gammaCorrect); + setAllowSRGBInputs(gammaCorrect); + } + + void setXPFactory(sk_sp xpFactory) { + fXPFactory = std::move(xpFactory); + } + + void setPorterDuffXPFactory(SkBlendMode mode) { + fXPFactory = GrPorterDuffXPFactory::Make((SkXfermode::Mode)mode); } void setPorterDuffXPFactory(SkXfermode::Mode mode) { - fXPFactory.reset(GrPorterDuffXPFactory::Create(mode)); + fXPFactory = GrPorterDuffXPFactory::Make(mode); } - void setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage = false); + void setCoverageSetOpXPFactory(SkRegion::Op, bool invertCoverage = false); /** * Appends an additional color processor to the color computation. */ - const GrFragmentProcessor* addColorFragmentProcessor(const GrFragmentProcessor* fp) { + void addColorFragmentProcessor(sk_sp fp) { SkASSERT(fp); - fColorFragmentProcessors.push_back(SkRef(fp)); - return fp; + fUsesDistanceVectorField |= fp->usesDistanceVectorField(); + fColorFragmentProcessors.push_back(std::move(fp)); } /** * Appends an additional coverage processor to the coverage computation. */ - const GrFragmentProcessor* addCoverageFragmentProcessor(const GrFragmentProcessor* fp) { + void addCoverageFragmentProcessor(sk_sp fp) { SkASSERT(fp); - fCoverageFragmentProcessors.push_back(SkRef(fp)); - return fp; + fUsesDistanceVectorField |= fp->usesDistanceVectorField(); + fCoverageFragmentProcessors.push_back(std::move(fp)); } /** * Helpers for adding color or coverage effects that sample a texture. The matrix is applied * to the src space position to compute texture coordinates. */ - void addColorTextureProcessor(GrTexture*, const SkMatrix&); + void addColorTextureProcessor(GrTexture*, sk_sp, const SkMatrix&); void addCoverageTextureProcessor(GrTexture*, const SkMatrix&); - void addColorTextureProcessor(GrTexture*, const SkMatrix&, const GrTextureParams&); + void addColorTextureProcessor(GrTexture*, sk_sp, const SkMatrix&, + const GrTextureParams&); void addCoverageTextureProcessor(GrTexture*, const SkMatrix&, const GrTextureParams&); int numColorFragmentProcessors() const { return fColorFragmentProcessors.count(); } @@ -113,34 +138,28 @@ public: int numTotalFragmentProcessors() const { return this->numColorFragmentProcessors() + this->numCoverageFragmentProcessors(); } - const GrXPFactory* getXPFactory() const { - return fXPFactory; + GrXPFactory* getXPFactory() const { + return fXPFactory.get(); } - const GrFragmentProcessor* getColorFragmentProcessor(int i) const { - return fColorFragmentProcessors[i]; + GrFragmentProcessor* getColorFragmentProcessor(int i) const { + return fColorFragmentProcessors[i].get(); } - const GrFragmentProcessor* getCoverageFragmentProcessor(int i) const { - return fCoverageFragmentProcessors[i]; + GrFragmentProcessor* getCoverageFragmentProcessor(int i) const { + return fCoverageFragmentProcessors[i].get(); } GrPaint& operator=(const GrPaint& paint) { fAntiAlias = paint.fAntiAlias; fDisableOutputConversionToSRGB = paint.fDisableOutputConversionToSRGB; fAllowSRGBInputs = paint.fAllowSRGBInputs; + fUsesDistanceVectorField = paint.fUsesDistanceVectorField; fColor = paint.fColor; - this->resetFragmentProcessors(); fColorFragmentProcessors = paint.fColorFragmentProcessors; fCoverageFragmentProcessors = paint.fCoverageFragmentProcessors; - for (int i = 0; i < fColorFragmentProcessors.count(); ++i) { - fColorFragmentProcessors[i]->ref(); - } - for (int i = 0; i < fCoverageFragmentProcessors.count(); ++i) { - fCoverageFragmentProcessors[i]->ref(); - } - fXPFactory.reset(SkSafeRef(paint.getXPFactory())); + fXPFactory = paint.fXPFactory; return *this; } @@ -151,29 +170,31 @@ public: * coverage and color, so the actual values written to pixels with partial coverage may still * not seem constant, even if this function returns true. */ - bool isConstantBlendedColor(GrColor* constantColor) const; - -private: - void resetFragmentProcessors() { - for (int i = 0; i < fColorFragmentProcessors.count(); ++i) { - fColorFragmentProcessors[i]->unref(); + bool isConstantBlendedColor(GrColor* constantColor) const { + GrColor paintColor = this->getColor(); + if (!fXPFactory && fColorFragmentProcessors.empty()) { + if (!GrColorIsOpaque(paintColor)) { + return false; + } + *constantColor = paintColor; + return true; } - for (int i = 0; i < fCoverageFragmentProcessors.count(); ++i) { - fCoverageFragmentProcessors[i]->unref(); - } - fColorFragmentProcessors.reset(); - fCoverageFragmentProcessors.reset(); + return this->internalIsConstantBlendedColor(paintColor, constantColor); } - mutable SkAutoTUnref fXPFactory; - SkSTArray<4, const GrFragmentProcessor*, true> fColorFragmentProcessors; - SkSTArray<2, const GrFragmentProcessor*, true> fCoverageFragmentProcessors; +private: + bool internalIsConstantBlendedColor(GrColor paintColor, GrColor* constantColor) const; - bool fAntiAlias; - bool fDisableOutputConversionToSRGB; - bool fAllowSRGBInputs; + mutable sk_sp fXPFactory; + SkSTArray<4, sk_sp> fColorFragmentProcessors; + SkSTArray<2, sk_sp> fCoverageFragmentProcessors; - GrColor fColor; + bool fAntiAlias; + bool fDisableOutputConversionToSRGB; + bool fAllowSRGBInputs; + bool fUsesDistanceVectorField; + + GrColor4f fColor; }; #endif diff --git a/gfx/skia/skia/include/gpu/GrProcessor.h b/gfx/skia/skia/include/gpu/GrProcessor.h index 3e892c6e3e25..d374a7f3d0e5 100644 --- a/gfx/skia/skia/include/gpu/GrProcessor.h +++ b/gfx/skia/skia/include/gpu/GrProcessor.h @@ -12,8 +12,10 @@ #include "GrProcessorUnitTest.h" #include "GrProgramElement.h" #include "GrTextureAccess.h" +#include "GrBufferAccess.h" #include "SkMath.h" #include "SkString.h" +#include "../private/SkAtomics.h" class GrContext; class GrCoordTransform; @@ -79,6 +81,14 @@ public: /** Shortcut for textureAccess(index).texture(); */ GrTexture* texture(int index) const { return this->textureAccess(index).getTexture(); } + int numBuffers() const { return fBufferAccesses.count(); } + + /** Returns the access pattern for the buffer at index. index must be valid according to + numBuffers(). */ + const GrBufferAccess& bufferAccess(int index) const { + return *fBufferAccesses[index]; + } + /** * Platform specific built-in features that a processor can request for the fragment shader. */ @@ -113,14 +123,16 @@ protected: GrProcessor() : fClassID(kIllegalProcessorClassID), fRequiredFeatures(kNone_RequiredFeatures) {} /** - * Subclasses call this from their constructor to register GrTextureAccesses. The processor - * subclass manages the lifetime of the accesses (this function only stores a pointer). The - * GrTextureAccess is typically a member field of the GrProcessor subclass. This must only be - * called from the constructor because GrProcessors are immutable. + * Subclasses call these from their constructor to register sampler sources. The processor + * subclass manages the lifetime of the objects (these functions only store pointers). The + * GrTextureAccess and/or GrBufferAccess instances are typically member fields of the + * GrProcessor subclass. These must only be called from the constructor because GrProcessors + * are immutable. */ virtual void addTextureAccess(const GrTextureAccess* textureAccess); + virtual void addBufferAccess(const GrBufferAccess* bufferAccess); - bool hasSameTextureAccesses(const GrProcessor&) const; + bool hasSameSamplers(const GrProcessor&) const; /** * If the prcoessor will generate code that uses platform specific built-in features, then it @@ -141,6 +153,7 @@ protected: uint32_t fClassID; SkSTArray<4, const GrTextureAccess*, true> fTextureAccesses; + SkSTArray<2, const GrBufferAccess*, true> fBufferAccesses; private: static uint32_t GenClassID() { diff --git a/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h b/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h index 8442d7ef715b..4f26665cbeac 100644 --- a/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h +++ b/gfx/skia/skia/include/gpu/GrProcessorUnitTest.h @@ -15,7 +15,7 @@ class SkMatrix; class GrCaps; class GrContext; -class GrRenderTarget; +class GrDrawContext; struct GrProcessorTestData; namespace GrProcessorUnitTest { @@ -28,7 +28,7 @@ enum { /** This allows parent FPs to implement a test create with known leaf children in order to avoid creating an unbounded FP tree which may overflow various shader limits. */ -const GrFragmentProcessor* CreateChildFP(GrProcessorTestData*); +sk_sp MakeChildFP(GrProcessorTestData*); } @@ -43,19 +43,19 @@ struct GrProcessorTestData { GrProcessorTestData(SkRandom* random, GrContext* context, const GrCaps* caps, - const GrRenderTarget* rt, + const GrDrawContext* drawContext, GrTexture* textures[2]) : fRandom(random) , fContext(context) , fCaps(caps) - , fRenderTarget(rt) { + , fDrawContext(drawContext) { fTextures[0] = textures[0]; fTextures[1] = textures[1]; } SkRandom* fRandom; GrContext* fContext; const GrCaps* fCaps; - const GrRenderTarget* fRenderTarget; + const GrDrawContext* fDrawContext; GrTexture* fTextures[2]; }; @@ -66,28 +66,28 @@ class GrTexture; template class GrProcessorTestFactory : SkNoncopyable { public: - typedef const Processor* (*CreateProc)(GrProcessorTestData*); + typedef sk_sp (*MakeProc)(GrProcessorTestData*); - GrProcessorTestFactory(CreateProc createProc) { - fCreateProc = createProc; + GrProcessorTestFactory(MakeProc makeProc) { + fMakeProc = makeProc; GetFactories()->push_back(this); } /** Pick a random factory function and create a processor. */ - static const Processor* Create(GrProcessorTestData* data) { + static sk_sp Make(GrProcessorTestData* data) { VerifyFactoryCount(); SkASSERT(GetFactories()->count()); uint32_t idx = data->fRandom->nextRangeU(0, GetFactories()->count() - 1); - return CreateIdx(idx, data); + return MakeIdx(idx, data); } /** Number of registered factory functions */ static int Count() { return GetFactories()->count(); } /** Use factory function at Index idx to create a processor. */ - static const Processor* CreateIdx(int idx, GrProcessorTestData* data) { + static sk_sp MakeIdx(int idx, GrProcessorTestData* data) { GrProcessorTestFactory* factory = (*GetFactories())[idx]; - return factory->fCreateProc(data); + return factory->fMakeProc(data); } /* @@ -96,7 +96,7 @@ public: static void VerifyFactoryCount(); private: - CreateProc fCreateProc; + MakeProc fMakeProc; static SkTArray*, true>* GetFactories(); }; @@ -106,15 +106,15 @@ private: */ #define GR_DECLARE_GEOMETRY_PROCESSOR_TEST \ static GrProcessorTestFactory gTestFactory SK_UNUSED; \ - static const GrGeometryProcessor* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) #define GR_DECLARE_FRAGMENT_PROCESSOR_TEST \ static GrProcessorTestFactory gTestFactory SK_UNUSED; \ - static const GrFragmentProcessor* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) #define GR_DECLARE_XP_FACTORY_TEST \ static GrProcessorTestFactory gTestFactory SK_UNUSED; \ - static const GrXPFactory* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) /** GrProcessor subclasses should insert this macro in their implementation file. They must then * also implement this static function: @@ -134,19 +134,19 @@ private: // The unit test relies on static initializers. Just declare the TestCreate function so that // its definitions will compile. #define GR_DECLARE_FRAGMENT_PROCESSOR_TEST \ - static const GrFragmentProcessor* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) #define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(X) // The unit test relies on static initializers. Just declare the TestCreate function so that // its definitions will compile. #define GR_DECLARE_XP_FACTORY_TEST \ - static const GrXPFactory* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) #define GR_DEFINE_XP_FACTORY_TEST(X) // The unit test relies on static initializers. Just declare the TestCreate function so that // its definitions will compile. #define GR_DECLARE_GEOMETRY_PROCESSOR_TEST \ - static const GrGeometryProcessor* TestCreate(GrProcessorTestData*) + static sk_sp TestCreate(GrProcessorTestData*) #define GR_DEFINE_GEOMETRY_PROCESSOR_TEST(X) #endif // !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS diff --git a/gfx/skia/skia/include/gpu/GrRenderTarget.h b/gfx/skia/skia/include/gpu/GrRenderTarget.h index d39d284bd825..1f87787d45dc 100644 --- a/gfx/skia/skia/include/gpu/GrRenderTarget.h +++ b/gfx/skia/skia/include/gpu/GrRenderTarget.h @@ -11,6 +11,7 @@ #include "GrSurface.h" #include "SkRect.h" +class GrCaps; class GrDrawTarget; class GrStencilAttachment; class GrRenderTargetPriv; @@ -29,66 +30,28 @@ public: const GrRenderTarget* asRenderTarget() const override { return this; } // GrRenderTarget - /** - * On some hardware it is possible for a render target to have multisampling - * only in certain buffers. - * Enforce only two legal sample configs. - * kUnified_SampleConfig signifies multisampling in both color and stencil - * buffers and is available across all hardware. - * kStencil_SampleConfig means multisampling is present in stencil buffer - * only; this config requires hardware support of - * NV_framebuffer_mixed_samples. - */ - enum SampleConfig { - kUnified_SampleConfig = 0, - kStencil_SampleConfig = 1 - }; + bool isStencilBufferMultisampled() const { return fDesc.fSampleCnt > 0; } /** - * @return true if the surface is multisampled in all buffers, - * false otherwise + * For our purposes, "Mixed Sampled" means the stencil buffer is multisampled but the color + * buffer is not. */ - bool isUnifiedMultisampled() const { - if (fSampleConfig != kUnified_SampleConfig) { - return false; - } - return 0 != fDesc.fSampleCnt; - } + bool isMixedSampled() const { return fFlags & Flags::kMixedSampled; } /** - * @return true if the surface is multisampled in the stencil buffer, - * false otherwise + * "Unified Sampled" means the stencil and color buffers are both multisampled. */ - bool isStencilBufferMultisampled() const { - return 0 != fDesc.fSampleCnt; - } + bool isUnifiedMultisampled() const { return fDesc.fSampleCnt > 0 && !this->isMixedSampled(); } /** - * @return the number of color samples-per-pixel, or zero if non-MSAA or - * multisampled in the stencil buffer only. + * Returns the number of samples/pixel in the stencil buffer (Zero if non-MSAA). */ - int numColorSamples() const { - if (fSampleConfig == kUnified_SampleConfig) { - return fDesc.fSampleCnt; - } - return 0; - } + int numStencilSamples() const { return fDesc.fSampleCnt; } /** - * @return the number of stencil samples-per-pixel, or zero if non-MSAA. + * Returns the number of samples/pixel in the color buffer (Zero if non-MSAA or mixed sampled). */ - int numStencilSamples() const { - return fDesc.fSampleCnt; - } - - /** - * @return true if the surface is mixed sampled, false otherwise. - */ - bool hasMixedSamples() const { - SkASSERT(kStencil_SampleConfig != fSampleConfig || - this->isStencilBufferMultisampled()); - return kStencil_SampleConfig == fSampleConfig; - } + int numColorSamples() const { return this->isMixedSampled() ? 0 : fDesc.fSampleCnt; } /** * Call to indicate the multisample contents were modified such that the @@ -156,15 +119,16 @@ public: GrDrawTarget* getLastDrawTarget() { return fLastDrawTarget; } protected: - GrRenderTarget(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc, - SampleConfig sampleConfig, GrStencilAttachment* stencil = nullptr) - : INHERITED(gpu, lifeCycle, desc) - , fStencilAttachment(stencil) - , fSampleConfig(sampleConfig) - , fLastDrawTarget(nullptr) { - fResolveRect.setLargestInverted(); - } + enum class Flags { + kNone = 0, + kMixedSampled = 1 << 0, + kWindowRectsSupport = 1 << 1 + }; + GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags); + + GrRenderTarget(GrGpu*, const GrSurfaceDesc&, Flags = Flags::kNone, + GrStencilAttachment* = nullptr); ~GrRenderTarget() override; // override of GrResource @@ -181,7 +145,8 @@ private: friend class GrRenderTargetPriv; GrStencilAttachment* fStencilAttachment; - SampleConfig fSampleConfig; + uint8_t fMultisampleSpecsID; + Flags fFlags; SkIRect fResolveRect; @@ -196,5 +161,6 @@ private: typedef GrSurface INHERITED; }; +GR_MAKE_BITFIELD_CLASS_OPS(GrRenderTarget::Flags); #endif diff --git a/gfx/skia/skia/include/gpu/GrResourceKey.h b/gfx/skia/skia/include/gpu/GrResourceKey.h index ff83a4310448..0ead35ea3f79 100644 --- a/gfx/skia/skia/include/gpu/GrResourceKey.h +++ b/gfx/skia/skia/include/gpu/GrResourceKey.h @@ -71,7 +71,7 @@ protected: /** 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(); @@ -238,7 +238,7 @@ public: GrUniqueKey& operator=(const GrUniqueKey& that) { this->INHERITED::operator=(that); - this->setCustomData(that.getCustomData()); + this->setCustomData(sk_ref_sp(that.getCustomData())); return *this; } @@ -247,11 +247,10 @@ public: } bool operator!=(const GrUniqueKey& that) const { return !(*this == that); } - void setCustomData(const SkData* data) { - SkSafeRef(data); - fData.reset(data); + void setCustomData(sk_sp data) { + fData = std::move(data); } - const SkData* getCustomData() const { + SkData* getCustomData() const { return fData.get(); } @@ -280,7 +279,7 @@ public: }; private: - SkAutoTUnref fData; + sk_sp fData; }; /** @@ -290,12 +289,12 @@ private: */ /** Place outside of function/class definitions. */ -#define GR_DECLARE_STATIC_UNIQUE_KEY(name) SK_DECLARE_STATIC_ONCE(name##_once) +#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; \ - SkOnce(&name##_once, gr_init_static_unique_key_once, &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) { diff --git a/gfx/skia/skia/include/gpu/GrShaderVar.h b/gfx/skia/skia/include/gpu/GrShaderVar.h index 3f56eaf70acb..78e08e0d9ab6 100644 --- a/gfx/skia/skia/include/gpu/GrShaderVar.h +++ b/gfx/skia/skia/include/gpu/GrShaderVar.h @@ -51,7 +51,6 @@ public: , fName(name) , fCount(arrayCount) , fPrecision(precision) { - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type)); SkASSERT(kVoid_GrSLType != type); } @@ -62,7 +61,6 @@ public: , fName(name) , fCount(arrayCount) , fPrecision(precision) { - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type)); SkASSERT(kVoid_GrSLType != type); } @@ -73,7 +71,6 @@ public: , fName(name) , fCount(arrayCount) , fPrecision(precision) { - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type)); SkASSERT(kVoid_GrSLType != type); } @@ -91,7 +88,6 @@ public: GrSLPrecision precision = kDefault_GrSLPrecision, int count = kNonArray) { SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type)); fType = type; fTypeModifier = typeModifier; fName = name; @@ -105,7 +101,6 @@ public: GrSLPrecision precision = kDefault_GrSLPrecision, int count = kNonArray) { SkASSERT(kVoid_GrSLType != type); - SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsNumeric(type)); fType = type; fTypeModifier = typeModifier; fName = name; diff --git a/gfx/skia/skia/include/gpu/GrSurface.h b/gfx/skia/skia/include/gpu/GrSurface.h index b59d802f328c..ac5c5fa1bbcd 100644 --- a/gfx/skia/skia/include/gpu/GrSurface.h +++ b/gfx/skia/skia/include/gpu/GrSurface.h @@ -33,8 +33,7 @@ public: /** * Helper that gets the width and height of the surface as a bounding rectangle. */ - void getBoundsRect(SkRect* rect) const { rect->setWH(SkIntToScalar(this->width()), - SkIntToScalar(this->height())); } + SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); } GrSurfaceOrigin origin() const { SkASSERT(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin || kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin); @@ -100,7 +99,7 @@ public: * packed. * @param pixelOpsFlags See the GrContext::PixelOpsFlags enum. * - * @return true if the read succeeded, false if not. The read can fail because of an + * @return true if the write succeeded, false if not. The write can fail because of an * unsupported pixel config. */ bool writePixels(int left, int top, int width, int height, @@ -114,13 +113,6 @@ public: */ void flushWrites(); - - /** - * After this returns any pending surface IO will be issued to the backend 3D API and - * if the surface has MSAA it will be resolved. - */ - void prepareForExternalIO(); - /** Access methods that are only to be used within Skia code. */ inline GrSurfacePriv surfacePriv(); inline const GrSurfacePriv surfacePriv() const; @@ -133,11 +125,10 @@ public: fReleaseCtx = ctx; } - static size_t WorseCaseSize(const GrSurfaceDesc& desc); + static size_t WorstCaseSize(const GrSurfaceDesc& desc); protected: // Methods made available via GrSurfacePriv - SkImageInfo info(SkAlphaType) const; bool savePixels(const char* filename); bool hasPendingRead() const; bool hasPendingWrite() const; @@ -146,8 +137,8 @@ protected: // Provides access to methods that should be public within Skia code. friend class GrSurfacePriv; - GrSurface(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc) - : INHERITED(gpu, lifeCycle) + GrSurface(GrGpu* gpu, const GrSurfaceDesc& desc) + : INHERITED(gpu) , fDesc(desc) , fReleaseProc(NULL) , fReleaseCtx(NULL) diff --git a/gfx/skia/skia/include/gpu/GrTestUtils.h b/gfx/skia/skia/include/gpu/GrTestUtils.h index 475e38a6a11d..17bf12af30cc 100644 --- a/gfx/skia/skia/include/gpu/GrTestUtils.h +++ b/gfx/skia/skia/include/gpu/GrTestUtils.h @@ -13,10 +13,13 @@ #ifdef GR_TEST_UTILS #include "GrColor.h" +#include "GrColorSpaceXform.h" +#include "SkPathEffect.h" #include "SkRandom.h" #include "SkStrokeRec.h" +#include "../private/SkTemplates.h" -class GrStrokeInfo; +class GrStyle; class SkMatrix; class SkPath; class SkRRect; @@ -24,21 +27,49 @@ struct SkRect; namespace GrTest { /** - * A helper for use in Test functions. + * Helpers for use in Test functions. */ const SkMatrix& TestMatrix(SkRandom*); const SkMatrix& TestMatrixPreservesRightAngles(SkRandom*); const SkMatrix& TestMatrixRectStaysRect(SkRandom*); const SkMatrix& TestMatrixInvertible(SkRandom*); +const SkMatrix& TestMatrixPerspective(SkRandom*); const SkRect& TestRect(SkRandom*); const SkRect& TestSquare(SkRandom*); const SkRRect& TestRRectSimple(SkRandom*); const SkPath& TestPath(SkRandom*); const SkPath& TestPathConvex(SkRandom*); SkStrokeRec TestStrokeRec(SkRandom*); -GrStrokeInfo TestStrokeInfo(SkRandom*); +/** Creates styles with dash path effects and null path effects */ +void TestStyle(SkRandom*, GrStyle*); +sk_sp TestColorSpace(SkRandom*); +sk_sp TestColorXform(SkRandom*); -} +// We have a simplified dash path effect here to avoid relying on SkDashPathEffect which +// is in the optional build target effects. +class TestDashPathEffect : public SkPathEffect { +public: + static sk_sp Make(const SkScalar* intervals, int count, SkScalar phase) { + return sk_sp(new TestDashPathEffect(intervals, count, phase)); + } + + bool filterPath(SkPath* dst, const SkPath&, SkStrokeRec* , const SkRect*) const override; + DashType asADash(DashInfo* info) const override; + Factory getFactory() const override { return nullptr; } + void toString(SkString*) const override {} + +private: + TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase); + + int fCount; + SkAutoTArray fIntervals; + SkScalar fPhase; + SkScalar fInitialDashLength; + int fInitialDashIndex; + SkScalar fIntervalLength; +}; + +} // namespace GrTest static inline GrColor GrRandomColor(SkRandom* random) { // There are only a few cases of random colors which interest us diff --git a/gfx/skia/skia/include/gpu/GrTexture.h b/gfx/skia/skia/include/gpu/GrTexture.h index 1d589eddcef3..211f1937da72 100644 --- a/gfx/skia/skia/include/gpu/GrTexture.h +++ b/gfx/skia/skia/include/gpu/GrTexture.h @@ -46,11 +46,12 @@ public: inline const GrTexturePriv texturePriv() const; protected: - GrTexture(GrGpu*, LifeCycle, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided); + GrTexture(GrGpu*, const GrSurfaceDesc&, GrSLType, bool wasMipMapDataProvided); void validateDesc() const; private: + void computeScratchKey(GrScratchKey*) const override; size_t onGpuMemorySize() const override; void dirtyMipMaps(bool mipMapsDirty); @@ -60,9 +61,10 @@ private: kValid_MipMapsStatus }; - GrSLType fSamplerType; - MipMapsStatus fMipMapsStatus; - int fMaxMipMapLevel; + GrSLType fSamplerType; + MipMapsStatus fMipMapsStatus; + int fMaxMipMapLevel; + SkSourceGammaTreatment fGammaTreatment; friend class GrTexturePriv; diff --git a/gfx/skia/skia/include/gpu/GrTextureAccess.h b/gfx/skia/skia/include/gpu/GrTextureAccess.h index 237485a9e279..1b5de0ce99cc 100644 --- a/gfx/skia/skia/include/gpu/GrTextureAccess.h +++ b/gfx/skia/skia/include/gpu/GrTextureAccess.h @@ -30,30 +30,25 @@ public: explicit GrTextureAccess(GrTexture*, GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, - GrShaderFlags visibility = kFragment_GrShaderFlag, - GrSLPrecision = kDefault_GrSLPrecision); + GrShaderFlags visibility = kFragment_GrShaderFlag); void reset(GrTexture*, const GrTextureParams&, - GrShaderFlags visibility = kFragment_GrShaderFlag, - GrSLPrecision = kDefault_GrSLPrecision); + GrShaderFlags visibility = kFragment_GrShaderFlag); void reset(GrTexture*, GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode, SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode, - GrShaderFlags visibility = kFragment_GrShaderFlag, - GrSLPrecision = kDefault_GrSLPrecision); + GrShaderFlags visibility = kFragment_GrShaderFlag); bool operator==(const GrTextureAccess& that) const { return this->getTexture() == that.getTexture() && fParams == that.fParams && - fVisibility == that.fVisibility && - fPrecision == that.fPrecision; + fVisibility == that.fVisibility; } bool operator!=(const GrTextureAccess& other) const { return !(*this == other); } GrTexture* getTexture() const { return fTexture.get(); } GrShaderFlags getVisibility() const { return fVisibility; } - GrSLPrecision getPrecision() const { return fPrecision; } /** * For internal use by GrProcessor. @@ -69,7 +64,6 @@ private: ProgramTexture fTexture; GrTextureParams fParams; GrShaderFlags fVisibility; - GrSLPrecision fPrecision; typedef SkNoncopyable INHERITED; }; diff --git a/gfx/skia/skia/include/gpu/GrTextureParams.h b/gfx/skia/skia/include/gpu/GrTextureParams.h index 40d9ac537504..3186b1b02718 100644 --- a/gfx/skia/skia/include/gpu/GrTextureParams.h +++ b/gfx/skia/skia/include/gpu/GrTextureParams.h @@ -24,11 +24,6 @@ public: static const GrTextureParams gParams(SkShader::kClamp_TileMode, kBilerp_FilterMode); return gParams; } - static const GrTextureParams& ClampNoFilterForceAllowSRGB() { - static const GrTextureParams gParams(SkShader::kClamp_TileMode, kNone_FilterMode, - kForceAllowSRGB_SRGBMode); - return gParams; - } GrTextureParams() { this->reset(); @@ -40,19 +35,10 @@ public: kMipMap_FilterMode }; - enum SRGBMode { - kRespectDestination_SRGBMode, - kForceAllowSRGB_SRGBMode, - }; - GrTextureParams(SkShader::TileMode tileXAndY, FilterMode filterMode) { this->reset(tileXAndY, filterMode); } - GrTextureParams(SkShader::TileMode tileXandY, FilterMode filterMode, SRGBMode srgbMode) { - this->reset(tileXandY, filterMode, srgbMode); - } - GrTextureParams(const SkShader::TileMode tileModes[2], FilterMode filterMode) { this->reset(tileModes, filterMode); } @@ -65,7 +51,6 @@ public: fTileModes[0] = params.fTileModes[0]; fTileModes[1] = params.fTileModes[1]; fFilterMode = params.fFilterMode; - fSRGBMode = params.fSRGBMode; return *this; } @@ -76,20 +61,12 @@ public: void reset(SkShader::TileMode tileXAndY, FilterMode filterMode) { fTileModes[0] = fTileModes[1] = tileXAndY; fFilterMode = filterMode; - fSRGBMode = kRespectDestination_SRGBMode; - } - - void reset(SkShader::TileMode tileXandY, FilterMode filterMode, SRGBMode srgbMode) { - fTileModes[0] = fTileModes[1] = tileXandY; - fFilterMode = filterMode; - fSRGBMode = srgbMode; } void reset(const SkShader::TileMode tileModes[2], FilterMode filterMode) { fTileModes[0] = tileModes[0]; fTileModes[1] = tileModes[1]; fFilterMode = filterMode; - fSRGBMode = kRespectDestination_SRGBMode; } void setClampNoFilter() { @@ -107,8 +84,6 @@ public: void setTileModeY(const SkShader::TileMode tm) { fTileModes[1] = tm; } void setTileModeXAndY(const SkShader::TileMode tm) { fTileModes[0] = fTileModes[1] = tm; } - void setSRGBMode(SRGBMode srgbMode) { fSRGBMode = srgbMode; } - SkShader::TileMode getTileModeX() const { return fTileModes[0]; } SkShader::TileMode getTileModeY() const { return fTileModes[1]; } @@ -120,13 +95,10 @@ public: FilterMode filterMode() const { return fFilterMode; } - SRGBMode srgbMode() const { return fSRGBMode; } - bool operator== (const GrTextureParams& other) const { return fTileModes[0] == other.fTileModes[0] && fTileModes[1] == other.fTileModes[1] && - fFilterMode == other.fFilterMode && - fSRGBMode == other.fSRGBMode; + fFilterMode == other.fFilterMode; } bool operator!= (const GrTextureParams& other) const { return !(*this == other); } @@ -134,6 +106,5 @@ public: private: SkShader::TileMode fTileModes[2]; FilterMode fFilterMode; - SRGBMode fSRGBMode; }; #endif diff --git a/gfx/skia/skia/include/gpu/GrTextureProvider.h b/gfx/skia/skia/include/gpu/GrTextureProvider.h index 7c12ebd6db36..e013bfff0fa7 100644 --- a/gfx/skia/skia/include/gpu/GrTextureProvider.h +++ b/gfx/skia/skia/include/gpu/GrTextureProvider.h @@ -10,7 +10,6 @@ #include "GrTexture.h" #include "GrTypes.h" -#include "SkImageFilter.h" class GrSingleOwner; diff --git a/gfx/skia/skia/include/gpu/GrTypes.h b/gfx/skia/skia/include/gpu/GrTypes.h index 47c13ec02d91..6b73f3c073de 100644 --- a/gfx/skia/skia/include/gpu/GrTypes.h +++ b/gfx/skia/skia/include/gpu/GrTypes.h @@ -49,6 +49,27 @@ \ template \ friend X operator & (X a, T b); \ + +/** + * Defines bitwise operators that make it possible to use an enum class as a + * very basic bitfield. + */ +#define GR_MAKE_BITFIELD_CLASS_OPS(X) \ + inline X operator | (X a, X b) { \ + return (X) ((int)a | (int)b); \ + } \ + inline X& operator |= (X& a, X b) { \ + return (a = a | b); \ + } \ + inline bool operator & (X a, X b) { \ + return SkToBool((int)a & (int)b); \ + } + +#define GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(X) \ + friend X operator | (X a, X b); \ + friend X& operator |= (X& a, X b); \ + friend bool operator & (X a, X b); + //////////////////////////////////////////////////////////////////////////////// // compile time versions of min/max @@ -107,20 +128,6 @@ static inline size_t GrSizeAlignDown(size_t x, uint32_t alignment) { /////////////////////////////////////////////////////////////////////////////// -/** - * Return the next power of 2 >= n. - */ -static inline uint32_t GrNextPow2(uint32_t n) { - return n ? (1 << (32 - SkCLZ(n - 1))) : 1; -} - -static inline int GrNextPow2(int n) { - SkASSERT(n >= 0); // this impl only works for non-neg. - return n ? (1 << (32 - SkCLZ(n - 1))) : 1; -} - -/////////////////////////////////////////////////////////////////////////////// - /** * Possible 3D APIs that may be used by Ganesh. */ @@ -135,6 +142,7 @@ const int kBackendCount = kLast_GrBackend + 1; /** * Backend-specific 3D context handle * GrGLInterface* for OpenGL. If NULL will use the default GL interface. + * GrVkBackendContext* for Vulkan. */ typedef intptr_t GrBackendContext; @@ -399,6 +407,17 @@ static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) { } } +static inline bool GrPixelConfigIsFloatingPoint(GrPixelConfig config) { + switch (config) { + case kRGBA_float_GrPixelConfig: + case kAlpha_half_GrPixelConfig: + case kRGBA_half_GrPixelConfig: + return true; + default: + return false; + } +} + /** * Optional bitfield flags that can be set on GrSurfaceDesc (below). */ @@ -443,58 +462,6 @@ struct GrMipLevel { size_t fRowBytes; }; -/** - * An container of function pointers which consumers of Skia can fill in and - * pass to Skia. Skia will use these function pointers in place of its backend - * API texture creation function. Either all of the function pointers should be - * filled in, or they should all be nullptr. - */ -struct GrTextureStorageAllocator { - GrTextureStorageAllocator() - : fAllocateTextureStorage(nullptr) - , fDeallocateTextureStorage(nullptr) { - } - - enum class Result { - kSucceededAndUploaded, - kSucceededWithoutUpload, - kFailed - }; - typedef Result (*AllocateTextureStorageProc)( - void* ctx, GrBackendObject texture, unsigned width, - unsigned height, GrPixelConfig config, const void* srcData, GrSurfaceOrigin); - typedef void (*DeallocateTextureStorageProc)(void* ctx, GrBackendObject texture); - - /* - * Generates and binds a texture to |textureStorageTarget()|. Allocates - * storage for the texture. - * - * In OpenGL, the MIN and MAX filters for the created texture must be - * GL_LINEAR. The WRAP_S and WRAP_T must be GL_CLAMP_TO_EDGE. - * - * If |srcData| is not nullptr, then the implementation of this function - * may attempt to upload the data into the texture. On successful upload, - * or if |srcData| is nullptr, returns kSucceededAndUploaded. - */ - AllocateTextureStorageProc fAllocateTextureStorage; - - /* - * Deallocate the storage for the given texture. - * - * Skia does not always destroy its outstanding textures. See - * GrContext::abandonContext() for more details. The consumer of Skia is - * responsible for making sure that all textures are destroyed, even if this - * callback is not invoked. - */ - DeallocateTextureStorageProc fDeallocateTextureStorage; - - /* - * The context to use when invoking fAllocateTextureStorage and - * fDeallocateTextureStorage. - */ - void* fCtx; -}; - /** * Describes a surface to be created. */ @@ -528,13 +495,6 @@ struct GrSurfaceDesc { * max supported count. */ int fSampleCnt; - - /** - * A custom platform-specific allocator to use in place of the backend APIs - * usual texture creation method (e.g. TexImage2D in OpenGL). - */ - GrTextureStorageAllocator fTextureStorageAllocator; - bool fIsMipMapped; //!< Indicates if the texture has mipmaps }; @@ -610,6 +570,7 @@ struct GrBackendTextureDesc { /** * Handle to the 3D API object. * OpenGL: Texture ID. + * Vulkan: GrVkImageInfo* */ GrBackendObject fTextureHandle; }; @@ -644,6 +605,7 @@ struct GrBackendRenderTargetDesc { /** * Handle to the 3D API object. * OpenGL: FBO ID + * Vulkan: GrVkImageInfo* */ GrBackendObject fRenderTargetHandle; }; diff --git a/gfx/skia/skia/include/gpu/GrTypesPriv.h b/gfx/skia/skia/include/gpu/GrTypesPriv.h index 39386f0140a7..636e72a019af 100644 --- a/gfx/skia/skia/include/gpu/GrTypesPriv.h +++ b/gfx/skia/skia/include/gpu/GrTypesPriv.h @@ -9,7 +9,7 @@ #define GrTypesPriv_DEFINED #include "GrTypes.h" -#include "SkRect.h" +#include "SkRefCnt.h" /** * Types of shader-language-specific boxed variables we can create. (Currently only GrGLShaderVars, @@ -24,14 +24,17 @@ enum GrSLType { kMat22f_GrSLType, kMat33f_GrSLType, kMat44f_GrSLType, - kSampler2D_GrSLType, - kSamplerExternal_GrSLType, - kSampler2DRect_GrSLType, + kTexture2DSampler_GrSLType, + kTextureExternalSampler_GrSLType, + kTexture2DRectSampler_GrSLType, + kTextureBufferSampler_GrSLType, kBool_GrSLType, kInt_GrSLType, kUint_GrSLType, + kTexture2D_GrSLType, + kSampler_GrSLType, - kLast_GrSLType = kUint_GrSLType + kLast_GrSLType = kSampler_GrSLType }; static const int kGrSLTypeCount = kLast_GrSLType + 1; @@ -52,6 +55,14 @@ enum GrShaderFlags { }; GR_MAKE_BITFIELD_OPS(GrShaderFlags); +enum class GrDrawFace { + kInvalid = -1, + + kBoth, + kCCW, + kCW, +}; + /** * 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 ( @@ -76,7 +87,7 @@ static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1; */ static inline int GrSLTypeVectorCount(GrSLType type) { SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, 1, 1, 1 }; + static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1 }; return kCounts[type]; GR_STATIC_ASSERT(0 == kVoid_GrSLType); @@ -87,12 +98,15 @@ static inline int GrSLTypeVectorCount(GrSLType type) { GR_STATIC_ASSERT(5 == kMat22f_GrSLType); GR_STATIC_ASSERT(6 == kMat33f_GrSLType); GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kSampler2D_GrSLType); - GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType); - GR_STATIC_ASSERT(11 == kBool_GrSLType); - GR_STATIC_ASSERT(12 == kInt_GrSLType); - GR_STATIC_ASSERT(13 == kUint_GrSLType); + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); + GR_STATIC_ASSERT(12 == kBool_GrSLType); + GR_STATIC_ASSERT(13 == kInt_GrSLType); + GR_STATIC_ASSERT(14 == kUint_GrSLType); + GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); + GR_STATIC_ASSERT(16 == kSampler_GrSLType); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrSLTypeCount); } @@ -121,19 +135,22 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) { GR_STATIC_ASSERT(5 == kMat22f_GrSLType); GR_STATIC_ASSERT(6 == kMat33f_GrSLType); GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kSampler2D_GrSLType); - GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType); - GR_STATIC_ASSERT(11 == kBool_GrSLType); - GR_STATIC_ASSERT(12 == kInt_GrSLType); - GR_STATIC_ASSERT(13 == kUint_GrSLType); - GR_STATIC_ASSERT(14 == kGrSLTypeCount); + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); + GR_STATIC_ASSERT(12 == kBool_GrSLType); + GR_STATIC_ASSERT(13 == kInt_GrSLType); + GR_STATIC_ASSERT(14 == kUint_GrSLType); + GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); + GR_STATIC_ASSERT(16 == kSampler_GrSLType); + GR_STATIC_ASSERT(17 == kGrSLTypeCount); } /** Is the shading language type integral (including vectors/matrices)? */ static inline bool GrSLTypeIsIntType(GrSLType type) { SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kInt_GrSLType; + return type >= kInt_GrSLType && type <= kUint_GrSLType; GR_STATIC_ASSERT(0 == kVoid_GrSLType); GR_STATIC_ASSERT(1 == kFloat_GrSLType); @@ -143,13 +160,16 @@ static inline bool GrSLTypeIsIntType(GrSLType type) { GR_STATIC_ASSERT(5 == kMat22f_GrSLType); GR_STATIC_ASSERT(6 == kMat33f_GrSLType); GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kSampler2D_GrSLType); - GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType); - GR_STATIC_ASSERT(11 == kBool_GrSLType); - GR_STATIC_ASSERT(12 == kInt_GrSLType); - GR_STATIC_ASSERT(13 == kUint_GrSLType); - GR_STATIC_ASSERT(14 == kGrSLTypeCount); + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); + GR_STATIC_ASSERT(12 == kBool_GrSLType); + GR_STATIC_ASSERT(13 == kInt_GrSLType); + GR_STATIC_ASSERT(14 == kUint_GrSLType); + GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); + GR_STATIC_ASSERT(16 == kSampler_GrSLType); + GR_STATIC_ASSERT(17 == kGrSLTypeCount); } /** Is the shading language type numeric (including vectors/matrices)? */ @@ -169,12 +189,15 @@ static inline size_t GrSLTypeSize(GrSLType type) { 2 * 2 * sizeof(float), // kMat22f_GrSLType 3 * 3 * sizeof(float), // kMat33f_GrSLType 4 * 4 * sizeof(float), // kMat44f_GrSLType - 0, // kSampler2D_GrSLType - 0, // kSamplerExternal_GrSLType - 0, // kSampler2DRect_GrSLType + 0, // kTexture2DSampler_GrSLType + 0, // kTextureExternalSampler_GrSLType + 0, // kTexture2DRectSampler_GrSLType + 0, // kTextureBufferSampler_GrSLType 0, // kBool_GrSLType 0, // kInt_GrSLType 0, // kUint_GrSLType + 0, // kTexture2D_GrSLType + 0, // kSampler_GrSLType }; return kSizes[type]; @@ -186,26 +209,39 @@ static inline size_t GrSLTypeSize(GrSLType type) { GR_STATIC_ASSERT(5 == kMat22f_GrSLType); GR_STATIC_ASSERT(6 == kMat33f_GrSLType); GR_STATIC_ASSERT(7 == kMat44f_GrSLType); - GR_STATIC_ASSERT(8 == kSampler2D_GrSLType); - GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType); - GR_STATIC_ASSERT(11 == kBool_GrSLType); - GR_STATIC_ASSERT(12 == kInt_GrSLType); - GR_STATIC_ASSERT(13 == kUint_GrSLType); - GR_STATIC_ASSERT(14 == kGrSLTypeCount); + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); + GR_STATIC_ASSERT(12 == kBool_GrSLType); + GR_STATIC_ASSERT(13 == kInt_GrSLType); + GR_STATIC_ASSERT(14 == kUint_GrSLType); + GR_STATIC_ASSERT(15 == kTexture2D_GrSLType); + GR_STATIC_ASSERT(16 == kSampler_GrSLType); + GR_STATIC_ASSERT(17 == kGrSLTypeCount); } -static inline bool GrSLTypeIsSamplerType(GrSLType type) { +static inline bool GrSLTypeIs2DCombinedSamplerType(GrSLType type) { SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); - return type >= kSampler2D_GrSLType && type <= kSampler2DRect_GrSLType; + return type >= kTexture2DSampler_GrSLType && type <= kTexture2DRectSampler_GrSLType; - GR_STATIC_ASSERT(8 == kSampler2D_GrSLType); - GR_STATIC_ASSERT(9 == kSamplerExternal_GrSLType); - GR_STATIC_ASSERT(10 == kSampler2DRect_GrSLType); + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); +} + +static inline bool GrSLTypeIsCombinedSamplerType(GrSLType type) { + SkASSERT(type >= 0 && type < static_cast(kGrSLTypeCount)); + return type >= kTexture2DSampler_GrSLType && type <= kTextureBufferSampler_GrSLType; + + GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType); + GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType); + GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType); + GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType); } static inline bool GrSLTypeAcceptsPrecision(GrSLType type) { - return GrSLTypeIsNumeric(type) || GrSLTypeIsSamplerType(type); + return type != kVoid_GrSLType && type != kBool_GrSLType; } ////////////////////////////////////////////////////////////////////////////// @@ -226,7 +262,7 @@ enum GrVertexAttribType { kInt_GrVertexAttribType, kUint_GrVertexAttribType, - + kLast_GrVertexAttribType = kUint_GrVertexAttribType }; static const int kGrVertexAttribTypeCount = kLast_GrVertexAttribType + 1; @@ -383,23 +419,6 @@ enum GrIOType { kRW_GrIOType }; -struct GrScissorState { - GrScissorState() : fEnabled(false) {} - void set(const SkIRect& rect) { fRect = rect; fEnabled = true; } - bool operator==(const GrScissorState& other) const { - return fEnabled == other.fEnabled && - (false == fEnabled || fRect == other.fRect); - } - bool operator!=(const GrScissorState& other) const { return !(*this == other); } - - bool enabled() const { return fEnabled; } - const SkIRect& rect() const { return fRect; } - -private: - bool fEnabled; - SkIRect fRect; -}; - /** * Indicates the type of data that a GPU buffer will be used for. */ @@ -448,4 +467,24 @@ enum GrAccessPattern { #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 * sk_sp_address_as_pointer_address(sk_sp const * sp) { + static_assert(sizeof(T*) == sizeof(sk_sp), "sk_sp not expected size."); + return reinterpret_cast(sp); +} + +/* + * Object for CPU-GPU synchronization + */ +typedef intptr_t GrFence; + #endif diff --git a/gfx/skia/skia/include/gpu/GrXferProcessor.h b/gfx/skia/skia/include/gpu/GrXferProcessor.h index 3a698143c323..1d4717e1569d 100644 --- a/gfx/skia/skia/include/gpu/GrXferProcessor.h +++ b/gfx/skia/skia/include/gpu/GrXferProcessor.h @@ -323,8 +323,7 @@ public: virtual void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, InvariantBlendedColor*) const = 0; - bool willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations, - bool hasMixedSamples) const; + bool willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations) const; bool isEqual(const GrXPFactory& that) const { if (this->classID() != that.classID()) { @@ -358,16 +357,12 @@ private: virtual bool onIsEqual(const GrXPFactory&) const = 0; - bool willReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples) const; + bool willReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const; /** * Returns true if the XP generated by this factory will explicitly read dst in the fragment * shader. */ - virtual bool onWillReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples) const = 0; + virtual bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const = 0; static uint32_t GenClassID() { // fCurrXPFactoryID has been initialized to kIllegalXPFactoryID. The diff --git a/gfx/skia/skia/include/gpu/SkGr.h b/gfx/skia/skia/include/gpu/SkGr.h index 6a73636c6904..43d61e250bcb 100644 --- a/gfx/skia/skia/include/gpu/SkGr.h +++ b/gfx/skia/skia/include/gpu/SkGr.h @@ -16,6 +16,7 @@ #include "SkImageInfo.h" class GrCaps; +class GrColorSpaceXform; class GrContext; class GrTexture; class GrTextureParams; @@ -41,6 +42,9 @@ static inline GrColor SkColorToUnpremulGrColor(SkColor c) { return GrColorPackRGBA(r, g, b, a); } +GrColor4f SkColorToPremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform); +GrColor4f SkColorToUnpremulGrColor4f(SkColor c, bool gammaCorrect, GrColorSpaceXform* gamutXform); + static inline GrColor SkColorToOpaqueGrColor(SkColor c) { unsigned r = SkColorGetR(c); unsigned g = SkColorGetG(c); @@ -68,13 +72,18 @@ static inline GrColor SkPMColorToGrColor(SkPMColor c) { /** Returns a texture representing the bitmap that is compatible with the GrTextureParams. The texture is inserted into the cache (unless the bitmap is marked volatile) and can be retrieved again via this function. */ -GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&); +GrTexture* GrRefCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&, + SkSourceGammaTreatment); + +sk_sp GrMakeCachedBitmapTexture(GrContext*, const SkBitmap&, const GrTextureParams&, + SkSourceGammaTreatment); // TODO: Move SkImageInfo2GrPixelConfig to SkGrPriv.h (requires cleanup to SkWindow its subclasses). -GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType, SkAlphaType, SkColorProfileType, const GrCaps&); +GrPixelConfig SkImageInfo2GrPixelConfig(SkColorType, SkAlphaType, const SkColorSpace*, + const GrCaps&); static inline GrPixelConfig SkImageInfo2GrPixelConfig(const SkImageInfo& info, const GrCaps& caps) { - return SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(), info.profileType(), caps); + return SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(), info.colorSpace(), caps); } GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality, @@ -82,12 +91,4 @@ GrTextureParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality pain const SkMatrix& localM, bool* doBicubic); -//////////////////////////////////////////////////////////////////////////////// - -SkImageInfo GrMakeInfoFromTexture(GrTexture* tex, int w, int h, bool isOpaque); - -// Using the dreaded SkGrPixelRef ... -SK_API void GrWrapTextureInBitmap(GrTexture* src, int w, int h, bool isOpaque, - SkBitmap* dst); - #endif diff --git a/gfx/skia/skia/include/gpu/SkGrPixelRef.h b/gfx/skia/skia/include/gpu/SkGrPixelRef.h deleted file mode 100644 index b4dbd9d73f3b..000000000000 --- a/gfx/skia/skia/include/gpu/SkGrPixelRef.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 SkGrPixelRef_DEFINED -#define SkGrPixelRef_DEFINED - -#include "SkBitmap.h" -#include "SkPixelRef.h" -#include "GrTexture.h" -#include "GrRenderTarget.h" - - -/** - * Common baseclass that implements onLockPixels() by calling onReadPixels(). - * Since it has a copy, it always returns false for onLockPixelsAreWritable(). - */ -class SK_API SkROLockPixelsPixelRef : public SkPixelRef { -public: - SkROLockPixelsPixelRef(const SkImageInfo&); - virtual ~SkROLockPixelsPixelRef(); - -protected: - bool onNewLockPixels(LockRec*) override; - void onUnlockPixels() override; - bool onLockPixelsAreWritable() const override; // return false; - -private: - SkBitmap fBitmap; - typedef SkPixelRef INHERITED; -}; - -/** - * PixelRef that wraps a GrSurface - */ -class SK_API SkGrPixelRef : public SkROLockPixelsPixelRef { -public: - /** - * Constructs a pixel ref around a GrSurface. - */ - SkGrPixelRef(const SkImageInfo&, GrSurface*); - virtual ~SkGrPixelRef(); - - // override from SkPixelRef - GrTexture* getTexture() override; - -protected: - // overrides from SkPixelRef - bool onReadPixels(SkBitmap* dst, SkColorType, const SkIRect* subset) override; - SkPixelRef* deepCopy(SkColorType, SkColorProfileType, - const SkIRect* subset) override; - void onNotifyPixelsChanged() override; - -private: - GrSurface* fSurface; - typedef SkROLockPixelsPixelRef INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/gpu/SkGrTexturePixelRef.h b/gfx/skia/skia/include/gpu/SkGrTexturePixelRef.h deleted file mode 100644 index 712951235d3f..000000000000 --- a/gfx/skia/skia/include/gpu/SkGrTexturePixelRef.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * 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 SkGrTexturePixelRef_DEFINED -#define SkGrTexturePixelRef_DEFINED - -#include "SkGrPixelRef.h" - -typedef SkGrPixelRef SkGrTexturePixelRef; -typedef SkGrPixelRef SkGrRenderTargetPixelRef; - -#endif diff --git a/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h b/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h index 679533eac597..e9781bb22a33 100644 --- a/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrConstColorProcessor.h @@ -26,8 +26,8 @@ public: }; static const int kInputModeCnt = kLastInputMode + 1; - static GrFragmentProcessor* Create(GrColor color, InputMode mode) { - return new GrConstColorProcessor(color, mode); + static sk_sp Make(GrColor color, InputMode mode) { + return sk_sp(new GrConstColorProcessor(color, mode)); } const char* name() const override { return "Color"; } diff --git a/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h b/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h index 42ac6ac52870..e5d197f33827 100644 --- a/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h +++ b/gfx/skia/skia/include/gpu/effects/GrCoverageSetOpXP.h @@ -21,7 +21,7 @@ class GrProcOptInfo; */ class GrCoverageSetOpXPFactory : public GrXPFactory { public: - static GrXPFactory* Create(SkRegion::Op regionOp, bool invertCoverage = false); + static sk_sp Make(SkRegion::Op regionOp, bool invertCoverage = false); void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; @@ -34,9 +34,7 @@ private: bool hasMixedSamples, const DstTexture*) const override; - bool onWillReadDstColor(const GrCaps& /*caps*/, - const GrPipelineOptimizations& /*optimizations*/, - bool /*hasMixedSamples*/) const override { + bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override { return false; } diff --git a/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h b/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h index bcbd5833ca87..3bd321447552 100644 --- a/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h +++ b/gfx/skia/skia/include/gpu/effects/GrCustomXfermode.h @@ -18,7 +18,7 @@ class GrTexture; */ namespace GrCustomXfermode { bool IsSupportedMode(SkXfermode::Mode mode); - GrXPFactory* CreateXPFactory(SkXfermode::Mode mode); + sk_sp MakeXPFactory(SkXfermode::Mode mode); }; #endif diff --git a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h b/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h index 865ef44253d7..6777d76046f4 100644 --- a/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -16,7 +16,10 @@ class GrProcOptInfo; class GrPorterDuffXPFactory : public GrXPFactory { public: - static GrXPFactory* Create(SkXfermode::Mode mode); + static sk_sp Make(SkXfermode::Mode mode); + static sk_sp Make(SkBlendMode mode) { + return Make((SkXfermode::Mode)mode); + } void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, GrXPFactory::InvariantBlendedColor*) const override; @@ -48,9 +51,7 @@ public: blendedColor->fKnownColorFlags = validColorFlags; } - static bool SrcOverWillNeedDstTexture(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples); + static bool SrcOverWillNeedDstTexture(const GrCaps&, const GrPipelineOptimizations&); private: GrPorterDuffXPFactory(SkXfermode::Mode); @@ -60,9 +61,7 @@ private: bool hasMixedSamples, const DstTexture*) const override; - bool onWillReadDstColor(const GrCaps& caps, - const GrPipelineOptimizations& optimizations, - bool hasMixedSamples) const override; + bool onWillReadDstColor(const GrCaps&, const GrPipelineOptimizations&) const override; bool onIsEqual(const GrXPFactory& xpfBase) const override { const GrPorterDuffXPFactory& xpf = xpfBase.cast(); diff --git a/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h b/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h index fb07d003cd65..0e2435ea93ec 100644 --- a/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h +++ b/gfx/skia/skia/include/gpu/effects/GrXfermodeFragmentProcessor.h @@ -15,20 +15,20 @@ class GrFragmentProcessor; namespace GrXfermodeFragmentProcessor { /** The color input to the returned processor is treated as the src and the passed in processor is the dst. */ - const GrFragmentProcessor* CreateFromDstProcessor(const GrFragmentProcessor* dst, - SkXfermode::Mode mode); + sk_sp MakeFromDstProcessor(sk_sp dst, + SkXfermode::Mode mode); /** The color input to the returned processor is treated as the dst and the passed in processor is the src. */ - const GrFragmentProcessor* CreateFromSrcProcessor(const GrFragmentProcessor* src, - SkXfermode::Mode mode); + sk_sp MakeFromSrcProcessor(sk_sp src, + SkXfermode::Mode mode); /** Takes the input color, which is assumed to be unpremultiplied, passes it as an opaque color to both src and dst. The outputs of a src and dst are blended using mode and the original input's alpha is applied to the blended color to produce a premul output. */ - const GrFragmentProcessor* CreateFromTwoProcessors(const GrFragmentProcessor* src, - const GrFragmentProcessor* dst, - SkXfermode::Mode mode); + sk_sp MakeFromTwoProcessors(sk_sp src, + sk_sp dst, + SkXfermode::Mode mode); }; #endif diff --git a/gfx/skia/skia/include/gpu/gl/GrGLConfig.h b/gfx/skia/skia/include/gpu/gl/GrGLConfig.h index 82963a752007..20ee37fe3086 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLConfig.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLConfig.h @@ -21,7 +21,11 @@ #endif #if !defined(GR_GL_FUNCTION_TYPE) - #define GR_GL_FUNCTION_TYPE + #if defined(SK_BUILD_FOR_WIN32) + #define GR_GL_FUNCTION_TYPE __stdcall + #else + #define GR_GL_FUNCTION_TYPE + #endif #endif /** diff --git a/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h b/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h index fd3000e87416..eccd1bf002e6 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLFunctions.h @@ -60,12 +60,13 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDisableProc)(GrGLenum cap); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDisableVertexAttribArrayProc)(GrGLuint index); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysProc)(GrGLenum mode, GrGLint first, GrGLsizei count); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysInstancedProc)(GrGLenum mode, GrGLint first, GrGLsizei count, GrGLsizei primcount); -typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysIndirectProc)(GrGLenum mode, GrGLvoid* indirect); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysIndirectProc)(GrGLenum mode, const GrGLvoid* indirect); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBufferProc)(GrGLenum mode); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBuffersProc)(GrGLsizei n, const GrGLenum* bufs); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsProc)(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsInstancedProc)(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid *indices, GrGLsizei primcount); -typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsIndirectProc)(GrGLenum mode, GrGLenum type, GrGLvoid* indirect); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsIndirectProc)(GrGLenum mode, GrGLenum type, const GrGLvoid* indirect); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawRangeElementsProc)(GrGLenum mode, GrGLuint start, GrGLuint end, GrGLsizei count, GrGLenum type, const GrGLvoid* indices); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableProc)(GrGLenum cap); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableVertexAttribArrayProc)(GrGLuint index); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEndQueryProc)(GrGLenum target); @@ -143,6 +144,7 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilMaskSeparateProc)(GrGLenum fac typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilOpProc)(GrGLenum fail, GrGLenum zfail, GrGLenum zpass); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilOpSeparateProc)(GrGLenum face, GrGLenum fail, GrGLenum zfail, GrGLenum zpass); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexBufferProc)(GrGLenum target, GrGLenum internalformat, GrGLuint buffer); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexBufferRangeProc)(GrGLenum target, GrGLenum internalformat, GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr size); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexImage2DProc)(GrGLenum target, GrGLint level, GrGLint internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLenum format, GrGLenum type, const GrGLvoid* pixels); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexParameteriProc)(GrGLenum target, GrGLenum pname, GrGLint param); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTexParameterivProc)(GrGLenum target, GrGLenum pname, const GrGLint* params); @@ -343,6 +345,11 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFlushMappedNamedBufferRangeProc)(GrGL // OpenGL 3.1 typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTextureBufferProc)(GrGLuint texture, GrGLenum target, GrGLenum internalformat, GrGLuint buffer); +/* ARB_sync */ +typedef GrGLsync (GR_GL_FUNCTION_TYPE* GrGLFenceSyncProc)(GrGLenum condition, GrGLbitfield flags); +typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLClientWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteSyncProc)(GrGLsync sync); + /* KHR_debug */ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageControlProc)(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageInsertProc)(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf); @@ -352,6 +359,9 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPushDebugGroupProc)(GrGLenum source, typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLPopDebugGroupProc)(); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLObjectLabelProc)(GrGLenum identifier, GrGLuint name, GrGLsizei length, const GrGLchar *label); +/** EXT_window_rectangles */ +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLWindowRectanglesProc)(GrGLenum mode, GrGLsizei count, const GrGLint box[]); + /** EGL functions */ typedef const char* (GR_GL_FUNCTION_TYPE* GrEGLQueryStringProc)(GrEGLDisplay dpy, GrEGLint name); typedef GrEGLDisplay (GR_GL_FUNCTION_TYPE* GrEGLGetCurrentDisplayProc)(); @@ -359,6 +369,6 @@ typedef GrEGLImage (GR_GL_FUNCTION_TYPE* GrEGLCreateImageProc)(GrEGLDisplay dpy, typedef GrEGLBoolean (GR_GL_FUNCTION_TYPE* GrEGLDestroyImageProc)(GrEGLDisplay dpy, GrEGLImage image); } // extern "C" -template using GrGLFunction = std__function>; +template using GrGLFunction = std::function>; #endif diff --git a/gfx/skia/skia/include/gpu/gl/GrGLInterface.h b/gfx/skia/skia/include/gpu/gl/GrGLInterface.h index 4ba516617f3e..60109ec18770 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLInterface.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLInterface.h @@ -53,7 +53,7 @@ typedef intptr_t GrGLInterfaceCallbackData; * 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(); +const SK_API GrGLInterface* GrGLCreateNullInterface(bool enableNVPR = false); /** Function that returns a new interface identical to "interface" but without support for GL_NV_path_rendering. */ @@ -155,6 +155,7 @@ public: GrGLFunction fDrawElements; GrGLFunction fDrawElementsIndirect; GrGLFunction fDrawElementsInstanced; + GrGLFunction fDrawRangeElements; GrGLFunction fEnable; GrGLFunction fEnableVertexAttribArray; GrGLFunction fEndQuery; @@ -206,6 +207,8 @@ public: GrGLFunction fMapBufferRange; GrGLFunction fMapBufferSubData; GrGLFunction fMapTexSubImage2D; + GrGLFunction fMultiDrawArraysIndirect; + GrGLFunction fMultiDrawElementsIndirect; GrGLFunction fPixelStorei; GrGLFunction fPopGroupMarker; GrGLFunction fPushGroupMarker; @@ -251,6 +254,7 @@ public: GrGLFunction fStencilOp; GrGLFunction fStencilOpSeparate; GrGLFunction fTexBuffer; + GrGLFunction fTexBufferRange; GrGLFunction fTexImage2D; GrGLFunction fTexParameteri; GrGLFunction fTexParameteriv; @@ -322,10 +326,6 @@ public: /* NV_framebuffer_mixed_samples */ GrGLFunction fCoverageModulation; - /* EXT_multi_draw_indirect */ - GrGLFunction fMultiDrawArraysIndirect; - GrGLFunction fMultiDrawElementsIndirect; - /* NV_bindless_texture */ // We use the NVIDIA verson for now because it does not require dynamically uniform handles. // We may switch the the ARB version and/or omit methods in the future. @@ -452,6 +452,11 @@ public: // OpenGL 3.1 GrGLFunction fTextureBuffer; + /* ARB_sync */ + GrGLFunction fFenceSync; + GrGLFunction fClientWaitSync; + GrGLFunction fDeleteSync; + /* KHR_debug */ GrGLFunction fDebugMessageControl; GrGLFunction fDebugMessageInsert; @@ -461,6 +466,9 @@ public: GrGLFunction fPopDebugGroup; GrGLFunction fObjectLabel; + /* EXT_window_rectangles */ + GrGLFunction fWindowRectangles; + /* EGL functions */ GrGLFunction fEGLCreateImage; GrGLFunction fEGLDestroyImage; diff --git a/gfx/skia/skia/include/gpu/gl/GrGLTypes.h b/gfx/skia/skia/include/gpu/gl/GrGLTypes.h index d0edcf101ef3..5b9e31de1a44 100644 --- a/gfx/skia/skia/include/gpu/gl/GrGLTypes.h +++ b/gfx/skia/skia/include/gpu/gl/GrGLTypes.h @@ -58,6 +58,7 @@ typedef signed long int GrGLintptr; typedef signed long int GrGLsizeiptr; #endif typedef void* GrGLeglImage; +typedef void* GrGLsync; struct GrGLDrawArraysIndirectCommand { GrGLuint fCount; diff --git a/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h b/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h index 82a9f94bccd4..9942016927f2 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkBackendContext.h @@ -12,10 +12,6 @@ #include "vk/GrVkDefines.h" -#ifdef SK_DEBUG -#define ENABLE_VK_LAYERS -#endif - struct GrVkInterface; enum GrVkExtensionFlags { @@ -25,7 +21,7 @@ enum GrVkExtensionFlags { kKHR_swapchain_GrVkExtensionFlag = 0x0008, kKHR_win32_surface_GrVkExtensionFlag = 0x0010, kKHR_android_surface_GrVkExtensionFlag = 0x0020, - kKHR_xlib_surface_GrVkExtensionFlag = 0x0040, + kKHR_xcb_surface_GrVkExtensionFlag = 0x0040, }; enum GrVkFeatureFlags { @@ -45,14 +41,20 @@ struct GrVkBackendContext : public SkRefCnt { VkPhysicalDevice fPhysicalDevice; VkDevice fDevice; VkQueue fQueue; - uint32_t fQueueFamilyIndex; + uint32_t fGraphicsQueueIndex; uint32_t fMinAPIVersion; uint32_t fExtensions; uint32_t fFeatures; SkAutoTUnref fInterface; + using CanPresentFn = std::function; + // Helper function to create the default Vulkan objects needed by the GrVkGpu object - static const GrVkBackendContext* Create(); + // If presentQueueIndex is non-NULL, will try to set up presentQueue as part of device + // creation using the platform-specific canPresent() function. + static const GrVkBackendContext* Create(uint32_t* presentQueueIndex = nullptr, + CanPresentFn = CanPresentFn()); ~GrVkBackendContext() override; }; diff --git a/gfx/skia/skia/include/gpu/vk/GrVkDefines.h b/gfx/skia/skia/include/gpu/vk/GrVkDefines.h index 7ff81c84f912..9caf2d75e524 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkDefines.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkDefines.h @@ -10,11 +10,15 @@ #define GrVkDefines_DEFINED #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_WIN32) -#define VK_USE_PLATFORM_WIN32_KHR +# define VK_USE_PLATFORM_WIN32_KHR #elif defined(SK_BUILD_FOR_ANDROID) -#define VK_USE_PLATFORM_ANDROID_KHR +# define VK_USE_PLATFORM_ANDROID_KHR #elif defined(SK_BUILD_FOR_UNIX) -#define VK_USE_PLATFORM_XLIB_KHR +# define VK_USE_PLATFORM_XCB_KHR +#endif + +#if defined(Bool) || defined(Status) || defined(True) || defined(False) +# pragma error "Macros unexpectedly defined." #endif #include diff --git a/gfx/skia/skia/include/gpu/vk/GrVkInterface.h b/gfx/skia/skia/include/gpu/vk/GrVkInterface.h index 418aaae95851..1f17865166b3 100644 --- a/gfx/skia/skia/include/gpu/vk/GrVkInterface.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkInterface.h @@ -195,33 +195,7 @@ public: VkPtr fCmdNextSubpass; VkPtr fCmdEndRenderPass; VkPtr fCmdExecuteCommands; - VkPtr fDestroySurfaceKHR; - VkPtr fGetPhysicalDeviceSurfaceSupportKHR; - VkPtr fGetPhysicalDeviceSurfaceCapabilitiesKHR; - VkPtr fGetPhysicalDeviceSurfaceFormatsKHR; - VkPtr fGetPhysicalDeviceSurfacePresentModesKHR; -#if defined(VK_USE_PLATFORM_WIN32_KHR) - VkPtr fCreateWin32SurfaceKHR; - VkPtr fGetPhysicalDeviceWin32PresentationSupportKHR; -#elif defined(VK_USE_PLATFORM_ANDROID_KHR) - VkPtr fCreateAndroidSurfaceKHR; -#elif defined(VK_USE_PLATFORM_XLIB_KHR) - VkPtr fCreateXlibSurfaceKHR; - VkPtr fGetPhysicalDeviceXlibPresentationSupportKHR; -#endif - VkPtr fCreateSwapchainKHR; - VkPtr fDestroySwapchainKHR; - VkPtr fGetSwapchainImagesKHR; - VkPtr fAcquireNextImageKHR; - VkPtr fQueuePresentKHR; - VkPtr fGetPhysicalDeviceDisplayPropertiesKHR; - VkPtr fGetPhysicalDeviceDisplayPlanePropertiesKHR; - VkPtr fGetDisplayPlaneSupportedDisplaysKHR; - VkPtr fGetDisplayModePropertiesKHR; - VkPtr fCreateDisplayModeKHR; - VkPtr fGetDisplayPlaneCapabilitiesKHR; - VkPtr fCreateDisplayPlaneSurfaceKHR; - VkPtr fCreateSharedSwapchainsKHR; + VkPtr fCreateDebugReportCallbackEXT; VkPtr fDebugReportMessageEXT; VkPtr fDestroyDebugReportCallbackEXT; diff --git a/gfx/skia/skia/include/gpu/vk/GrVkTypes.h b/gfx/skia/skia/include/gpu/vk/GrVkTypes.h old mode 100755 new mode 100644 index 833f6d30df33..aa1334adca09 --- a/gfx/skia/skia/include/gpu/vk/GrVkTypes.h +++ b/gfx/skia/skia/include/gpu/vk/GrVkTypes.h @@ -9,6 +9,7 @@ #ifndef GrVkTypes_DEFINED #define GrVkTypes_DEFINED +#include "GrTypes.h" #include "vk/GrVkDefines.h" /** @@ -26,17 +27,38 @@ /////////////////////////////////////////////////////////////////////////////// /** - * Types for interacting with Vulkan resources created externally to Skia. GrBackendObjects for - * Vulkan textures are really const GrVkTextureInfo* + * Types for interacting with Vulkan resources created externally to Skia. GrBackendObjects for + * Vulkan textures are really const GrVkImageInfo* */ +struct GrVkAlloc { + VkDeviceMemory fMemory; // can be VK_NULL_HANDLE iff Tex is an RT and uses borrow semantics + VkDeviceSize fOffset; + VkDeviceSize fSize; // this can be indeterminate iff Tex uses borrow semantics + uint32_t fFlags; -struct GrVkTextureInfo { - VkImage fImage; - VkDeviceMemory fAlloc; // this may be null iff the texture is an RT and uses borrow semantics - VkImageTiling fImageTiling; - VkImageLayout fImageLayout; + enum Flag { + kNoncoherent_Flag = 0x1, // memory must be flushed to device after mapping + }; }; -GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrVkTextureInfo*)); +struct GrVkImageInfo { + /** + * If the image's format is sRGB (GrVkFormatIsSRGB returns true), then the image must have + * been created with VkImageCreateFlags containing VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT. + */ + VkImage fImage; + GrVkAlloc fAlloc; + VkImageTiling fImageTiling; + VkImageLayout fImageLayout; + VkFormat fFormat; + uint32_t fLevelCount; + + // 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; } +}; + +GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrVkImageInfo*)); #endif diff --git a/gfx/skia/skia/include/images/SkForceLinking.h b/gfx/skia/skia/include/images/SkForceLinking.h index 13ada542e1df..5de8918e6f62 100644 --- a/gfx/skia/skia/include/images/SkForceLinking.h +++ b/gfx/skia/skia/include/images/SkForceLinking.h @@ -5,6 +5,8 @@ * found in the LICENSE file. */ +#include "SkTypes.h" + /** * This function's sole purpose is to trick the linker into not discarding * SkImageDecoder subclasses just because we do not directly call them. diff --git a/gfx/skia/skia/include/ports/SkAtomics_atomic.h b/gfx/skia/skia/include/ports/SkAtomics_atomic.h deleted file mode 100644 index 64ee823f90d2..000000000000 --- a/gfx/skia/skia/include/ports/SkAtomics_atomic.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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_atomic_DEFINED -#define SkAtomics_atomic_DEFINED - -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); - return __atomic_load_n(ptr, 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); - __atomic_store_n(ptr, val, mo); -} - -template -T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order mo) { - // All values of mo are valid. - return __atomic_fetch_add(ptr, val, mo); -} - -template -T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) { - // All values of mo are valid. - return __atomic_fetch_sub(ptr, val, 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); - return __atomic_compare_exchange_n(ptr, expected, desired, false/*weak?*/, success, failure); -} - -template -T sk_atomic_exchange(T* ptr, T val, sk_memory_order mo) { - // All values of mo are valid. - return __atomic_exchange_n(ptr, val, mo); -} - -#endif//SkAtomics_atomic_DEFINED diff --git a/gfx/skia/skia/include/ports/SkAtomics_std.h b/gfx/skia/skia/include/ports/SkAtomics_std.h deleted file mode 100644 index 163efb78c0c1..000000000000 --- a/gfx/skia/skia/include/ports/SkAtomics_std.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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_std_DEFINED -#define SkAtomics_std_DEFINED - -// We try not to depend on the C++ standard library, -// but these uses of should all inline, so we don't feel to bad here. -#include - -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 -T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) { - // All values of mo are valid. - std::atomic* ap = reinterpret_cast*>(ptr); - return std::atomic_fetch_sub_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); -} - -template -T sk_atomic_exchange(T* ptr, T val, sk_memory_order mo) { - // All values of mo are valid. - std::atomic* ap = reinterpret_cast*>(ptr); - return std::atomic_exchange_explicit(ap, val, (std::memory_order)mo); -} - -#endif//SkAtomics_std_DEFINED diff --git a/gfx/skia/skia/include/ports/SkAtomics_sync.h b/gfx/skia/skia/include/ports/SkAtomics_sync.h deleted file mode 100644 index 02b1e580725d..000000000000 --- a/gfx/skia/skia/include/ports/SkAtomics_sync.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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_sync_DEFINED -#define SkAtomics_sync_DEFINED - -// This file is mostly a shim. We'd like to delete it. Please don't put much -// effort into maintaining it, and if you find bugs in it, the right fix is to -// delete this file and upgrade your compiler to something that supports -// __atomic builtins or std::atomic. - -static inline void barrier(sk_memory_order mo) { - asm volatile("" : : : "memory"); // Prevents the compiler from reordering code. - #if SK_CPU_X86 - // On x86, we generally don't need an extra memory barrier for loads or stores. - if (sk_memory_order_seq_cst == mo) { __sync_synchronize(); } - #else - // On other platforms (e.g. ARM) we do unless the memory order is relaxed. - if (sk_memory_order_relaxed != mo) { __sync_synchronize(); } - #endif -} - -// These barriers only support our majority use cases: acquire and relaxed loads, release stores. -// For anything more complicated, please consider deleting this file and upgrading your compiler. - -template -T sk_atomic_load(const T* ptr, sk_memory_order mo) { - T val = *ptr; - barrier(mo); - return val; -} - -template -void sk_atomic_store(T* ptr, T val, sk_memory_order mo) { - barrier(mo); - *ptr = val; -} - -template -T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order) { - return __sync_fetch_and_add(ptr, val); -} - -template -T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order) { - return __sync_fetch_and_sub(ptr, val); -} - -template -bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired, sk_memory_order, sk_memory_order) { - T prev = __sync_val_compare_and_swap(ptr, *expected, desired); - if (prev == *expected) { - return true; - } - *expected = prev; - return false; -} - -template -T sk_atomic_exchange(T* ptr, T val, sk_memory_order) { - // There is no __sync exchange. Emulate it with a CAS loop. - T prev; - do { - prev = sk_atomic_load(ptr); - } while(!sk_atomic_compare_exchange(ptr, &prev, val)); - return prev; -} - -#endif//SkAtomics_sync_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontConfigInterface.h b/gfx/skia/skia/include/ports/SkFontConfigInterface.h index 063cb9d553ba..74f766f52e8a 100644 --- a/gfx/skia/skia/include/ports/SkFontConfigInterface.h +++ b/gfx/skia/skia/include/ports/SkFontConfigInterface.h @@ -13,7 +13,7 @@ #include "SkRefCnt.h" #include "SkTypeface.h" -struct SkBaseMutex; +class SkFontMgr; /** * \class SkFontConfigInterface @@ -23,12 +23,12 @@ struct SkBaseMutex; */ class SK_API SkFontConfigInterface : public SkRefCnt { public: - /** - * Returns the global SkFontConfigInterface instance, and if it is not - * NULL, calls ref() on it. The caller must balance this with a call to - * unref(). + * 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 SkFontConfigInterface* RefGlobal(); @@ -81,10 +81,10 @@ public: * If a match is not found, return false, and ignore all out parameters. */ virtual bool matchFamilyName(const char familyName[], - SkTypeface::Style requested, + SkFontStyle requested, FontIdentity* outFontIdentifier, SkString* outFamilyName, - SkTypeface::Style* outStyle) = 0; + SkFontStyle* outStyle) = 0; /** * Given a FontRef, open a stream to access its data, or return null @@ -98,23 +98,20 @@ public: * * The default implementation simply returns a new typeface built using data obtained from * openStream(), but derived classes may implement more complex caching schemes. - * - * Callers are responsible for unref-ing the result. */ - virtual SkTypeface* createTypeface(const FontIdentity& identity) { - return SkTypeface::CreateFromStream(this->openStream(identity), identity.fTTCIndex); + virtual sk_sp makeTypeface(const FontIdentity& identity) { + return SkTypeface::MakeFromStream(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. - * The mutex may be used to guarantee the singleton is only constructed once. */ - static SkFontConfigInterface* GetSingletonDirectInterface(SkBaseMutex* mutex = NULL); + static SkFontConfigInterface* GetSingletonDirectInterface(); // New APIS, which have default impls for now (which do nothing) - virtual SkDataTable* getFamilyNames() { return SkDataTable::NewEmpty(); } + virtual sk_sp getFamilyNames() { return SkDataTable::MakeEmpty(); } typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/ports/SkFontMgr.h b/gfx/skia/skia/include/ports/SkFontMgr.h index 3e6c785be9eb..afadeaaa9785 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr.h +++ b/gfx/skia/skia/include/ports/SkFontMgr.h @@ -150,11 +150,10 @@ public: /** * Create a typeface from the specified font data. - * Takes ownership of the font data, so the caller should not reference it again. * Will return NULL if the typeface could not be created. * The caller must call unref() on the returned object if it is not null. */ - SkTypeface* createFromFontData(SkFontData*) const; + SkTypeface* createFromFontData(std::unique_ptr) const; /** * Create a typeface for the specified fileName and TTC index @@ -164,8 +163,7 @@ public: */ SkTypeface* createFromFile(const char path[], int ttcIndex = 0) const; - SkTypeface* legacyCreateTypeface(const char familyName[], - unsigned typefaceStyleBits) const; + SkTypeface* legacyCreateTypeface(const char familyName[], SkFontStyle style) const; /** * Return a ref to the default fontmgr. The caller must call unref() on @@ -193,14 +191,13 @@ protected: virtual SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const = 0; // TODO: make pure virtual. virtual SkTypeface* onCreateFromStream(SkStreamAsset*, const FontParameters&) const; - virtual SkTypeface* onCreateFromFontData(SkFontData*) const; + virtual SkTypeface* onCreateFromFontData(std::unique_ptr) const; virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const = 0; - virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], - unsigned styleBits) const = 0; + virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle) const = 0; + private: static SkFontMgr* Factory(); // implemented by porting layer - friend SkFontMgr* sk_fontmgr_create_default(); typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h b/gfx/skia/skia/include/ports/SkFontMgr_FontConfigInterface.h new file mode 100644 index 000000000000..356e54c87d0b --- /dev/null +++ b/gfx/skia/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 SkFontMgr* SkFontMgr_New_FCI(sk_sp fci); + +#endif // #ifndef SkFontMgr_FontConfigInterface_DEFINED diff --git a/gfx/skia/skia/include/ports/SkFontMgr_indirect.h b/gfx/skia/skia/include/ports/SkFontMgr_indirect.h index 37502d240425..406a75a7ee35 100644 --- a/gfx/skia/skia/include/ports/SkFontMgr_indirect.h +++ b/gfx/skia/skia/include/ports/SkFontMgr_indirect.h @@ -9,6 +9,7 @@ #define SkFontMgr_indirect_DEFINED #include "../private/SkMutex.h" +#include "../private/SkOnce.h" #include "../private/SkTArray.h" #include "SkDataTable.h" #include "SkFontMgr.h" @@ -28,7 +29,7 @@ public: // In the future these calls should be broken out into their own interface // with a name like SkFontRenderer. SkFontMgr_Indirect(SkFontMgr* impl, SkRemotableFontMgr* proxy) - : fImpl(SkRef(impl)), fProxy(SkRef(proxy)), fFamilyNamesInited(false) + : fImpl(SkRef(impl)), fProxy(SkRef(proxy)) { } protected: @@ -38,24 +39,23 @@ protected: SkFontStyleSet* onMatchFamily(const char familyName[]) const override; - virtual SkTypeface* onMatchFamilyStyle(const char familyName[], - const SkFontStyle& fontStyle) const override; + SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle& fontStyle) const override; - virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], - const SkFontStyle&, - const char* bcp47[], - int bcp47Count, - SkUnichar character) const override; + SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle&, + const char* bcp47[], + int bcp47Count, + SkUnichar character) const override; - virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, - const SkFontStyle& fontStyle) const override; + SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle& fontStyle) const override; SkTypeface* onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const override; SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override; SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override; - virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], - unsigned styleBits) const override; + SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle) const override; private: SkTypeface* createTypefaceFromFontId(const SkFontIdentity& fontId) const; @@ -95,9 +95,8 @@ private: mutable SkTArray fDataCache; mutable SkMutex fDataCacheMutex; - mutable SkAutoTUnref fFamilyNames; - mutable bool fFamilyNamesInited; - mutable SkMutex fFamilyNamesMutex; + mutable sk_sp fFamilyNames; + mutable SkOnce fFamilyNamesInitOnce; static void set_up_family_names(const SkFontMgr_Indirect* self); friend class SkStyleSet_Indirect; diff --git a/gfx/skia/skia/include/ports/SkRemotableFontMgr.h b/gfx/skia/skia/include/ports/SkRemotableFontMgr.h index ddc8e50a12e2..2e028cee2620 100644 --- a/gfx/skia/skia/include/ports/SkRemotableFontMgr.h +++ b/gfx/skia/skia/include/ports/SkRemotableFontMgr.h @@ -61,10 +61,8 @@ public: * * The indexes may be used with getIndex(int) and * matchIndexStyle(int, SkFontStyle). - * - * The caller must unref() the returned object. */ - virtual SkDataTable* getFamilyNames() const = 0; + virtual sk_sp getFamilyNames() const = 0; /** * Returns all of the fonts with the given familyIndex. diff --git a/gfx/skia/skia/include/ports/SkTypeface_win.h b/gfx/skia/skia/include/ports/SkTypeface_win.h index 6929cc08c7b6..2c4cc41ba41c 100644 --- a/gfx/skia/skia/include/ports/SkTypeface_win.h +++ b/gfx/skia/skia/include/ports/SkTypeface_win.h @@ -8,6 +8,7 @@ #ifndef SkTypeface_win_DEFINED #define SkTypeface_win_DEFINED +#include "../private/SkLeanWindows.h" #include "SkTypeface.h" #include @@ -42,6 +43,7 @@ class SkFontMgr; class SkRemotableFontMgr; struct IDWriteFactory; struct IDWriteFontCollection; +struct IDWriteFontFallback; /** * Like the other Typeface create methods, this returns a new reference to the @@ -55,6 +57,9 @@ SK_API SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory, SK_API SkFontMgr* SkFontMgr_New_GDI(); SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL, IDWriteFontCollection* collection = NULL); +SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, + IDWriteFontCollection* collection, + IDWriteFontFallback* fallback); /** * Creates an SkFontMgr which renders using DirectWrite and obtains its data diff --git a/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h b/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h new file mode 100644 index 000000000000..7e6482da9014 --- /dev/null +++ b/gfx/skia/skia/include/private/GrInstancedPipelineInfo.h @@ -0,0 +1,49 @@ +/* + * 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 GrGrInstancedPipelineInfo_DEFINED +#define GrGrInstancedPipelineInfo_DEFINED + +#include "GrRenderTarget.h" + +/** + * Provides info about the pipeline that GrInstancedRendering needs in order to select appropriate + * drawing algorithms. + */ +struct GrInstancedPipelineInfo { + GrInstancedPipelineInfo(const GrRenderTarget* rt) + : fIsMultisampled(rt->isStencilBufferMultisampled()), + fIsMixedSampled(rt->isMixedSampled()), + fIsRenderingToFloat(GrPixelConfigIsFloatingPoint(rt->desc().fConfig)), + fColorDisabled(false), + fDrawingShapeToStencil(false), + fCanDiscard(false) { + } + + bool canUseCoverageAA() const { + return !fIsMultisampled || (fIsMixedSampled && !fDrawingShapeToStencil); + } + + bool fIsMultisampled : 1; + bool fIsMixedSampled : 1; + bool fIsRenderingToFloat : 1; + bool fColorDisabled : 1; + /** + * Indicates that the instanced renderer should take extra precautions to ensure the shape gets + * drawn correctly to the stencil buffer (e.g. no coverage AA). NOTE: this does not mean a + * stencil test is or is not active. + */ + bool fDrawingShapeToStencil : 1; + /** + * Indicates that the instanced renderer can use processors with discard instructions. This + * should not be set if the shader will use derivatives, automatic mipmap LOD, or other features + * that depend on neighboring pixels. Some draws will fail to create if this is not set. + */ + bool fCanDiscard : 1; +}; + +#endif diff --git a/gfx/skia/skia/include/private/GrRenderTargetProxy.h b/gfx/skia/skia/include/private/GrRenderTargetProxy.h new file mode 100644 index 000000000000..e4bc70f21273 --- /dev/null +++ b/gfx/skia/skia/include/private/GrRenderTargetProxy.h @@ -0,0 +1,97 @@ +/* + * 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 "GrRenderTarget.h" +#include "GrRenderTargetPriv.h" +#include "GrSurfaceProxy.h" +#include "GrTypes.h" + +class GrTextureProvider; + +// 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 : public GrSurfaceProxy { +public: + /** + * The caller gets the creation ref. + */ + static sk_sp Make(const GrCaps&, const GrSurfaceDesc&, + SkBackingFit, SkBudgeted); + static sk_sp Make(const GrCaps&, sk_sp); + + ~GrRenderTargetProxy() override; + + // TODO: add asTextureProxy variants + GrRenderTargetProxy* asRenderTargetProxy() override { return this; } + const GrRenderTargetProxy* asRenderTargetProxy() const override { return this; } + + // Actually instantiate the backing rendertarget, if necessary. + GrRenderTarget* instantiate(GrTextureProvider* texProvider); + + bool isStencilBufferMultisampled() const { return fDesc.fSampleCnt > 0; } + + /** + * For our purposes, "Mixed Sampled" means the stencil buffer is multisampled but the color + * buffer is not. + */ + bool isMixedSampled() const { return fFlags & GrRenderTargetPriv::Flags::kMixedSampled; } + + /** + * "Unified Sampled" means the stencil and color buffers are both multisampled. + */ + bool isUnifiedMultisampled() const { return fDesc.fSampleCnt > 0 && !this->isMixedSampled(); } + + /** + * Returns the number of samples/pixel in the stencil buffer (Zero if non-MSAA). + */ + int numStencilSamples() const { return fDesc.fSampleCnt; } + + /** + * Returns the number of samples/pixel in the color buffer (Zero if non-MSAA or mixed sampled). + */ + int numColorSamples() const { return this->isMixedSampled() ? 0 : fDesc.fSampleCnt; } + + void setLastDrawTarget(GrDrawTarget* dt); + GrDrawTarget* getLastDrawTarget() { return fLastDrawTarget; } + + GrRenderTargetPriv::Flags testingOnly_getFlags() const; + +private: + // Deferred version + GrRenderTargetProxy(const GrCaps&, const GrSurfaceDesc&, SkBackingFit, SkBudgeted); + + // Wrapped version + GrRenderTargetProxy(const GrCaps&, sk_sp rt); + + // For wrapped render targets we store it here. + // For deferred proxies we will fill this in when we need to instantiate the deferred resource + sk_sp fTarget; + + // These don't usually get computed until the render target is instantiated, but the render + // target proxy may need to answer queries about it before then. And since in the deferred case + // we know the newly created render target will be internal, we are able to precompute what the + // flags will ultimately end up being. In the wrapped case we just copy the wrapped + // rendertarget's info here. + GrRenderTargetPriv::Flags fFlags; + + // The last drawTarget that wrote to or is currently going to write to this renderTarget + // The drawTarget can be closed (e.g., no draw context is currently bound + // to this renderTarget). + // This back-pointer is required so that we can add a dependancy between + // the drawTarget used to create the current contents of this renderTarget + // and the drawTarget of a destination renderTarget to which this one is being drawn. + GrDrawTarget* fLastDrawTarget; + + typedef GrSurfaceProxy INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/include/private/GrSurfaceProxy.h b/gfx/skia/skia/include/private/GrSurfaceProxy.h new file mode 100644 index 000000000000..69656fe4f57c --- /dev/null +++ b/gfx/skia/skia/include/private/GrSurfaceProxy.h @@ -0,0 +1,92 @@ +/* + * 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 "GrGpuResource.h" +#include "SkRect.h" + +class GrTextureProxy; +class GrRenderTargetProxy; + +class GrSurfaceProxy : public GrIORef { +public: + const GrSurfaceDesc& desc() const { return fDesc; } + + GrSurfaceOrigin origin() const { + SkASSERT(kTopLeft_GrSurfaceOrigin == fDesc.fOrigin || + kBottomLeft_GrSurfaceOrigin == fDesc.fOrigin); + return fDesc.fOrigin; + } + int width() const { return fDesc.fWidth; } + int height() const { return fDesc.fWidth; } + GrPixelConfig config() const { return fDesc.fConfig; } + + uint32_t uniqueID() const { return fUniqueID; } + + /** + * Helper that gets the width and height of the surface as a bounding rectangle. + */ + SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); } + + /** + * @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; } + + /** + * Does the resource count against the resource budget? + */ + SkBudgeted isBudgeted() const { return fBudgeted; } + +protected: + // Deferred version + GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted) + : fDesc(desc) + , fFit(fit) + , fBudgeted(budgeted) + , fUniqueID(GrGpuResource::CreateUniqueID()) { + } + + // Wrapped version + GrSurfaceProxy(const GrSurfaceDesc& desc, SkBackingFit fit, + SkBudgeted budgeted, uint32_t uniqueID) + : fDesc(desc) + , fFit(fit) + , fBudgeted(budgeted) + , fUniqueID(uniqueID) { + } + + virtual ~GrSurfaceProxy() {} + + // For wrapped resources, 'fDesc' will always be filled in from the wrapped resource. + const GrSurfaceDesc fDesc; + const SkBackingFit fFit; // always exact for wrapped resources + const SkBudgeted fBudgeted; // set from the backing resource for wrapped resources + const uint32_t fUniqueID; // set from the backing resource for wrapped resources + +private: + + // See comment in GrGpuResource.h. + void notifyAllCntsAreZero(CntType) const { delete this; } + bool notifyRefCountIsZero() const { return true; } + + typedef GrIORef INHERITED; + + // to access notifyAllCntsAreZero and notifyRefCntIsZero. + friend class GrIORef; +}; + +#endif diff --git a/gfx/skia/skia/include/private/GrTextureProxy.h b/gfx/skia/skia/include/private/GrTextureProxy.h new file mode 100644 index 000000000000..63cb3c8359d6 --- /dev/null +++ b/gfx/skia/skia/include/private/GrTextureProxy.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 GrTextureProxy_DEFINED +#define GrTextureProxy_DEFINED + +#include "GrSurfaceProxy.h" +#include "GrTexture.h" + +class GrTextureProvider; + +// This class delays the acquisition of textures until they are actually required +class GrTextureProxy : public GrSurfaceProxy { +public: + // TODO: need to refine ownership semantics of 'srcData' if we're in completely + // deferred mode + static sk_sp Make(const GrSurfaceDesc&, SkBackingFit, SkBudgeted, + const void* srcData = nullptr, size_t rowBytes = 0); + static sk_sp Make(sk_sp); + + // TODO: add asRenderTargetProxy variants + GrTextureProxy* asTextureProxy() override { return this; } + const GrTextureProxy* asTextureProxy() const override { return this; } + + // Actually instantiate the backing texture, if necessary + GrTexture* instantiate(GrTextureProvider* texProvider); + +private: + // Deferred version + GrTextureProxy(const GrSurfaceDesc& srcDesc, SkBackingFit, SkBudgeted, + const void* srcData, size_t srcRowBytes); + // Wrapped version + GrTextureProxy(sk_sp tex); + + // For wrapped textures we store it here. + // For deferred proxies we will fill this in when we need to instantiate the deferred resource + sk_sp fTexture; + + typedef GrSurfaceProxy INHERITED; +}; + +#endif diff --git a/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.h b/gfx/skia/skia/include/private/GrTextureStripAtlas.h similarity index 98% rename from gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.h rename to gfx/skia/skia/include/private/GrTextureStripAtlas.h index 91ce61c23200..5b90a342d7f9 100644 --- a/gfx/skia/skia/src/gpu/effects/GrTextureStripAtlas.h +++ b/gfx/skia/skia/include/private/GrTextureStripAtlas.h @@ -9,7 +9,7 @@ #define GrTextureStripAtlas_DEFINED #include "SkBitmap.h" -#include "SkChecksum.h" +#include "SkOpts.h" #include "SkGr.h" #include "SkTDArray.h" #include "SkTDynamicHash.h" @@ -142,7 +142,7 @@ private: public: // for SkTDynamicHash static const Desc& GetKey(const AtlasEntry& entry) { return entry.fDesc; } - static uint32_t Hash(const Desc& desc) { return SkChecksum::Murmur3(&desc, sizeof(Desc)); } + static uint32_t Hash(const Desc& desc) { return SkOpts::hash(&desc, sizeof(Desc)); } // AtlasEntry proper AtlasEntry() : fAtlas(nullptr) {} diff --git a/gfx/skia/skia/include/private/SkAtomics.h b/gfx/skia/skia/include/private/SkAtomics.h index d9989cf0f7e4..1e26df86ed48 100644 --- a/gfx/skia/skia/include/private/SkAtomics.h +++ b/gfx/skia/skia/include/private/SkAtomics.h @@ -10,6 +10,9 @@ // This file is not part of the public Skia API. #include "SkTypes.h" +#include + +// ~~~~~~~~ APIs ~~~~~~~~~ enum sk_memory_order { sk_memory_order_relaxed, @@ -58,10 +61,6 @@ public: sk_atomic_store(&fVal, val, mo); } - T exchange(const T& val, sk_memory_order mo = default_memory_order) { - return sk_atomic_exchange(&fVal, val, mo); - } - // Alias for .load(default_memory_order). MOZ_IMPLICIT operator T() const { return this->load(); @@ -90,52 +89,71 @@ private: T fVal; }; -// IWYU pragma: begin_exports -#if defined(_MSC_VER) - #include "../ports/SkAtomics_std.h" -#elif !defined(SK_BUILD_FOR_IOS) && defined(__ATOMIC_RELAXED) - #include "../ports/SkAtomics_atomic.h" -#else - #include "../ports/SkAtomics_sync.h" -#endif -// IWYU pragma: end_exports +// ~~~~~~~~ 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 +T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) { + // All values of mo are valid. + std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_fetch_sub_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); +} + +template +T sk_atomic_exchange(T* ptr, T val, sk_memory_order mo) { + // All values of mo are valid. + std::atomic* ap = reinterpret_cast*>(ptr); + return std::atomic_exchange_explicit(ap, val, (std::memory_order)mo); +} + +// ~~~~~~~~ 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); } -inline int32_t sk_atomic_add(int32_t* ptr, int32_t v) { return sk_atomic_fetch_add(ptr, v); } - -inline int64_t sk_atomic_inc(int64_t* ptr) { return sk_atomic_fetch_add(ptr, +1); } - -inline bool sk_atomic_cas(int32_t* ptr, int32_t expected, int32_t desired) { - return sk_atomic_compare_exchange(ptr, &expected, desired); -} - -inline void* sk_atomic_cas(void** ptr, void* expected, void* desired) { - (void)sk_atomic_compare_exchange(ptr, &expected, desired); - return expected; -} - -inline int32_t sk_atomic_conditional_inc(int32_t* ptr) { - int32_t prev = sk_atomic_load(ptr); - do { - if (0 == prev) { - break; - } - } while(!sk_atomic_compare_exchange(ptr, &prev, prev+1)); - return prev; -} - -template -T sk_acquire_load(T* ptr) { return sk_atomic_load(ptr, sk_memory_order_acquire); } - -template -void sk_release_store(T* ptr, T val) { sk_atomic_store(ptr, val, sk_memory_order_release); } - -inline void sk_membar_acquire__after_atomic_dec() {} -inline void sk_membar_acquire__after_atomic_conditional_inc() {} +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/gfx/skia/skia/include/private/SkBitmaskEnum.h b/gfx/skia/skia/include/private/SkBitmaskEnum.h new file mode 100644 index 000000000000..f787d3b04d84 --- /dev/null +++ b/gfx/skia/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/gfx/skia/skia/include/private/SkChecksum.h b/gfx/skia/skia/include/private/SkChecksum.h index 6289a444ae78..8a04c89ae79f 100644 --- a/gfx/skia/skia/include/private/SkChecksum.h +++ b/gfx/skia/skia/include/private/SkChecksum.h @@ -12,6 +12,12 @@ #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: /** @@ -41,17 +47,6 @@ public: hash ^= hash >> 16; return hash; } - - /** - * Calculate 32-bit Murmur hash (murmur3). - * See en.wikipedia.org/wiki/MurmurHash. - * - * @param data Memory address of the data block to be processed. - * @param size Size of the data block in bytes. - * @param seed Initial hash seed. (optional) - * @return hash result - */ - static uint32_t Murmur3(const void* data, size_t bytes, uint32_t seed=0); }; // SkGoodHash should usually be your first choice in hashing data. @@ -64,11 +59,11 @@ struct SkGoodHash { template SK_WHEN(sizeof(K) != 4, uint32_t) operator()(const K& k) const { - return SkChecksum::Murmur3(&k, sizeof(K)); + return SkOpts::hash_fn(&k, sizeof(K), 0); } uint32_t operator()(const SkString& k) const { - return SkChecksum::Murmur3(k.c_str(), k.size()); + return SkOpts::hash_fn(k.c_str(), k.size(), 0); } }; diff --git a/gfx/skia/skia/include/private/SkFixed.h b/gfx/skia/skia/include/private/SkFixed.h index c90d5e9ffd09..be3bb5d6045d 100644 --- a/gfx/skia/skia/include/private/SkFixed.h +++ b/gfx/skia/skia/include/private/SkFixed.h @@ -33,17 +33,6 @@ typedef int32_t SkFixed; #define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1)) -// Pins over/under flows to SK_FixedMax/SK_FixedMin (slower than just a cast). -static inline SkFixed SkFloatPinToFixed(float x) { - x *= SK_Fixed1; - // Casting float to int outside the range of the target type (int32_t) is undefined behavior. - if (x >= SK_FixedMax) return SK_FixedMax; - if (x <= SK_FixedMin) return SK_FixedMin; - const SkFixed result = static_cast(x); - SkASSERT(truncf(x) == static_cast(result)); - return result; -} - #ifdef SK_DEBUG static inline SkFixed SkFloatToFixed_Check(float x) { int64_t n64 = (int64_t)(x * SK_Fixed1); @@ -58,17 +47,6 @@ static inline SkFixed SkFloatPinToFixed(float x) { #define SkFixedToDouble(x) ((x) * 1.52587890625e-5) #define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) -// Pins over/under flows to SK_FixedMax/SK_FixedMin (slower than just a cast). -static inline SkFixed SkDoublePinToFixed(double x) { - x *= SK_Fixed1; - // Casting double to int outside the range of the target type (int32_t) is undefined behavior. - if (x >= SK_FixedMax) return SK_FixedMax; - if (x <= SK_FixedMin) return SK_FixedMin; - const SkFixed result = static_cast(x); - SkASSERT(trunc(x) == static_cast(result)); - return result; -} - /** Converts an integer to a SkFixed, asserting that the result does not overflow a 32 bit signed integer */ @@ -98,14 +76,9 @@ static inline SkFixed SkDoublePinToFixed(double x) { #define SkFixedAbs(x) SkAbs32(x) #define SkFixedAve(a, b) (((a) + (b)) >> 1) -// Blink layout tests are baselined to Clang optimizing through undefined behavior in SkDivBits. -#if defined(SK_SUPPORT_LEGACY_DIVBITS_UB) - #define SkFixedDiv(numer, denom) SkDivBits(numer, denom, 16) -#else - // 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)) -#endif +// 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)) ////////////////////////////////////////////////////////////////////////////////////////////////////// // Now look for ASM overrides for our portable versions (should consider putting this in its own file) @@ -163,13 +136,11 @@ inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) { #define SkFixedToScalar(x) SkFixedToFloat(x) #define SkScalarToFixed(x) SkFloatToFixed(x) -#define SkScalarPinToFixed(x) SkFloatPinToFixed(x) #else // SK_SCALAR_IS_DOUBLE #define SkFixedToScalar(x) SkFixedToDouble(x) #define SkScalarToFixed(x) SkDoubleToFixed(x) -#define SkScalarPinToFixed(x) SkDoublePinToFixed(x) #endif diff --git a/gfx/skia/skia/include/private/SkFloatBits.h b/gfx/skia/skia/include/private/SkFloatBits.h index caad342a4a6b..7aa13cf67b7d 100644 --- a/gfx/skia/skia/include/private/SkFloatBits.h +++ b/gfx/skia/skia/include/private/SkFloatBits.h @@ -1,4 +1,3 @@ - /* * Copyright 2008 The Android Open Source Project * @@ -11,6 +10,7 @@ #define SkFloatBits_DEFINED #include "SkTypes.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 @@ -36,27 +36,6 @@ static inline int32_t Sk2sComplimentToSignBit(int32_t x) { return x; } -/** Given the bit representation of a float, return its value cast to an int. - If the value is out of range, or NaN, return return +/- SK_MaxS32 -*/ -int32_t SkFloatBits_toIntCast(int32_t floatBits); - -/** Given the bit representation of a float, return its floor as an int. - If the value is out of range, or NaN, return return +/- SK_MaxS32 - */ -SK_API int32_t SkFloatBits_toIntFloor(int32_t floatBits); - -/** Given the bit representation of a float, return it rounded to an int. - If the value is out of range, or NaN, return return +/- SK_MaxS32 - */ -SK_API int32_t SkFloatBits_toIntRound(int32_t floatBits); - -/** Given the bit representation of a float, return its ceiling as an int. - If the value is out of range, or NaN, return return +/- SK_MaxS32 - */ -SK_API int32_t SkFloatBits_toIntCeil(int32_t floatBits); - - union SkFloatIntUnion { float fFloat; int32_t fSignBitInt; @@ -92,36 +71,29 @@ static inline float Sk2sComplimentAsFloat(int32_t x) { return SkBits2Float(Sk2sComplimentToSignBit(x)); } -/** Return x cast to a float (i.e. (float)x) -*/ -float SkIntToFloatCast(int x); - -/** Return the float cast to an int. - If the value is out of range, or NaN, return +/- SK_MaxS32 -*/ -static inline int32_t SkFloatToIntCast(float x) { - return SkFloatBits_toIntCast(SkFloat2Bits(x)); +static inline int32_t pin_double_to_int(double x) { + return (int32_t)SkTPin(x, SK_MinS32, SK_MaxS32); } /** Return the floor of the float as an int. If the value is out of range, or NaN, return +/- SK_MaxS32 */ static inline int32_t SkFloatToIntFloor(float x) { - return SkFloatBits_toIntFloor(SkFloat2Bits(x)); + return pin_double_to_int(floor(x)); } /** Return the float rounded to an int. If the value is out of range, or NaN, return +/- SK_MaxS32 */ static inline int32_t SkFloatToIntRound(float x) { - return SkFloatBits_toIntRound(SkFloat2Bits(x)); + return pin_double_to_int(floor((double)x + 0.5)); } /** Return the ceiling of the float as an int. If the value is out of range, or NaN, return +/- SK_MaxS32 */ static inline int32_t SkFloatToIntCeil(float x) { - return SkFloatBits_toIntCeil(SkFloat2Bits(x)); + return pin_double_to_int(ceil(x)); } // Scalar wrappers for float-bit routines diff --git a/gfx/skia/skia/include/private/SkFloatingPoint.h b/gfx/skia/skia/include/private/SkFloatingPoint.h index 25b18c95cad2..6a6edf36519d 100644 --- a/gfx/skia/skia/include/private/SkFloatingPoint.h +++ b/gfx/skia/skia/include/private/SkFloatingPoint.h @@ -12,9 +12,15 @@ #include "SkTypes.h" -#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 @@ -70,9 +76,9 @@ static inline float sk_float_pow(float base, float exp) { return (bits << 1) == (0xFF << 24); } #else - #define sk_float_isfinite(x) std::isfinite(x) - #define sk_float_isnan(x) std::isnan(x) - #define sk_float_isinf(x) std::isinf(x) + #define sk_float_isfinite(x) isfinite(x) + #define sk_float_isnan(x) isnan(x) + #define sk_float_isinf(x) isinf(x) #endif #define sk_double_isnan(a) sk_float_isnan(a) @@ -94,19 +100,18 @@ static inline float sk_float_pow(float base, float exp) { #define sk_double_round2int(x) (int)floor((x) + 0.5f) #define sk_double_ceil2int(x) (int)ceil(x) -extern const uint32_t gIEEENotANumber; -extern const uint32_t gIEEEInfinity; -extern const uint32_t gIEEENegativeInfinity; - -#define SK_FloatNaN (*SkTCast(&gIEEENotANumber)) -#define SK_FloatInfinity (*SkTCast(&gIEEEInfinity)) -#define SK_FloatNegativeInfinity (*SkTCast(&gIEEENegativeInfinity)) +static const uint32_t kIEEENotANumber = 0x7fffffff; +#define SK_FloatNaN (*SkTCast(&kIEEENotANumber)) +#define SK_FloatInfinity (+(float)INFINITY) +#define SK_FloatNegativeInfinity (-(float)INFINITY) static inline float sk_float_rsqrt_portable(float x) { // Get initial estimate. - int i = *SkTCast(&x); + int i; + memcpy(&i, &x, 4); i = 0x5F1FFFF9 - (i>>1); - float estimate = *SkTCast(&i); + float estimate; + memcpy(&estimate, &i, 4); // One step of Newton's method to refine. const float estimate_sq = estimate*estimate; diff --git a/gfx/skia/skia/include/private/SkGpuFenceSync.h b/gfx/skia/skia/include/private/SkGpuFenceSync.h deleted file mode 100644 index 72fd24107871..000000000000 --- a/gfx/skia/skia/include/private/SkGpuFenceSync.h +++ /dev/null @@ -1,29 +0,0 @@ - -/* - * 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 SkGpuFenceSync_DEFINED -#define SkGpuFenceSync_DEFINED - -#include "SkTypes.h" - -typedef void* SkPlatformGpuFence; - -/* - * This class provides an interface to interact with fence syncs. A fence sync is an object that the - * client can insert into the GPU command stream, and then at any future time, wait until all - * commands that were issued before the fence have completed. - */ -class SkGpuFenceSync { -public: - virtual SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const = 0; - virtual bool waitFence(SkPlatformGpuFence, bool flush) const = 0; - virtual void deleteFence(SkPlatformGpuFence) const = 0; - - virtual ~SkGpuFenceSync() {} -}; - -#endif diff --git a/gfx/skia/skia/include/private/SkLeanWindows.h b/gfx/skia/skia/include/private/SkLeanWindows.h new file mode 100644 index 000000000000..2bdddbba390e --- /dev/null +++ b/gfx/skia/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/gfx/skia/skia/include/private/SkMiniRecorder.h b/gfx/skia/skia/include/private/SkMiniRecorder.h index 2f5612ca39f7..6365ebc65b9f 100644 --- a/gfx/skia/skia/include/private/SkMiniRecorder.h +++ b/gfx/skia/skia/include/private/SkMiniRecorder.h @@ -20,8 +20,6 @@ public: ~SkMiniRecorder(); // Try to record an op. Returns false on failure. - bool drawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, - const SkPaint*, SkCanvas::SrcRectConstraint); bool drawPath(const SkPath&, const SkPaint&); bool drawRect(const SkRect&, const SkPaint&); bool drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint&); @@ -38,7 +36,6 @@ public: private: enum class State { kEmpty, - kDrawBitmapRectFixedSize, kDrawPath, kDrawRect, kDrawTextBlob, @@ -50,10 +47,9 @@ private: struct Max { static const size_t val = A > B ? A : B; }; static const size_t kInlineStorage = - Max::val>::val>::val; + sizeof(SkRecords::DrawTextBlob)>::val>::val; SkAlignedSStorage fBuffer; }; diff --git a/gfx/skia/skia/include/private/SkMutex.h b/gfx/skia/skia/include/private/SkMutex.h index 8c78e1205c87..7cfdb1132c2f 100644 --- a/gfx/skia/skia/include/private/SkMutex.h +++ b/gfx/skia/skia/include/private/SkMutex.h @@ -8,33 +8,16 @@ #ifndef SkMutex_DEFINED #define SkMutex_DEFINED -// This file is not part of the public Skia API. #include "../private/SkSemaphore.h" +#include "../private/SkThreadID.h" #include "SkTypes.h" -#ifdef SK_DEBUG - #include "../private/SkThreadID.h" -#endif +#define SK_DECLARE_STATIC_MUTEX(name) static SkBaseMutex name; -#define SK_MUTEX_SEMAPHORE_INIT {1, {0}} +class SkBaseMutex { +public: + constexpr SkBaseMutex() = default; -#ifdef SK_DEBUG - #define SK_BASE_MUTEX_INIT {SK_MUTEX_SEMAPHORE_INIT, 0} -#else - #define SK_BASE_MUTEX_INIT {SK_MUTEX_SEMAPHORE_INIT} -#endif - -// Using POD-style initialization prevents the generation of a static initializer. -// -// Without magic statics there are no thread safety guarantees on initialization -// of local statics (even POD). As a result, it is illegal to use -// SK_DECLARE_STATIC_MUTEX in a function. -// -// Because SkBaseMutex is not a primitive, a static SkBaseMutex cannot be -// initialized in a class with this macro. -#define SK_DECLARE_STATIC_MUTEX(name) namespace {} static SkBaseMutex name = SK_BASE_MUTEX_INIT; - -struct SkBaseMutex { void acquire() { fSemaphore.wait(); SkDEBUGCODE(fOwner = SkGetThreadID();) @@ -50,76 +33,61 @@ struct SkBaseMutex { SkASSERT(fOwner == SkGetThreadID()); } - SkBaseSemaphore fSemaphore; - SkDEBUGCODE(SkThreadID fOwner;) +protected: + SkBaseSemaphore fSemaphore{1}; + SkDEBUGCODE(SkThreadID fOwner{kIllegalThreadID};) }; -// This needs to use subclassing instead of encapsulation to make SkAutoMutexAcquire to work. class SkMutex : public SkBaseMutex { public: - SkMutex () { - fSemaphore = SK_MUTEX_SEMAPHORE_INIT; - SkDEBUGCODE(fOwner = kIllegalThreadID); - } - ~SkMutex () { fSemaphore.deleteSemaphore(); } - SkMutex(const SkMutex&) = delete; - SkMutex& operator=(const SkMutex&) = delete; + using SkBaseMutex::SkBaseMutex; + ~SkMutex() { fSemaphore.cleanup(); } }; -template -class SkAutoTAcquire : SkNoncopyable { +class SkAutoMutexAcquire { public: - explicit SkAutoTAcquire(Lock& mutex) : fMutex(&mutex) { - SkASSERT(fMutex != nullptr); - mutex.acquire(); - } - - explicit SkAutoTAcquire(Lock* mutex) : fMutex(mutex) { + template + SkAutoMutexAcquire(T* mutex) : fMutex(mutex) { if (mutex) { mutex->acquire(); } + fRelease = [](void* mutex) { ((T*)mutex)->release(); }; } - /** If the mutex has not been released, release it now. */ - ~SkAutoTAcquire() { - if (fMutex) { - fMutex->release(); - } - } + template + SkAutoMutexAcquire(T& mutex) : SkAutoMutexAcquire(&mutex) {} + + ~SkAutoMutexAcquire() { this->release(); } - /** If the mutex has not been released, release it now. */ void release() { if (fMutex) { - fMutex->release(); - fMutex = nullptr; + fRelease(fMutex); } - } - - /** Assert that we're holding the mutex. */ - void assertHeld() { - SkASSERT(fMutex); - fMutex->assertHeld(); + fMutex = nullptr; } private: - Lock* fMutex; + void* fMutex; + void (*fRelease)(void*); }; - -// SkAutoTExclusive is a lighter weight version of SkAutoTAcquire. It assumes that there is a valid -// mutex, thus removing the check for the null pointer. -template -class SkAutoTExclusive { -public: - SkAutoTExclusive(Lock& lock) : fLock(lock) { lock.acquire(); } - ~SkAutoTExclusive() { fLock.release(); } -private: - Lock &fLock; -}; - -typedef SkAutoTAcquire SkAutoMutexAcquire; #define SkAutoMutexAcquire(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexAcquire) -typedef SkAutoTExclusive SkAutoMutexExclusive; -#define SkAutoMutexExclusive(...) SK_REQUIRE_LOCAL_VAR(SkAutoMutexExclusive) +// 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/gfx/skia/skia/include/private/SkOnce.h b/gfx/skia/skia/include/private/SkOnce.h index 5434d9d7d9d3..65334e3a26af 100644 --- a/gfx/skia/skia/include/private/SkOnce.h +++ b/gfx/skia/skia/include/private/SkOnce.h @@ -8,132 +8,43 @@ #ifndef SkOnce_DEFINED #define SkOnce_DEFINED -// Before trying SkOnce, see if SkLazyPtr or SkLazyFnPtr will work for you. -// They're smaller and faster, if slightly less versatile. +#include +#include +#include "SkTypes.h" - -// SkOnce.h defines SK_DECLARE_STATIC_ONCE and SkOnce(), which you can use -// together to create a threadsafe way to call a function just once. E.g. +// SkOnce provides call-once guarantees for Skia, much like std::once_flag/std::call_once(). // -// static void register_my_stuff(GlobalRegistry* registry) { -// registry->register(...); -// } -// ... -// void EnsureRegistered() { -// SK_DECLARE_STATIC_ONCE(once); -// SkOnce(&once, register_my_stuff, GetGlobalRegistry()); -// } -// -// No matter how many times you call EnsureRegistered(), register_my_stuff will be called just once. -// OnceTest.cpp also should serve as a few other simple examples. +// 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. -#include "../private/SkAtomics.h" -#include "../private/SkSpinlock.h" - -// This must be used in a global scope, not in function scope or as a class member. -#define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name - -class SkOnceFlag; - -inline void SkOnce(SkOnceFlag* once, void (*f)()); - -template -inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg); - -// If you've already got a lock and a flag to use, this variant lets you avoid an extra SkOnceFlag. -template -inline void SkOnce(bool* done, Lock* lock, void (*f)()); - -template -inline void SkOnce(bool* done, Lock* lock, void (*f)(Arg), Arg arg); - -// ---------------------- Implementation details below here. ----------------------------- - -// This class has no constructor and must be zero-initialized (the macro above does this). -class SkOnceFlag { +class SkOnce { public: - bool* mutableDone() { return &fDone; } + constexpr SkOnce() = default; - void acquire() { fSpinlock.acquire(); } - void release() { fSpinlock.release(); } + 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)) { + // 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: - bool fDone; - SkSpinlock fSpinlock; + enum State : uint8_t { NotStarted, Claimed, Done}; + std::atomic fState{NotStarted}; }; -// We've pulled a pretty standard double-checked locking implementation apart -// into its main fast path and a slow path that's called when we suspect the -// one-time code hasn't run yet. - -// This is the guts of the code, called when we suspect the one-time code hasn't been run yet. -// This should be rarely called, so we separate it from SkOnce and don't mark it as inline. -// (We don't mind if this is an actual function call, but odds are it'll be inlined anyway.) -template -static void sk_once_slow(bool* done, Lock* lock, void (*f)(Arg), Arg arg) { - lock->acquire(); - if (!sk_atomic_load(done, sk_memory_order_relaxed)) { - f(arg); - // Also known as a store-store/load-store barrier, this makes sure that the writes - // done before here---in particular, those done by calling f(arg)---are observable - // before the writes after the line, *done = true. - // - // In version control terms this is like saying, "check in the work up - // to and including f(arg), then check in *done=true as a subsequent change". - // - // We'll use this in the fast path to make sure f(arg)'s effects are - // observable whenever we observe *done == true. - sk_release_store(done, true); - } - lock->release(); -} - -// This is our fast path, called all the time. We do really want it to be inlined. -template -inline void SkOnce(bool* done, Lock* lock, void (*f)(Arg), Arg arg) { - // When *done == true: - // Also known as a load-load/load-store barrier, this acquire barrier makes - // sure that anything we read from memory---in particular, memory written by - // calling f(arg)---is at least as current as the value we read from done. - // - // In version control terms, this is a lot like saying "sync up to the - // commit where we wrote done = true". - // - // The release barrier in sk_once_slow guaranteed that done = true - // happens after f(arg), so by syncing to done = true here we're - // forcing ourselves to also wait until the effects of f(arg) are readble. - // - // When *done == false: - // We'll try to call f(arg) in sk_once_slow. - // If we get the lock, great, we call f(arg), release true into done, and drop the lock. - // If we race and don't get the lock first, we'll wait for the first guy to finish. - // Then lock acquire() will give us at least an acquire memory barrier to get the same - // effect as the acquire load in the *done == true fast case. We'll see *done is true, - // then just drop the lock and return. - if (!sk_atomic_load(done, sk_memory_order_acquire)) { - sk_once_slow(done, lock, f, arg); - } -} - -template -inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg) { - return SkOnce(once->mutableDone(), once, f, arg); -} - -// Calls its argument. -// This lets us use functions that take no arguments with SkOnce methods above. -// (We pass _this_ as the function and the no-arg function as its argument. Cute eh?) -static void sk_once_no_arg_adaptor(void (*f)()) { - f(); -} - -inline void SkOnce(SkOnceFlag* once, void (*func)()) { - return SkOnce(once, sk_once_no_arg_adaptor, func); -} - -template -inline void SkOnce(bool* done, Lock* lock, void (*func)()) { - return SkOnce(done, lock, sk_once_no_arg_adaptor, func); -} - #endif // SkOnce_DEFINED diff --git a/gfx/skia/skia/include/private/SkOncePtr.h b/gfx/skia/skia/include/private/SkOncePtr.h deleted file mode 100644 index 3c1ab634ee43..000000000000 --- a/gfx/skia/skia/include/private/SkOncePtr.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 SkOncePtr_DEFINED -#define SkOncePtr_DEFINED - -#include "../private/SkAtomics.h" -#include - -template class SkBaseOncePtr; - -// Use this to create a global static pointer that's intialized exactly once when you call get(). -#define SK_DECLARE_STATIC_ONCE_PTR(type, name) namespace {} static SkBaseOncePtr name; - -// Use this for a local or member pointer that's initialized exactly once when you call get(). -template > -class SkOncePtr : SkNoncopyable { -public: - SkOncePtr() { sk_bzero(this, sizeof(*this)); } - ~SkOncePtr() { - if (T* ptr = (T*)*this) { - Delete()(ptr); - } - } - - template - T* get(const F& f) const { - return fOnce.get(f); - } - - operator T*() const { - return (T*)fOnce; - } - -private: - SkBaseOncePtr fOnce; -}; - -// If you ask for SkOncePtr, we'll clean up with delete[] by default. -template -class SkOncePtr : public SkOncePtr> {}; - -/* TODO(mtklein): in next CL -typedef SkBaseOncePtr SkOnceFlag; -#define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name - -template -inline void SkOnce(SkOnceFlag* once, const F& f) { - once->get([&]{ f(); return (void*)2; }); -} -*/ - -// Implementation details below here! No peeking! - -template -class SkBaseOncePtr { -public: - template - T* get(const F& f) const { - uintptr_t state = sk_atomic_load(&fState, sk_memory_order_acquire); - if (state < 2) { - if (state == 0) { - // It looks like no one has tried to create our pointer yet. - // We try to claim that task by atomically swapping our state from '0' to '1'. - if (sk_atomic_compare_exchange( - &fState, &state, (uintptr_t)1, sk_memory_order_relaxed, sk_memory_order_relaxed)) { - // We've claimed it. Create our pointer and store it into fState. - state = (uintptr_t)f(); - SkASSERT(state > 1); - sk_atomic_store(&fState, state, sk_memory_order_release); - } else { - // Someone else claimed it. - // We fall through to the spin loop just below to wait for them to finish. - } - } - - while (state == 1) { - // State '1' is our busy-but-not-done state. - // Some other thread has claimed the job of creating our pointer. - // We just need to wait for it to finish. - state = sk_atomic_load(&fState, sk_memory_order_acquire); - } - - // We shouldn't be able to get here without having created our pointer. - SkASSERT(state > 1); - } - return (T*)state; - } - - operator T*() const { - auto state = sk_atomic_load(&fState, sk_memory_order_acquire); - return state < 2 ? nullptr : (T*)state; - // TODO: If state == 1 spin until it's not? - } - - // fState == 0 --> we have not created our ptr yet - // fState == 1 --> someone is in the middle of creating our ptr - // else --> (T*)fState is our ptr - mutable uintptr_t fState; -}; - -#endif//SkOncePtr_DEFINED diff --git a/gfx/skia/skia/include/private/SkRecords.h b/gfx/skia/skia/include/private/SkRecords.h index 1e274e9f46a2..05f935b3ced9 100644 --- a/gfx/skia/skia/include/private/SkRecords.h +++ b/gfx/skia/skia/include/private/SkRecords.h @@ -21,6 +21,14 @@ #include "SkString.h" #include "SkTextBlob.h" +// Windows.h, will pull in all of the GDI defines. GDI #defines +// DrawText to DrawTextA or DrawTextW, but SkRecord has a struct +// called DrawText. Since this file does not use GDI, undefing +// DrawText makes things less confusing. +#ifdef DrawText +#undef DrawText +#endif + namespace SkRecords { // A list of all the types of canvas calls we can record. @@ -39,18 +47,17 @@ namespace SkRecords { M(Save) \ M(SaveLayer) \ M(SetMatrix) \ + M(Translate) \ + M(TranslateZ) \ M(Concat) \ M(ClipPath) \ M(ClipRRect) \ M(ClipRect) \ M(ClipRegion) \ - M(DrawBitmap) \ - M(DrawBitmapNine) \ - M(DrawBitmapRect) \ - M(DrawBitmapRectFast) \ - M(DrawBitmapRectFixedSize) \ + M(DrawArc) \ M(DrawDrawable) \ M(DrawImage) \ + M(DrawImageLattice) \ M(DrawImageRect) \ M(DrawImageNine) \ M(DrawDRRect) \ @@ -59,13 +66,16 @@ namespace SkRecords { M(DrawPath) \ M(DrawPatch) \ M(DrawPicture) \ + M(DrawShadowedPicture) \ M(DrawPoints) \ M(DrawPosText) \ M(DrawPosTextH) \ M(DrawText) \ M(DrawTextOnPath) \ + M(DrawTextRSXform) \ M(DrawRRect) \ M(DrawRect) \ + M(DrawRegion) \ M(DrawTextBlob) \ M(DrawAtlas) \ M(DrawVertices) \ @@ -80,22 +90,6 @@ enum Type { SK_RECORD_TYPES(ENUM) }; operator T*() const { return ptr; } \ T* operator->() const { return ptr; } -template -class RefBox : SkNoncopyable { -public: - RefBox() {} - RefBox(T* obj) : fObj(SkSafeRef(obj)) {} - RefBox(RefBox&& o) : fObj(o.fObj) { - o.fObj = nullptr; - } - ~RefBox() { SkSafeUnref(fObj); } - - ACT_AS_PTR(fObj); - -private: - T* fObj; -}; - // An Optional doesn't own the pointer's memory, but may need to destroy non-POD data. template class Optional : SkNoncopyable { @@ -107,7 +101,7 @@ public: } ~Optional() { if (fPtr) fPtr->~T(); } - ACT_AS_PTR(fPtr); + ACT_AS_PTR(fPtr) private: T* fPtr; }; @@ -124,7 +118,7 @@ public: } ~Adopted() { if (fPtr) fPtr->~T(); } - ACT_AS_PTR(fPtr); + ACT_AS_PTR(fPtr) private: T* fPtr; }; @@ -137,32 +131,13 @@ public: PODArray(T* ptr) : fPtr(ptr) {} // Default copy and assign. - ACT_AS_PTR(fPtr); + ACT_AS_PTR(fPtr) private: T* fPtr; }; #undef ACT_AS_PTR -// Like SkBitmap, but deep copies pixels if they're not immutable. -// Using this, we guarantee the immutability of all bitmaps we record. -class ImmutableBitmap : SkNoncopyable { -public: - ImmutableBitmap() {} - ImmutableBitmap(const SkBitmap& bitmap); - ImmutableBitmap(ImmutableBitmap&& o) { - fBitmap.swap(o.fBitmap); - } - - int width() const { return fBitmap.width(); } - int height() const { return fBitmap.height(); } - - // While the pixels are immutable, SkBitmap itself is not thread-safe, so return a copy. - SkBitmap shallowCopy() const { return fBitmap; } -private: - SkBitmap fBitmap; -}; - // SkPath::getBounds() isn't thread safe unless we precache the bounds in a singlethreaded context. // SkPath::cheapComputeDirection() is similar. // Recording is a convenient time to cache these, or we can delay it to between record and playback. @@ -182,6 +157,7 @@ enum Tags { kDraw_Tag = 1, // May draw something (usually named DrawFoo). kHasImage_Tag = 2, // Contains an SkImage or SkBitmap. kHasText_Tag = 4, // Contains text. + kHasPaint_Tag = 8, // May have an SkPaint field, at least optionally. }; // A macro to make it a little easier to define a struct that can be stored in SkRecord. @@ -198,10 +174,10 @@ RECORD(Restore, 0, TypedMatrix matrix); RECORD(Save, 0); -RECORD(SaveLayer, 0, +RECORD(SaveLayer, kHasPaint_Tag, Optional bounds; Optional paint; - RefBox backdrop; + sk_sp backdrop; SkCanvas::SaveLayerFlags saveLayerFlags); RECORD(SetMatrix, 0, @@ -209,59 +185,44 @@ RECORD(SetMatrix, 0, RECORD(Concat, 0, TypedMatrix matrix); -struct RegionOpAndAA { - RegionOpAndAA() {} - RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {} - SkRegion::Op op : 31; // This really only needs to be 3, but there's no win today to do so. - unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. +RECORD(Translate, 0, + SkScalar dx; + SkScalar dy); +RECORD(TranslateZ, 0, SkScalar z); + +struct ClipOpAndAA { + ClipOpAndAA() {} + ClipOpAndAA(SkCanvas::ClipOp op, bool aa) : op(op), aa(aa) {} + SkCanvas::ClipOp op : 31; // This really only needs to be 3, but there's no win today to do so. + unsigned aa : 1; // MSVC won't pack an enum with an bool, so we call this an unsigned. }; -static_assert(sizeof(RegionOpAndAA) == 4, "RegionOpAndAASize"); +static_assert(sizeof(ClipOpAndAA) == 4, "ClipOpAndAASize"); RECORD(ClipPath, 0, SkIRect devBounds; PreCachedPath path; - RegionOpAndAA opAA); + ClipOpAndAA opAA); RECORD(ClipRRect, 0, SkIRect devBounds; SkRRect rrect; - RegionOpAndAA opAA); + ClipOpAndAA opAA); RECORD(ClipRect, 0, SkIRect devBounds; SkRect rect; - RegionOpAndAA opAA); + ClipOpAndAA opAA); RECORD(ClipRegion, 0, SkIRect devBounds; SkRegion region; - SkRegion::Op op); + SkCanvas::ClipOp op); // While not strictly required, if you have an SkPaint, it's fastest to put it first. -RECORD(DrawBitmap, kDraw_Tag|kHasImage_Tag, - Optional paint; - ImmutableBitmap bitmap; - SkScalar left; - SkScalar top); -RECORD(DrawBitmapNine, kDraw_Tag|kHasImage_Tag, - Optional paint; - ImmutableBitmap bitmap; - SkIRect center; - SkRect dst); -RECORD(DrawBitmapRect, kDraw_Tag|kHasImage_Tag, - Optional paint; - ImmutableBitmap bitmap; - Optional src; - SkRect dst); -RECORD(DrawBitmapRectFast, kDraw_Tag|kHasImage_Tag, - Optional paint; - ImmutableBitmap bitmap; - Optional src; - SkRect dst); -RECORD(DrawBitmapRectFixedSize, kDraw_Tag|kHasImage_Tag, - SkPaint paint; - ImmutableBitmap bitmap; - SkRect src; - SkRect dst; - SkCanvas::SrcRectConstraint constraint); -RECORD(DrawDRRect, kDraw_Tag, +RECORD(DrawArc, kDraw_Tag|kHasPaint_Tag, + SkPaint paint; + SkRect oval; + SkScalar startAngle; + SkScalar sweepAngle; + unsigned useCenter); +RECORD(DrawDRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect outer; SkRRect inner); @@ -269,102 +230,127 @@ RECORD(DrawDrawable, kDraw_Tag, Optional matrix; SkRect worstCaseBounds; int32_t index); -RECORD(DrawImage, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImage, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; - RefBox image; + sk_sp image; SkScalar left; SkScalar top); -RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImageLattice, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; - RefBox image; + sk_sp image; + int xCount; + PODArray xDivs; + int yCount; + PODArray yDivs; + int flagCount; + PODArray flags; + SkIRect src; + SkRect dst); +RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, + Optional paint; + sk_sp image; Optional src; SkRect dst; SkCanvas::SrcRectConstraint constraint); -RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag, +RECORD(DrawImageNine, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; - RefBox image; + sk_sp image; SkIRect center; SkRect dst); -RECORD(DrawOval, kDraw_Tag, +RECORD(DrawOval, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect oval); -RECORD(DrawPaint, kDraw_Tag, +RECORD(DrawPaint, kDraw_Tag|kHasPaint_Tag, SkPaint paint); -RECORD(DrawPath, kDraw_Tag, +RECORD(DrawPath, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PreCachedPath path); -RECORD(DrawPicture, kDraw_Tag, +RECORD(DrawPicture, kDraw_Tag|kHasPaint_Tag, Optional paint; - RefBox picture; + sk_sp picture; TypedMatrix matrix); -RECORD(DrawPoints, kDraw_Tag, +RECORD(DrawShadowedPicture, kDraw_Tag|kHasPaint_Tag, + Optional paint; + sk_sp picture; + TypedMatrix matrix; + const SkShadowParams& params); +RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::PointMode mode; unsigned count; SkPoint* pts); -RECORD(DrawPosText, kDraw_Tag|kHasText_Tag, +RECORD(DrawPosText, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; PODArray pos); -RECORD(DrawPosTextH, kDraw_Tag|kHasText_Tag, +RECORD(DrawPosTextH, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; unsigned byteLength; SkScalar y; PODArray xpos); -RECORD(DrawRRect, kDraw_Tag, +RECORD(DrawRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect rrect); -RECORD(DrawRect, kDraw_Tag, +RECORD(DrawRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRect rect); -RECORD(DrawText, kDraw_Tag|kHasText_Tag, +RECORD(DrawRegion, kDraw_Tag|kHasPaint_Tag, + SkPaint paint; + SkRegion region); +RECORD(DrawText, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; SkScalar x; SkScalar y); -RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag, +RECORD(DrawTextBlob, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; - RefBox blob; + sk_sp blob; SkScalar x; SkScalar y); -RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag, +RECORD(DrawTextOnPath, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, SkPaint paint; PODArray text; size_t byteLength; PreCachedPath path; TypedMatrix matrix); -RECORD(DrawPatch, kDraw_Tag, +RECORD(DrawTextRSXform, kDraw_Tag|kHasText_Tag|kHasPaint_Tag, + SkPaint paint; + PODArray text; + size_t byteLength; + PODArray xforms; + Optional cull); +RECORD(DrawPatch, kDraw_Tag|kHasPaint_Tag, SkPaint paint; PODArray cubics; PODArray colors; PODArray texCoords; - RefBox xmode); -RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag, + sk_sp xmode); +RECORD(DrawAtlas, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag, Optional paint; - RefBox atlas; + sk_sp atlas; PODArray xforms; PODArray texs; PODArray colors; int count; SkXfermode::Mode mode; Optional cull); -RECORD(DrawVertices, kDraw_Tag, +RECORD(DrawVertices, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::VertexMode vmode; int vertexCount; PODArray vertices; PODArray texs; PODArray colors; - RefBox xmode; + sk_sp xmode; PODArray indices; int indexCount); -RECORD(DrawAnnotation, 0, +RECORD(DrawAnnotation, 0, // TODO: kDraw_Tag, skia:5548 SkRect rect; SkString key; - RefBox value); + sk_sp value); #undef RECORD } // namespace SkRecords diff --git a/gfx/skia/skia/include/private/SkSemaphore.h b/gfx/skia/skia/include/private/SkSemaphore.h index cb2f58da4a27..3da2b99ab4a9 100644 --- a/gfx/skia/skia/include/private/SkSemaphore.h +++ b/gfx/skia/skia/include/private/SkSemaphore.h @@ -8,43 +8,27 @@ #ifndef SkSemaphore_DEFINED #define SkSemaphore_DEFINED +#include "../private/SkOnce.h" #include "SkTypes.h" -#include "../private/SkAtomics.h" -#include "../private/SkOncePtr.h" +#include -struct SkBaseSemaphore { +class SkBaseSemaphore { +public: + constexpr SkBaseSemaphore(int count = 0) + : fCount(count), fOSSemaphore(nullptr) {} - // Increment the counter by 1. - // This is a specialization for supporting SkMutex. - void signal() { - // Since this fetches the value before the add, 0 indicates that this thread is running and - // no threads are waiting, -1 and below means that threads are waiting, but only signal 1 - // thread to run. - if (sk_atomic_fetch_add(&fCount, 1, sk_memory_order_release) < 0) { - this->osSignal(1); - } - } - - // Increment the counter N times. - // Generally it's better to call signal(N) instead of signal() N times. - void signal(int N); + // 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() { - // 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 (sk_atomic_fetch_sub(&fCount, 1, sk_memory_order_acquire) <= 0) { - this->osWait(); - } - } + void wait(); - struct OSSemaphore; - - void osSignal(int n); - void osWait(); - void deleteSemaphore(); + // 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 @@ -54,33 +38,46 @@ struct SkBaseSemaphore { // 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. - int fCount; - SkBaseOncePtr fOSSemaphore; + struct OSSemaphore; + + void osSignal(int n); + void osWait(); + + std::atomic fCount; + SkOnce fOSSemaphoreOnce; + OSSemaphore* fOSSemaphore; }; -/** - * SkSemaphore is a fast mostly-user-space semaphore. - * - * A semaphore is logically an atomic integer with a few special properties: - * - The integer always starts at 0. - * - You can only increment or decrement it, never read or write it. - * - Increment is spelled 'signal()'; decrement is spelled 'wait()'. - * - If a call to wait() decrements the counter to <= 0, - * the calling thread sleeps until another thread signal()s it back above 0. - */ -class SkSemaphore : SkNoncopyable { +class SkSemaphore : public SkBaseSemaphore { public: - // Initializes the counter to 0. - // (Though all current implementations could start from an arbitrary value.) - SkSemaphore(); - ~SkSemaphore(); - - void wait(); - - void signal(int n = 1); - -private: - SkBaseSemaphore fBaseSemaphore; + 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/gfx/skia/skia/include/private/SkShadowParams.h b/gfx/skia/skia/include/private/SkShadowParams.h new file mode 100644 index 000000000000..3df0a442796a --- /dev/null +++ b/gfx/skia/skia/include/private/SkShadowParams.h @@ -0,0 +1,48 @@ +/* + * 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 SkShadowParams_DEFINED +#define SkShadowParams_DEFINED + +/** \struct SkShadowParams + + This struct holds information needed for drawing shadows. + + fShadowRadius - radius of the shadow blur + + fBiasingConstant - A constant used in variance shadow mapping to directly + 0.0 - 1.0 reduce light bleeding. Essentially sets all shadows + ~.25 below a certain brightness equal to no light, and does + a linear step on the rest. Essentially makes shadows + darker and more rounded at higher values. + + fMinVariance - Too low of a variance (near the outer edges of blurry + ~512, 1024 shadows) will lead to ugly sharp shadow brightness + distortions. This enforces a minimum amount of variance + in the calculation to smooth out the outside edges of + blurry shadows. However, too high of a value for this will + cause all shadows to be lighter by visibly different + amounts varying on depth. + + fType - Decides which algorithm to use to draw shadows. +*/ +struct SkShadowParams { + SkScalar fShadowRadius; + SkScalar fBiasingConstant; + SkScalar fMinVariance; + + enum ShadowType { + kNoBlur_ShadowType, + kVariance_ShadowType, + + kLast_ShadowType = kVariance_ShadowType + }; + static const int kShadowTypeCount = kLast_ShadowType + 1; + + ShadowType fType; +}; + +#endif diff --git a/gfx/skia/skia/include/private/SkSpinlock.h b/gfx/skia/skia/include/private/SkSpinlock.h index da3b6dd51193..a5d378289ffa 100644 --- a/gfx/skia/skia/include/private/SkSpinlock.h +++ b/gfx/skia/skia/include/private/SkSpinlock.h @@ -9,13 +9,15 @@ #define SkSpinlock_DEFINED #include "SkTypes.h" -#include "SkAtomics.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, sk_memory_order_acquire)) { + if (fLocked.exchange(true, std::memory_order_acquire)) { // Lock was contended. Fall back to an out-of-line spin loop. this->contendedAcquire(); } @@ -23,13 +25,13 @@ public: void release() { // To act as a mutex, we need a release barrier when we release the lock. - fLocked.store(false, sk_memory_order_release); + fLocked.store(false, std::memory_order_release); } private: SK_API void contendedAcquire(); - SkAtomic fLocked{false}; + std::atomic fLocked{false}; }; #endif//SkSpinlock_DEFINED diff --git a/gfx/skia/skia/include/private/SkTArray.h b/gfx/skia/skia/include/private/SkTArray.h index cdaa5f675de4..f7c18be40fbc 100644 --- a/gfx/skia/skia/include/private/SkTArray.h +++ b/gfx/skia/skia/include/private/SkTArray.h @@ -8,9 +8,9 @@ #ifndef SkTArray_DEFINED #define SkTArray_DEFINED -#include "SkTypes.h" #include "../private/SkTLogic.h" #include "../private/SkTemplates.h" +#include "SkTypes.h" #include #include @@ -38,14 +38,20 @@ public: * elements. */ explicit SkTArray(int reserveCount) { - this->init(NULL, 0, NULL, reserveCount); + this->init(0, NULL, reserveCount); } /** * Copies one array to another. The new array will be heap allocated. */ - explicit SkTArray(const SkTArray& array) { - this->init(array.fItemArray, array.fCount, NULL, 0); + explicit SkTArray(const SkTArray& that) { + this->init(that.fCount, NULL, 0); + this->copy(that.fItemArray); + } + SkTArray(SkTArray&& that) { + this->init(that.fCount, NULL, 0); + that.move(fMemArray); + that.fCount = 0; } /** @@ -54,20 +60,32 @@ public: * when you really want the (void*, int) version. */ SkTArray(const T* array, int count) { - this->init(array, count, NULL, 0); + this->init(count, NULL, 0); + this->copy(array); } /** * assign copy of array to this */ - SkTArray& operator =(const SkTArray& array) { + SkTArray& operator =(const SkTArray& that) { for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } fCount = 0; - this->checkRealloc((int)array.count()); - fCount = array.count(); - this->copy(static_cast(array.fMemArray)); + this->checkRealloc(that.count()); + fCount = that.count(); + this->copy(that.fItemArray); + return *this; + } + SkTArray& operator =(SkTArray&& that) { + 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; } @@ -93,7 +111,7 @@ public: for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } - // set fCount to 0 before calling checkRealloc so that no copy cons. are called. + // Set fCount to 0 before calling checkRealloc so that no elements are moved. fCount = 0; this->checkRealloc(n); fCount = n; @@ -102,6 +120,15 @@ public: } } + /** + * Ensures there is enough reserved space for n elements. + */ + void reserve(int n) { + if (fCount < n) { + this->checkRealloc(n - fCount); + } + } + /** * Resets to a copy of a C array. */ @@ -109,8 +136,8 @@ public: for (int i = 0; i < fCount; ++i) { fItemArray[i].~T(); } - int delta = count - fCount; - this->checkRealloc(delta); + fCount = 0; + this->checkRealloc(count); fCount = count; this->copy(array); } @@ -141,35 +168,32 @@ public: * elements. */ T& push_back() { - T* newT = reinterpret_cast(this->push_back_raw(1)); - new (newT) T; - return *newT; + 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) { - T* newT = reinterpret_cast(this->push_back_raw(1)); - new (newT) T(t); - return *newT; + 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) { - T* newT = reinterpret_cast(this->push_back_raw(1)); - new (newT) T(std__move(t)); - return *newT; + 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) { - T* newT = reinterpret_cast(this->push_back_raw(1)); - return *new (newT) T(std__forward(args)...); + void* newT = this->push_back_raw(1); + return *new (newT) T(std::forward(args)...); } /** @@ -179,11 +203,11 @@ public: */ T* push_back_n(int n) { SkASSERT(n >= 0); - T* newTs = reinterpret_cast(this->push_back_raw(n)); + void* newTs = this->push_back_raw(n); for (int i = 0; i < n; ++i) { - new (newTs + i) T; + new (static_cast(newTs) + i * sizeof(T)) T; } - return newTs; + return static_cast(newTs); } /** @@ -192,11 +216,11 @@ public: */ T* push_back_n(int n, const T& t) { SkASSERT(n >= 0); - T* newTs = reinterpret_cast(this->push_back_raw(n)); + void* newTs = this->push_back_raw(n); for (int i = 0; i < n; ++i) { - new (newTs + i) T(t); + new (static_cast(newTs) + i * sizeof(T)) T(t); } - return newTs; + return static_cast(newTs); } /** @@ -213,6 +237,19 @@ public: 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. */ @@ -264,9 +301,9 @@ public: SkTSwap(fAllocCount, that->fAllocCount); } else { // This could be more optimal... - SkTArray copy(*that); - *that = *this; - *this = copy; + SkTArray copy(std::move(*that)); + *that = std::move(*this); + *this = std::move(copy); } } @@ -351,7 +388,7 @@ protected: */ template SkTArray(SkAlignedSTStorage* storage) { - this->init(NULL, 0, storage->get(), N); + this->init(0, storage->get(), N); } /** @@ -361,7 +398,8 @@ protected: */ template SkTArray(const SkTArray& array, SkAlignedSTStorage* storage) { - this->init(array.fItemArray, array.fCount, storage->get(), N); + this->init(array.fCount, storage->get(), N); + this->copy(array.fItemArray); } /** @@ -371,11 +409,11 @@ protected: */ template SkTArray(const T* array, int count, SkAlignedSTStorage* storage) { - this->init(array, count, storage->get(), N); + this->init(count, storage->get(), N); + this->copy(array); } - void init(const T* array, int count, - void* preAllocStorage, int preAllocOrReserveCount) { + void init(int count, void* preAllocStorage, int preAllocOrReserveCount) { SkASSERT(count >= 0); SkASSERT(preAllocOrReserveCount >= 0); fCount = count; @@ -391,8 +429,6 @@ protected: fAllocCount = SkMax32(fCount, fReserveCount); fMemArray = sk_malloc_throw(fAllocCount * sizeof(T)); } - - this->copy(array); } private: @@ -405,7 +441,7 @@ private: template SK_WHEN(E, void) move(int dst, int src) { memcpy(&fItemArray[dst], &fItemArray[src], sizeof(T)); } - template SK_WHEN(E, void) move(char* dst) { + template SK_WHEN(E, void) move(void* dst) { sk_careful_memcpy(dst, fMemArray, fCount * sizeof(T)); } @@ -415,12 +451,12 @@ private: } } template SK_WHEN(!E, void) move(int dst, int src) { - new (&fItemArray[dst]) T(std__move(fItemArray[src])); + new (&fItemArray[dst]) T(std::move(fItemArray[src])); fItemArray[src].~T(); } - template SK_WHEN(!E, void) move(char* dst) { + template SK_WHEN(!E, void) move(void* dst) { for (int i = 0; i < fCount; ++i) { - new (dst + sizeof(T) * i) T(std__move(fItemArray[i])); + new (static_cast(dst) + sizeof(T) * i) T(std::move(fItemArray[i])); fItemArray[i].~T(); } } @@ -453,12 +489,12 @@ private: if (newAllocCount != fAllocCount) { fAllocCount = newAllocCount; - char* newMemArray; + void* newMemArray; if (fAllocCount == fReserveCount && fPreAllocMemArray) { - newMemArray = (char*) fPreAllocMemArray; + newMemArray = fPreAllocMemArray; } else { - newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T)); + newMemArray = sk_malloc_throw(fAllocCount*sizeof(T)); } this->move(newMemArray); diff --git a/gfx/skia/skia/include/private/SkTDArray.h b/gfx/skia/skia/include/private/SkTDArray.h index 8af54bbcc5bb..f71d3570056b 100644 --- a/gfx/skia/skia/include/private/SkTDArray.h +++ b/gfx/skia/skia/include/private/SkTDArray.h @@ -14,10 +14,7 @@ template class SkTDArray { public: - SkTDArray() { - fReserve = fCount = 0; - fArray = NULL; - } + SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {} SkTDArray(const T src[], int count) { SkASSERT(src || count == 0); @@ -29,12 +26,13 @@ public: fReserve = fCount = count; } } - SkTDArray(const SkTDArray& src) { - fReserve = fCount = 0; - fArray = NULL; + 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); } @@ -51,6 +49,13 @@ public: } 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 && @@ -212,6 +217,18 @@ public: } } + template int select(S&& selector) const { + const T* iter = fArray; + const T* stop = fArray + fCount; + + for (; iter < stop; iter++) { + if (selector(*iter)) { + return SkToInt(iter - fArray); + } + } + return -1; + } + int find(const T& elem) const { const T* iter = fArray; const T* stop = fArray + fCount; diff --git a/gfx/skia/skia/include/private/SkTFitsIn.h b/gfx/skia/skia/include/private/SkTFitsIn.h index 8e8c2b1ba9fa..4802aff1eb72 100644 --- a/gfx/skia/skia/include/private/SkTFitsIn.h +++ b/gfx/skia/skia/include/private/SkTFitsIn.h @@ -10,6 +10,7 @@ #include "../private/SkTLogic.h" #include +#include namespace sktfitsin { namespace Private { diff --git a/gfx/skia/skia/include/private/SkTLogic.h b/gfx/skia/skia/include/private/SkTLogic.h index bc4cce57dc54..2b12434d0dc7 100644 --- a/gfx/skia/skia/include/private/SkTLogic.h +++ b/gfx/skia/skia/include/private/SkTLogic.h @@ -14,92 +14,11 @@ #ifndef SkTLogic_DEFINED #define SkTLogic_DEFINED -#include +#include #include -#include -#include -#include -#include - -#if MOZ_SKIA_AVOID_CXX11 -#include "mozilla/Function.h" -#include "mozilla/Move.h" -#include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" - -namespace std { - #define std__forward mozilla::Forward - #define std__move mozilla::Move -#if SKIA_IMPLEMENTATION - using mozilla::Forward; - using mozilla::Move; - #define forward Forward - #define move Move -#endif - - // If we have 'using mozilla::function', we're going to collide with - // 'std::function' on platforms that have it. Therefore we use a macro - // work around. - template - using moz_function = mozilla::function; - #define std__function std::moz_function -#if SKIA_IMPLEMENTATION - #define function moz_function -#endif - - typedef decltype(nullptr) moz_nullptr_t; - #define nullptr_t moz_nullptr_t - - using mozilla::DefaultDelete; - using mozilla::UniquePtr; - #define default_delete DefaultDelete - #define unique_ptr UniquePtr - - using mozilla::IsEnum; - using mozilla::IsIntegral; - using mozilla::FalseType; - using mozilla::TrueType; - #define is_enum IsEnum - #define is_integral IsIntegral - #define false_type FalseType - #define true_type TrueType - -#if SKIA_IMPLEMENTATION - using mozilla::IntegralConstant; - using mozilla::IsEmpty; - using mozilla::IsPod; - using mozilla::IsUnsigned; - #define integral_constant IntegralConstant - #define is_empty IsEmpty - #define is_pod IsPod - #define is_unsigned IsUnsigned -#endif -} - -namespace skstd { - -template using bool_constant = mozilla::IntegralConstant; - -template using conditional_t = typename mozilla::Conditional::Type; -template using enable_if_t = typename mozilla::EnableIf::Type; - -template using is_convertible = mozilla::IsConvertible; -template using remove_pointer_t = typename mozilla::RemovePointer::Type; - -template struct underlying_type { - using type = __underlying_type(T); -}; -template using underlying_type_t = typename skstd::underlying_type::type; - -} - -#else /* !MOZ_SKIA_AVOID_CXX11 */ - -#define std__forward std::forward -#define std__move std::move -#define std__function std::function - +#include // see bug 981264 #include +#include namespace skstd { @@ -115,27 +34,6 @@ template using remove_pointer_t = typename std::remove_pointer:: template using remove_reference_t = typename std::remove_reference::type; template using remove_extent_t = typename std::remove_extent::type; -// template struct is_function< -// R [calling-convention] (Args...[, ...]) [const] [volatile] [&|&&]> : std::true_type {}; -// The cv and ref-qualified versions are strange types we're currently avoiding, so not supported. -// These aren't supported in msvc either until vs2015u2. -// On all platforms, variadic functions only exist in the c calling convention. -// mcvc 2013 introduced __vectorcall, but it wan't until 2015 that it was added to is_function. -template struct is_function : std::false_type {}; -#if !defined(WIN32) -template struct is_function : std::true_type {}; -#else -template struct is_function : std::true_type {}; -#if defined(_M_IX86) -template struct is_function : std::true_type {}; -template struct is_function : std::true_type {}; -#endif -#if defined(_MSC_VER) && (_M_IX86_FP >= 2 || defined(_M_AMD64) || defined(_M_X64)) -template struct is_function : std::true_type {}; -#endif -#endif -template struct is_function : std::true_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; @@ -165,29 +63,6 @@ template using underlying_type = std::underlying_type; #endif template using underlying_type_t = typename skstd::underlying_type::type; -template ::value || is_function::value || std::is_array::value> -struct is_convertible_detector { - static const/*expr*/ bool value = std::is_void::value; -}; -template struct is_convertible_detector { - using yes_type = uint8_t; - using no_type = uint16_t; - - template static void param_convertable_to(To); - - template - static decltype(param_convertable_to(std::declval()), yes_type()) convertible(int); - - template static no_type convertible(...); - - static const/*expr*/ bool value = sizeof(convertible(0)) == sizeof(yes_type); -}; -// std::is_convertable is known to be broken (not work with incomplete types) in Android clang NDK. -// This is currently what prevents us from using std::unique_ptr. -template struct is_convertible - : bool_constant::value> {}; - } // namespace skstd // The sknonstd namespace contains things we would like to be proposed and feel std-ish. @@ -224,8 +99,6 @@ template using same_cv_t = typename same_cv::type } // namespace sknonstd -#endif /* MOZ_SKIA_AVOID_CXX11 */ - // Just a pithier wrapper for enable_if_t. #define SK_WHEN(condition, T) skstd::enable_if_t diff --git a/gfx/skia/skia/include/private/SkTemplates.h b/gfx/skia/skia/include/private/SkTemplates.h index b006f4f942c7..01a8ec0c3bd9 100644 --- a/gfx/skia/skia/include/private/SkTemplates.h +++ b/gfx/skia/skia/include/private/SkTemplates.h @@ -42,7 +42,7 @@ template static D* SkTAfter(S* ptr, size_t count = 1) { 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((char*)(ptr) + byteOffset); + return reinterpret_cast(reinterpret_cast*>(ptr) + byteOffset); } template struct SkFunctionWrapper { @@ -192,6 +192,7 @@ public: (--iter)->~T(); } + SkASSERT(count >= 0); if (fCount != count) { if (fCount > kCount) { // 'fArray' was allocated last time so free it now @@ -267,7 +268,7 @@ public: /** Allocates space for 'count' Ts. */ explicit SkAutoTMalloc(size_t count) { - fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW); + fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr; } ~SkAutoTMalloc() { @@ -276,7 +277,11 @@ public: /** Resize the memory area pointed to by the current ptr preserving contents. */ void realloc(size_t count) { - fPtr = reinterpret_cast(sk_realloc_throw(fPtr, count * sizeof(T))); + if (count) { + fPtr = reinterpret_cast(sk_realloc_throw(fPtr, count * sizeof(T))); + } else { + this->reset(0); + } } /** Resize the memory area pointed to by the current ptr without preserving contents. */ @@ -326,8 +331,10 @@ public: SkAutoSTMalloc(size_t count) { if (count > kCount) { fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); - } else { + } else if (count) { fPtr = fTStorage; + } else { + fPtr = nullptr; } } @@ -344,8 +351,10 @@ public: } if (count > kCount) { fPtr = (T*)sk_malloc_throw(count * sizeof(T)); - } else { + } else if (count) { fPtr = fTStorage; + } else { + fPtr = nullptr; } return fPtr; } @@ -377,8 +386,12 @@ public: } else { fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T)); } - } else if (fPtr != fTStorage) { - 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); } } @@ -434,6 +447,12 @@ T* SkInPlaceNewCheck(void* storage, size_t size, const A1& a1, const A2& a2, con return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3) : new T(a1, a2, a3); } +template +T* SkInPlaceNewCheck(void* storage, size_t size, + const A1& a1, const A2& a2, const A3& a3, const A4& a4) { + return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3, a4) : new T(a1, a2, a3, a4); +} + /** * Reserves memory that is aligned on double and pointer boundaries. * Hopefully this is sufficient for all practical purposes. diff --git a/gfx/skia/skia/include/private/SkWeakRefCnt.h b/gfx/skia/skia/include/private/SkWeakRefCnt.h index 1a78ba509231..d6631e946f95 100644 --- a/gfx/skia/skia/include/private/SkWeakRefCnt.h +++ b/gfx/skia/skia/include/private/SkWeakRefCnt.h @@ -9,7 +9,7 @@ #define SkWeakRefCnt_DEFINED #include "SkRefCnt.h" -#include "../private/SkAtomics.h" +#include /** \class SkWeakRefCnt @@ -62,22 +62,39 @@ public: */ virtual ~SkWeakRefCnt() { #ifdef SK_DEBUG - SkASSERT(fWeakCnt == 1); - fWeakCnt = 0; + SkASSERT(getWeakCnt() == 1); + fWeakCnt.store(0, std::memory_order_relaxed); #endif } - /** Return the weak reference count. - */ - int32_t getWeakCnt() const { return fWeakCnt; } - #ifdef SK_DEBUG + /** Return the weak reference count. */ + int32_t getWeakCnt() const { + return fWeakCnt.load(std::memory_order_relaxed); + } + void validate() const { this->INHERITED::validate(); - SkASSERT(fWeakCnt > 0); + SkASSERT(getWeakCnt() > 0); } #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 @@ -86,10 +103,9 @@ public: reference is in the same state as before the call. */ bool SK_WARN_UNUSED_RESULT try_ref() const { - if (sk_atomic_conditional_inc(&fRefCnt) != 0) { + if (atomic_conditional_acquire_strong_ref() != 0) { // Acquire barrier (L/SL), if not provided above. // Prevents subsequent code from happening before the increment. - sk_membar_acquire__after_atomic_conditional_inc(); return true; } return false; @@ -99,9 +115,10 @@ public: weak_unref(). */ void weak_ref() const { - SkASSERT(fRefCnt > 0); - SkASSERT(fWeakCnt > 0); - sk_atomic_inc(&fWeakCnt); // No barrier required. + 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 @@ -110,15 +127,14 @@ public: not on the stack. */ void weak_unref() const { - SkASSERT(fWeakCnt > 0); - // Release barrier (SL/S), if not provided below. - if (sk_atomic_dec(&fWeakCnt) == 1) { - // Acquire barrier (L/SL), if not provided above. - // Prevents code in destructor from happening before the decrement. - sk_membar_acquire__after_atomic_dec(); + 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 = 1; + fWeakCnt.store(1, std::memory_order_relaxed); #endif this->INHERITED::internal_dispose(); } @@ -128,7 +144,7 @@ public: is the case all future calls to try_ref() will return false. */ bool weak_expired() const { - return fRefCnt == 0; + return fRefCnt.load(std::memory_order_relaxed) == 0; } protected: @@ -151,7 +167,7 @@ private: } /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ - mutable int32_t fWeakCnt; + mutable std::atomic fWeakCnt; typedef SkRefCnt INHERITED; }; diff --git a/gfx/skia/skia/include/svg/parser/SkSVGAttribute.h b/gfx/skia/skia/include/svg/parser/SkSVGAttribute.h deleted file mode 100644 index 5ba2916b7426..000000000000 --- a/gfx/skia/skia/include/svg/parser/SkSVGAttribute.h +++ /dev/null @@ -1,43 +0,0 @@ - -/* - * 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 SkSVGAttribute_DEFINED -#define SkSVGAttribute_DEFINED - -#include "SkTypes.h" - -struct SkSVGAttribute { - const char* fName; -#ifdef SK_DEBUG - size_t fOffset; -#endif -}; - -#ifndef SK_OFFSETOF - // This is offsetof for types which are not standard layout. - #define SK_OFFSETOF(type, field) (size_t)((char*)&(((type*)1024)->field) - (char*)1024) -#endif - -#ifdef SK_DEBUG -#define SVG_ATTRIBUTE(attr) { #attr, SK_OFFSETOF(BASE_CLASS, f_##attr) } -#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr, SK_OFFSETOF(BASE_CLASS, cAttr) } -#else -#define SVG_ATTRIBUTE(attr) { #attr } -#define SVG_LITERAL_ATTRIBUTE(svgAttr, cAttr) { #svgAttr } -#endif - -#define SVG_ADD_ATTRIBUTE(attr) \ - if (f_##attr.size() > 0) \ - parser._addAttributeLen(#attr, f_##attr.c_str(), f_##attr.size()) - -#define SVG_ADD_ATTRIBUTE_ALIAS(attr, alias) \ - if (f_##alias.size() > 0) \ - parser._addAttributeLen(#attr, f_##alias.c_str(), f_##alias.size()) - -#endif // SkSVGAttribute_DEFINED diff --git a/gfx/skia/skia/include/svg/parser/SkSVGBase.h b/gfx/skia/skia/include/svg/parser/SkSVGBase.h deleted file mode 100644 index 6bfc39d0bfd1..000000000000 --- a/gfx/skia/skia/include/svg/parser/SkSVGBase.h +++ /dev/null @@ -1,25 +0,0 @@ - -/* - * 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 SkSVGBase_DEFINED -#define SkSVGBase_DEFINED - -#include "SkSVGAttribute.h" - -class SkSVGParser; - -class SkSVGBase { -public: - virtual ~SkSVGBase(); - virtual void addAttribute(SkSVGParser& parser, int attrIndex, - const char* attrValue, size_t attrLength); - virtual int getAttributes(const SkSVGAttribute** attrPtr) = 0; -}; - -#endif // SkSVGBase_DEFINEDes(const SkSVGAttribute** attrPtr) = 0; diff --git a/gfx/skia/skia/include/svg/parser/SkSVGPaintState.h b/gfx/skia/skia/include/svg/parser/SkSVGPaintState.h deleted file mode 100644 index 211e9cfce407..000000000000 --- a/gfx/skia/skia/include/svg/parser/SkSVGPaintState.h +++ /dev/null @@ -1,89 +0,0 @@ - -/* - * 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 SkSVGPaintState_DEFINED -#define SkSVGPaintState_DEFINED - -#include "SkSVGBase.h" -#include "SkString.h" - -class SkSVGPaint : public SkSVGBase { -public: - enum Field { - kInitial = -1, - kClipPath, - kClipRule, - kEnableBackground, - kFill, - kFillRule, - kFilter, - kFontFamily, - kFontSize, - kLetterSpacing, - kMask, - kOpacity, - kStopColor, - kStopOpacity, - kStroke, - kStroke_Dasharray, - kStroke_Linecap, - kStroke_Linejoin, - kStroke_Miterlimit, - kStroke_Width, - kStyle, - kTransform, - kTerminal - }; - - SkSVGPaint(); - virtual void addAttribute(SkSVGParser& parser, int attrIndex, - const char* attrValue, size_t attrLength); - bool flush(SkSVGParser& , bool isFlushable, bool isDef); - virtual int getAttributes(const SkSVGAttribute** attrPtr); - static void Push(SkSVGPaint** head, SkSVGPaint* add); - static void Pop(SkSVGPaint** head); - SkString* operator[](int index); - SkString fInitial; - SkString f_clipPath; - SkString f_clipRule; - SkString f_enableBackground; - SkString f_fill; - SkString f_fillRule; - SkString f_filter; - SkString f_fontFamily; - SkString f_fontSize; - SkString f_letterSpacing; - SkString f_mask; - SkString f_opacity; - SkString f_stopColor; - SkString f_stopOpacity; - SkString f_stroke; - SkString f_strokeDasharray; - SkString f_strokeLinecap; - SkString f_strokeLinejoin; - SkString f_strokeMiterlimit; - SkString f_strokeWidth; - SkString f_style; // unused, but allows array access to the rest - SkString f_transform; -#ifdef SK_DEBUG - SkString fTerminal; -#endif - SkString fTransformID; - static SkSVGAttribute gAttributes[]; - static const int kAttributesSize; -private: - void setSave(SkSVGParser& ); - bool writeChangedAttributes(SkSVGParser& , SkSVGPaint& , bool* changed); - bool writeChangedElements(SkSVGParser& , SkSVGPaint& , bool* changed); - SkSVGPaint* fNext; - friend class SkSVGParser; - typedef SkSVGPaint BASE_CLASS; -}; - -#endif // SkSVGPaintState_DEFINED diff --git a/gfx/skia/skia/include/svg/parser/SkSVGParser.h b/gfx/skia/skia/include/svg/parser/SkSVGParser.h deleted file mode 100644 index 9a5c4157b18b..000000000000 --- a/gfx/skia/skia/include/svg/parser/SkSVGParser.h +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * 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 SkSVGParser_DEFINED -#define SkSVGParser_DEFINED - -#include "SkMatrix.h" -#include "../private/SkTDict.h" -#include "SkSVGPaintState.h" -#include "SkSVGTypes.h" -#include "SkStream.h" -#include "SkString.h" -#include "SkXMLParser.h" -#include "SkXMLWriter.h" - -class SkSVGBase; -class SkSVGElement; - -class SkSVGParser : public SkXMLParser { -public: - SkSVGParser(SkXMLParserError* err = NULL); - virtual ~SkSVGParser(); - void _addAttribute(const char* attrName, const char* attrValue) { - fXMLWriter.addAttribute(attrName, attrValue); } - void _addAttribute(const char* attrName, SkString& attrValue) { - fXMLWriter.addAttribute(attrName, attrValue.c_str()); } - void _addAttributeLen(const char* attrName, const char* attrValue, size_t len) { - fXMLWriter.addAttributeLen(attrName, attrValue, len); } - void _endElement() { fXMLWriter.endElement(); } - int findAttribute(SkSVGBase* , const char* attrValue, size_t len, bool isPaint); -// const char* getFinal(); - SkTDict& getIDs() { return fIDs; } - SkString& getPaintLast(SkSVGPaint::Field field); - void _startElement(const char name[]) { fXMLWriter.startElement(name); } - void translate(SkSVGElement*, bool isDef); - void translateMatrix(SkString& , SkString* id); - static void ConvertToArray(SkString& vals); -protected: - virtual bool onAddAttribute(const char name[], const char value[]); - bool onAddAttributeLen(const char name[], const char value[], size_t len); - virtual bool onEndElement(const char elem[]); - virtual bool onStartElement(const char elem[]); - bool onStartElementLen(const char elem[], size_t len); - virtual bool onText(const char text[], int len); -private: - bool isStrokeAndFill(SkSVGPaint** stroke, SkSVGPaint** fill); - static SkSVGElement* CreateElement(SkSVGTypes type, SkSVGElement* parent); - static void Delete(SkTDArray& fChildren); - static SkSVGTypes GetType(const char name[], size_t len); - SkSVGPaint* fHead; - SkSVGPaint fEmptyPaint; - SkSVGPaint fLastFlush; - SkString fLastColor; - SkMatrix fLastTransform; - SkTDArray fChildren; - SkTDict fIDs; - SkTDArray fParents; - SkDynamicMemoryWStream fStream; - SkXMLStreamWriter fXMLWriter; - SkSVGElement* fCurrElement; - SkBool8 fInSVG; - SkBool8 fSuppressPaint; - friend class SkSVGPaint; - friend class SkSVGGradient; -}; - -#endif // SkSVGParser_DEFINED diff --git a/gfx/skia/skia/include/svg/parser/SkSVGTypes.h b/gfx/skia/skia/include/svg/parser/SkSVGTypes.h deleted file mode 100644 index b13bc6e4fceb..000000000000 --- a/gfx/skia/skia/include/svg/parser/SkSVGTypes.h +++ /dev/null @@ -1,40 +0,0 @@ - -/* - * 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 SkSVGTypes_DEFINED -#define SkSVGTypes_DEFINED - -enum SkSVGTypes { - SkSVGType_Circle, - SkSVGType_ClipPath, - SkSVGType_Defs, - SkSVGType_Ellipse, - SkSVGType_FeColorMatrix, - SkSVGType_Filter, - SkSVGType_G, - SkSVGType_Image, - SkSVGType_Line, - SkSVGType_LinearGradient, - SkSVGType_Mask, - SkSVGType_Metadata, - SkSVGType_Path, - SkSVGType_Polygon, - SkSVGType_Polyline, - SkSVGType_RadialGradient, - SkSVGType_Rect, - SkSVGType_SVG, - SkSVGType_Stop, - SkSVGType_Symbol, - SkSVGType_Text, - SkSVGType_Tspan, - SkSVGType_Unknown, - SkSVGType_Use -}; - -#endif // SkSVGTypes_DEFINED diff --git a/gfx/skia/skia/include/utils/SkDumpCanvas.h b/gfx/skia/skia/include/utils/SkDumpCanvas.h index 1c16bf3f03ab..e11185336973 100644 --- a/gfx/skia/skia/include/utils/SkDumpCanvas.h +++ b/gfx/skia/skia/include/utils/SkDumpCanvas.h @@ -1,17 +1,15 @@ - /* * 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 SkDumpCanvas_DEFINED #define SkDumpCanvas_DEFINED #include "SkCanvas.h" -#ifdef SK_DEVELOPER - /** This class overrides all the draw methods on SkCanvas, and formats them as text, and then sends that to a Dumper helper object. @@ -38,6 +36,7 @@ public: kDrawPaint_Verb, kDrawPoints_Verb, kDrawOval_Verb, + kDrawArc_Verb, kDrawRect_Verb, kDrawRRect_Verb, kDrawDRRect_Verb, @@ -89,6 +88,8 @@ protected: SkScalar constY, const SkPaint&) override; virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, 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; virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], @@ -99,6 +100,7 @@ protected: 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; @@ -115,10 +117,10 @@ protected: const uint16_t indices[], int indexCount, const SkPaint&) override; - void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, SkRegion::Op) override; + void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, ClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawAnnotation(const SkRect&, const char key[], SkData* value) override; @@ -164,5 +166,3 @@ private: }; #endif - -#endif diff --git a/gfx/skia/skia/include/utils/SkJSONCPP.h b/gfx/skia/skia/include/utils/SkJSONCPP.h deleted file mode 100644 index 6baf223610d6..000000000000 --- a/gfx/skia/skia/include/utils/SkJSONCPP.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * A common place to put the jsoncpp library includes, as opposed to littering - * the pragmas repeatedly through our code. - */ -#ifndef SkJSONCPP_DEFINED -#define SkJSONCPP_DEFINED - -#ifdef GOOGLE3 - #include "third_party/jsoncpp/reader.h" - #include "third_party/jsoncpp/value.h" - #include "third_party/jsoncpp/writer.h" -#else - #ifdef SK_BUILD_FOR_WIN - // json includes xlocale which generates warning 4530 because we're - // compiling without exceptions; - // see https://code.google.com/p/skia/issues/detail?id=1067 - #pragma warning(push) - #pragma warning(disable : 4530) - #endif - #include "json/reader.h" - #include "json/value.h" - #include "json/writer.h" - #ifdef SK_BUILD_FOR_WIN - #pragma warning(pop) - #endif -#endif - -#endif // SkJSONCPP_DEFINED diff --git a/gfx/skia/skia/include/utils/SkLuaCanvas.h b/gfx/skia/skia/include/utils/SkLuaCanvas.h index 37e82be51dc1..ac29f6f27214 100644 --- a/gfx/skia/skia/include/utils/SkLuaCanvas.h +++ b/gfx/skia/skia/include/utils/SkLuaCanvas.h @@ -37,6 +37,8 @@ protected: SkScalar constY, const SkPaint&) override; virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, 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; @@ -44,6 +46,7 @@ protected: 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; @@ -60,10 +63,10 @@ protected: const uint16_t indices[], int indexCount, const SkPaint&) override; - void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, SkRegion::Op) override; + void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, ClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; diff --git a/gfx/skia/skia/include/utils/SkNWayCanvas.h b/gfx/skia/skia/include/utils/SkNWayCanvas.h index f2a99db8027d..4e7f4224f8c8 100644 --- a/gfx/skia/skia/include/utils/SkNWayCanvas.h +++ b/gfx/skia/skia/include/utils/SkNWayCanvas.h @@ -49,6 +49,8 @@ protected: const SkMatrix* matrix, 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], SkXfermode* xmode, const SkPaint& paint) override; @@ -57,6 +59,7 @@ protected: 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; @@ -73,10 +76,10 @@ protected: const uint16_t indices[], int indexCount, const SkPaint&) override; - void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override; - void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override; - void onClipRegion(const SkRegion&, SkRegion::Op) override; + void onClipRect(const SkRect&, ClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, ClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, ClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, ClipOp) override; void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; void onDrawAnnotation(const SkRect&, const char[], SkData*) override; diff --git a/gfx/skia/skia/include/utils/SkNinePatch.h b/gfx/skia/skia/include/utils/SkNinePatch.h deleted file mode 100644 index 4d8788b28547..000000000000 --- a/gfx/skia/skia/include/utils/SkNinePatch.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * 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 SkNinePatch_DEFINED -#define SkNinePatch_DEFINED - -#include "SkRect.h" -#include "SkRegion.h" - -class SkBitmap; -class SkCanvas; -class SkPaint; - -class SkNinePatch { -public: - static void DrawNine(SkCanvas* canvas, const SkRect& dst, - const SkBitmap& bitmap, const SkIRect& margins, - const SkPaint* paint = NULL); - - static void DrawMesh(SkCanvas* canvas, const SkRect& dst, - const SkBitmap& bitmap, - const int32_t xDivs[], int numXDivs, - const int32_t yDivs[], int numYDivs, - const SkPaint* paint = NULL); -}; - -#endif diff --git a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h index 909cf3b987de..63eaaa2fbcd6 100644 --- a/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h +++ b/gfx/skia/skia/include/utils/SkPaintFilterCanvas.h @@ -31,6 +31,7 @@ public: enum Type { kPaint_Type, kPoint_Type, + kArc_Type, kBitmap_Type, kRect_Type, kRRect_Type, @@ -66,6 +67,7 @@ protected: void onDrawRRect(const SkRRect&, const SkPaint&) override; void onDrawDRRect(const SkRRect&, const SkRRect&, 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*, @@ -95,6 +97,8 @@ protected: SkScalar constY, const SkPaint&) override; void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, 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; diff --git a/gfx/skia/skia/include/utils/SkRTConf.h b/gfx/skia/skia/include/utils/SkRTConf.h deleted file mode 100644 index c3e97ef5e30c..000000000000 --- a/gfx/skia/skia/include/utils/SkRTConf.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 SkRTConf_DEFINED -#define SkRTConf_DEFINED - -#include "../private/SkTDArray.h" -#include "../private/SkTDict.h" -#include "SkString.h" -#include "SkStream.h" - -/** \class SkRTConfBase - Non-templated base class for the runtime configs -*/ - -class SkRTConfBase { -public: - SkRTConfBase(const char *name) : fName(name) {} - virtual ~SkRTConfBase() {} - virtual const char *getName() const { return fName.c_str(); } - virtual bool isDefault() const = 0; - virtual void print(SkWStream *o) const = 0; - virtual bool equals(const SkRTConfBase *conf) const = 0; -protected: - SkString fName; -}; - -/** \class SkRTConf - A class to provide runtime configurability. -*/ -template class SkRTConf: public SkRTConfBase { -public: - SkRTConf(const char *name, const T &defaultValue, const char *description); - operator const T&() const { return fValue; } - void print(SkWStream *o) const; - bool equals(const SkRTConfBase *conf) const; - bool isDefault() const { return fDefault == fValue; } - void set(const T& value) { fValue = value; } -protected: - void doPrint(char *s) const; - - T fValue; - T fDefault; - SkString fDescription; -}; - -#ifdef SK_DEVELOPER -#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static SkRTConf varName(confName, defaultValue, description) -#define SK_CONF_SET(confname, value) \ - skRTConfRegistry().set(confname, value, true) -/* SK_CONF_TRY_SET() is like SK_CONF_SET(), but doesn't complain if - confname can't be found. This is useful if the SK_CONF_DECLARE is - inside a source file whose linkage is dependent on the system. */ -#define SK_CONF_TRY_SET(confname, value) \ - skRTConfRegistry().set(confname, value, false) -#else -#define SK_CONF_DECLARE(confType, varName, confName, defaultValue, description) static confType varName = defaultValue -#define SK_CONF_SET(confname, value) (void) confname, (void) value -#define SK_CONF_TRY_SET(confname, value) (void) confname, (void) value -#endif - -/** \class SkRTConfRegistry - A class that maintains a systemwide registry of all runtime configuration - parameters. Mainly used for printing them out and handling multiply-defined - knobs. -*/ - -class SkRTConfRegistry { -public: - SkRTConfRegistry(); - ~SkRTConfRegistry(); - void printAll(const char *fname = NULL) const; - bool hasNonDefault() const; - void printNonDefault(const char *fname = NULL) const; - const char *configFileLocation() const; - void possiblyDumpFile() const; - void validate() const; - template void set(const char *confname, - T value, - bool warnIfNotFound = true); - -private: - template friend class SkRTConf; - - void registerConf(SkRTConfBase *conf); - - template bool parse(const char *name, T* value); - - SkTDArray fConfigFileKeys, fConfigFileValues; - typedef SkTDict< SkTDArray * > ConfMap; - ConfMap fConfs; - - template - friend bool test_rt_conf_parse(SkRTConfRegistry*, const char* name, T* value); -}; - -// our singleton registry - -SkRTConfRegistry &skRTConfRegistry(); - -template -SkRTConf::SkRTConf(const char *name, const T &defaultValue, const char *description) - : SkRTConfBase(name) - , fValue(defaultValue) - , fDefault(defaultValue) - , fDescription(description) { - - T value; - if (skRTConfRegistry().parse(fName.c_str(), &value)) { - fValue = value; - } - skRTConfRegistry().registerConf(this); -} - -template -void SkRTConf::print(SkWStream *o) const { - char outline[200]; // should be ok because we specify a max. width for everything here. - char *outptr; - if (strlen(getName()) >= 30) { - o->writeText(getName()); - o->writeText(" "); - outptr = &(outline[0]); - } else { - sprintf(outline, "%-30.30s", getName()); - outptr = &(outline[30]); - } - - doPrint(outptr); - sprintf(outptr+30, " %.128s", fDescription.c_str()); - for (size_t i = strlen(outline); i --> 0 && ' ' == outline[i];) { - outline[i] = '\0'; - } - o->writeText(outline); -} - -template -void SkRTConf::doPrint(char *s) const { - sprintf(s, "%-30.30s", "How do I print myself??"); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%s # [%s]", fValue ? "true" : "false", fDefault ? "true" : "false"); - sprintf(s, "%-30.30s", tmp); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%d # [%d]", fValue, fDefault); - sprintf(s, "%-30.30s", tmp); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%u # [%u]", fValue, fDefault); - sprintf(s, "%-30.30s", tmp); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); - sprintf(s, "%-30.30s", tmp); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%6.6f # [%6.6f]", fValue, fDefault); - sprintf(s, "%-30.30s", tmp); -} - -template<> inline void SkRTConf::doPrint(char *s) const { - char tmp[30]; - sprintf(tmp, "%s # [%s]", fValue, fDefault); - sprintf(s, "%-30.30s", tmp); -} - -template -bool SkRTConf::equals(const SkRTConfBase *conf) const { - // static_cast here is okay because there's only one kind of child class. - const SkRTConf *child_pointer = static_cast *>(conf); - return child_pointer && - fName == child_pointer->fName && - fDescription == child_pointer->fDescription && - fValue == child_pointer->fValue && - fDefault == child_pointer->fDefault; -} - -#endif diff --git a/gfx/skia/skia/include/utils/SkTextBox.h b/gfx/skia/skia/include/utils/SkTextBox.h index d4372d1b6ab8..90903b558d5f 100644 --- a/gfx/skia/skia/include/utils/SkTextBox.h +++ b/gfx/skia/skia/include/utils/SkTextBox.h @@ -60,7 +60,7 @@ public: int countLines() const; SkScalar getTextHeight() const; - SkTextBlob* snapshotTextBlob(SkScalar* computedBottom) const; + sk_sp snapshotTextBlob(SkScalar* computedBottom) const; class Visitor { public: diff --git a/gfx/skia/skia/include/utils/mac/SkCGUtils.h b/gfx/skia/skia/include/utils/mac/SkCGUtils.h index 3d9aff44515f..29df8b81a889 100644 --- a/gfx/skia/skia/include/utils/mac/SkCGUtils.h +++ b/gfx/skia/skia/include/utils/mac/SkCGUtils.h @@ -23,7 +23,7 @@ class SkBitmap; class SkData; -class SkStream; +class SkStreamRewindable; /** * Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not @@ -65,20 +65,12 @@ static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) { void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y); /** - * Create an SkBitmap drawing of the encoded PDF document, returning true on - * success. Deletes the stream when finished. - */ -bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output); - -/** - * Return a provider that wraps the specified stream. It will become the only - * owner of the stream, so the caller must stop referring to the stream. - * + * Return a provider that wraps the specified stream. * When the provider is finally deleted, it will delete the stream. */ -CGDataProviderRef SkCreateDataProviderFromStream(SkStream*); +CGDataProviderRef SkCreateDataProviderFromStream(std::unique_ptr); -CGDataProviderRef SkCreateDataProviderFromData(SkData*); +CGDataProviderRef SkCreateDataProviderFromData(sk_sp); #endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) #endif // SkCGUtils_DEFINED diff --git a/gfx/skia/skia/include/views/SkEvent.h b/gfx/skia/skia/include/views/SkEvent.h index b8fc00ef51c9..649553000660 100644 --- a/gfx/skia/skia/include/views/SkEvent.h +++ b/gfx/skia/skia/include/views/SkEvent.h @@ -12,6 +12,8 @@ #include "SkMetaData.h" #include "SkString.h" +#include "../private/SkLeanWindows.h" + /** Unique 32bit id used to identify an instance of SkEventSink. When events are posted, they are posted to a specific sinkID. When it is time to dispatch the event, the sinkID is used to find the specific SkEventSink object. If it is found, diff --git a/gfx/skia/skia/include/views/SkOSWindow_Android.h b/gfx/skia/skia/include/views/SkOSWindow_Android.h deleted file mode 100644 index 74175bafd144..000000000000 --- a/gfx/skia/skia/include/views/SkOSWindow_Android.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2011 Skia - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkOSWindow_Android_DEFINED -#define SkOSWindow_Android_DEFINED - -#include "SkWindow.h" - -#include - -struct SkAndroidWindow { - EGLDisplay fDisplay; - EGLSurface fSurface; - EGLContext fContext; -}; - -class SkOSWindow : public SkWindow { -public: - SkOSWindow(void*); - ~SkOSWindow(); - - enum SkBackEndTypes { - kNone_BackEndType, - kNativeGL_BackEndType, - }; - - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info); - void release(); - void present(); - bool makeFullscreen() { return true; } - void closeWindow(); - void setVsync(bool); - bool destroyRequested() { return fDestroyRequested; } - -protected: - // overrides from SkWindow - virtual void onHandleInval(const SkIRect&); - virtual void onSetTitle(const char title[]); - -private: - SkAndroidWindow fWindow; - ANativeWindow* fNativeWindow; - bool fDestroyRequested; - - typedef SkWindow INHERITED; -}; - -#endif diff --git a/gfx/skia/skia/include/views/SkOSWindow_Mac.h b/gfx/skia/skia/include/views/SkOSWindow_Mac.h index efa97bf87245..41766a0f53ad 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_Mac.h +++ b/gfx/skia/skia/include/views/SkOSWindow_Mac.h @@ -27,13 +27,11 @@ public: #if SK_ANGLE kANGLE_BackEndType, #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - kCommandBuffer_BackEndType, -#endif // SK_COMMAND_BUFFER }; void release(); - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, + AttachmentInfo*); void present(); bool makeFullscreen(); diff --git a/gfx/skia/skia/include/views/SkOSWindow_SDL.h b/gfx/skia/skia/include/views/SkOSWindow_SDL.h index 68234417154f..65685d1d2114 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_SDL.h +++ b/gfx/skia/skia/include/views/SkOSWindow_SDL.h @@ -23,13 +23,10 @@ public: #if SK_ANGLE kANGLE_BackEndType, #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - kCommandBuffer_BackEndType, -#endif // SK_COMMAND_BUFFER }; void release(); - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*); void present(); bool makeFullscreen(); void setVsync(bool); diff --git a/gfx/skia/skia/include/views/SkOSWindow_Unix.h b/gfx/skia/skia/include/views/SkOSWindow_Unix.h index 30386da183dc..9d1b8e039296 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_Unix.h +++ b/gfx/skia/skia/include/views/SkOSWindow_Unix.h @@ -39,12 +39,9 @@ public: #if SK_ANGLE kANGLE_BackEndType, #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - kCommandBuffer_BackEndType, -#endif // SK_COMMAND_BUFFER }; - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*); void release(); void present(); diff --git a/gfx/skia/skia/include/views/SkOSWindow_Win.h b/gfx/skia/skia/include/views/SkOSWindow_Win.h index eb8b1fc89238..7ed22a651459 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_Win.h +++ b/gfx/skia/skia/include/views/SkOSWindow_Win.h @@ -18,10 +18,6 @@ #include "EGL/egl.h" #endif -#if SK_COMMAND_BUFFER -class SkCommandBufferGLContext; -#endif - class SkOSWindow : public SkWindow { public: struct WindowInit { @@ -41,13 +37,10 @@ public: #if SK_ANGLE kANGLE_BackEndType, #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - kCommandBuffer_BackEndType, -#endif // SK_COMMAND_BUFFER #endif // SK_SUPPORT_GPU }; - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*); void release(); void present(); @@ -104,9 +97,6 @@ private: EGLConfig fConfig; SkAutoTUnref fANGLEInterface; #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - SkCommandBufferGLContext* fCommandBuffer; -#endif // SK_COMMAND_BUFFER #endif // SK_SUPPORT_GPU bool fFullscreen; @@ -127,7 +117,7 @@ private: void updateSize(); #if SK_SUPPORT_GPU - bool attachGL(int msaaSampleCount, AttachmentInfo* info); + bool attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info); void detachGL(); void presentGL(); @@ -137,11 +127,6 @@ private: void presentANGLE(); #endif // SK_ANGLE -#if SK_COMMAND_BUFFER - bool attachCommandBuffer(int msaaSampleCount, AttachmentInfo* info); - void detachCommandBuffer(); - void presentCommandBuffer(); -#endif // SK_COMMAND_BUFFER #endif // SK_SUPPORT_GPU typedef SkWindow INHERITED; diff --git a/gfx/skia/skia/include/views/SkOSWindow_iOS.h b/gfx/skia/skia/include/views/SkOSWindow_iOS.h index 5a8b2e3d2f99..c0b2fc3f0ae3 100644 --- a/gfx/skia/skia/include/views/SkOSWindow_iOS.h +++ b/gfx/skia/skia/include/views/SkOSWindow_iOS.h @@ -22,7 +22,8 @@ public: }; void release(); - bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*); + bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, + AttachmentInfo*); void present(); bool makeFullscreen() { return true; } diff --git a/gfx/skia/skia/include/views/SkTouchGesture.h b/gfx/skia/skia/include/views/SkTouchGesture.h index 60487c7a2f28..4d4c0312d330 100644 --- a/gfx/skia/skia/include/views/SkTouchGesture.h +++ b/gfx/skia/skia/include/views/SkTouchGesture.h @@ -43,6 +43,8 @@ public: const SkMatrix& localM(); const SkMatrix& globalM() const { return fGlobalM; } + void setTransLimit(const SkRect& contentRect, const SkRect& windowRect); + private: enum State { kEmpty_State, @@ -65,7 +67,11 @@ private: double fLastUpMillis; SkPoint fLastUpP; + // The following rects are used to limit the translation so the content never leaves the window + SkRect fContentRect, fWindowRect; + bool fIsTransLimited = false; + void limitTrans(); // here we only limit the translation with respect to globalM void flushLocalM(); int findRec(void* owner) const; void appendNewRec(void* owner, float x, float y); diff --git a/gfx/skia/skia/include/views/SkWindow.h b/gfx/skia/skia/include/views/SkWindow.h index b4fabd253ee1..e964fc681b5a 100644 --- a/gfx/skia/skia/include/views/SkWindow.h +++ b/gfx/skia/skia/include/views/SkWindow.h @@ -32,8 +32,14 @@ public: virtual ~SkWindow(); struct AttachmentInfo { + AttachmentInfo() + : fSampleCount(0) + , fStencilBits(0) + , fColorBits(0) {} + int fSampleCount; int fStencilBits; + int fColorBits; }; SkSurfaceProps getSurfaceProps() const { return fSurfaceProps; } @@ -46,7 +52,7 @@ public: void resize(int width, int height); void resize(const SkImageInfo&); - void setColorType(SkColorType, SkColorProfileType); + void setColorType(SkColorType, sk_sp); bool isDirty() const { return !fDirtyRgn.isEmpty(); } bool update(SkIRect* updateArea); @@ -72,7 +78,7 @@ public: void preConcat(const SkMatrix&); void postConcat(const SkMatrix&); - virtual SkSurface* createSurface(); + virtual sk_sp makeSurface(); protected: virtual bool onEvent(const SkEvent&); @@ -92,8 +98,8 @@ protected: virtual bool onSetFocusView(SkView* focus); #if SK_SUPPORT_GPU - GrRenderTarget* renderTarget(const AttachmentInfo& attachmentInfo, - const GrGLInterface* , GrContext* grContext); + sk_sp makeGpuBackedSurface(const AttachmentInfo& attachmentInfo, + const GrGLInterface* , GrContext* grContext); #endif private: @@ -123,7 +129,7 @@ private: #elif defined(SK_BUILD_FOR_WIN) #include "SkOSWindow_Win.h" #elif defined(SK_BUILD_FOR_ANDROID) - #include "SkOSWindow_Android.h" + #error Android does not support SkOSWindow and SampleApp. Please use Viewer instead. #elif defined(SK_BUILD_FOR_UNIX) #include "SkOSWindow_Unix.h" #elif defined(SK_BUILD_FOR_IOS) diff --git a/gfx/skia/skia/include/xml/SkBML_WXMLParser.h b/gfx/skia/skia/include/xml/SkBML_WXMLParser.h deleted file mode 100644 index 20239c2b6dfa..000000000000 --- a/gfx/skia/skia/include/xml/SkBML_WXMLParser.h +++ /dev/null @@ -1,46 +0,0 @@ - -/* - * 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 SkBML_WXMLParser_DEFINED -#define SkBML_WXMLParser_DEFINED - -#include "SkString.h" -#include "SkXMLParser.h" - -class SkStream; -class SkWStream; - -class BML_WXMLParser : public SkXMLParser { -public: - BML_WXMLParser(SkWStream& writer); - virtual ~BML_WXMLParser(); - static void Write(SkStream& s, const char filename[]); - - /** @cond UNIT_TEST */ - SkDEBUGCODE(static void UnitTest();) - /** @endcond */ -private: - virtual bool onAddAttribute(const char name[], const char value[]); - virtual bool onEndElement(const char name[]); - virtual bool onStartElement(const char name[]); - BML_WXMLParser& operator=(const BML_WXMLParser& src); -#ifdef SK_DEBUG - int fElemsCount, fElemsReused; - int fAttrsCount, fNamesReused, fValuesReused; -#endif - SkWStream& fWriter; - char* fElems[256]; - char* fAttrNames[256]; - char* fAttrValues[256]; - - // important that these are U8, so we get automatic wrap-around - uint8_t fNextElem, fNextAttrName, fNextAttrValue; -}; - -#endif // SkBML_WXMLParser_DEFINED diff --git a/gfx/skia/skia/include/xml/SkBML_XMLParser.h b/gfx/skia/skia/include/xml/SkBML_XMLParser.h deleted file mode 100644 index 9bdbf5128231..000000000000 --- a/gfx/skia/skia/include/xml/SkBML_XMLParser.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * 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 SkBML_XMLParser_DEFINED -#define SkBML_XMLParser_DEFINED - -class SkStream; -class SkWStream; -class SkXMLParser; -class SkXMLWriter; - -class BML_XMLParser { -public: - /** Read the byte XML stream and write the decompressed XML. - */ - static void Read(SkStream& s, SkXMLWriter& writer); - /** Read the byte XML stream and write the decompressed XML into a writable stream. - */ - static void Read(SkStream& s, SkWStream& output); - /** Read the byte XML stream and write the decompressed XML into an XML parser. - */ - static void Read(SkStream& s, SkXMLParser& output); -}; - -#endif // SkBML_XMLParser_DEFINED diff --git a/gfx/skia/skia/include/xml/SkDOM.h b/gfx/skia/skia/include/xml/SkDOM.h index 14d79cf8af30..b6f611af6e97 100644 --- a/gfx/skia/skia/include/xml/SkDOM.h +++ b/gfx/skia/skia/include/xml/SkDOM.h @@ -13,14 +13,16 @@ #include "../private/SkTemplates.h" #include "SkChunkAlloc.h" #include "SkScalar.h" +#include "SkTypes.h" struct SkDOMNode; struct SkDOMAttr; class SkDOMParser; +class SkStream; class SkXMLParser; -class SkDOM { +class SK_API SkDOM : public SkNoncopyable { public: SkDOM(); ~SkDOM(); @@ -30,7 +32,7 @@ public: /** Returns null on failure */ - const Node* build(const char doc[], size_t len); + const Node* build(SkStream&); const Node* copy(const SkDOM& dom, const Node* node); const Node* getRootNode() const; @@ -77,7 +79,7 @@ public: class AttrIter { public: - AttrIter(const class SkDOM&, const Node*); + AttrIter(const SkDOM&, const Node*); const char* next(const char** value); private: const Attr* fAttr; @@ -85,15 +87,13 @@ public: }; SkDEBUGCODE(void dump(const Node* node = NULL, int tabLevel = 0) const;) - SkDEBUGCODE(static void UnitTest();) private: SkChunkAlloc fAlloc; Node* fRoot; SkAutoTDelete fParser; - friend class AttrIter; - friend class SkDOMParser; + typedef SkNoncopyable INHERITED; }; #endif diff --git a/gfx/skia/skia/include/xml/SkXMLParser.h b/gfx/skia/skia/include/xml/SkXMLParser.h index 1a90bf71e797..3f69013ce6af 100644 --- a/gfx/skia/skia/include/xml/SkXMLParser.h +++ b/gfx/skia/skia/include/xml/SkXMLParser.h @@ -73,10 +73,10 @@ protected: public: // public for ported implementation, not meant for clients to call - virtual bool startElement(const char elem[]); - virtual bool addAttribute(const char name[], const char value[]); - virtual bool endElement(const char elem[]); - virtual bool text(const char text[], int len); + bool startElement(const char elem[]); + bool addAttribute(const char name[], const char value[]); + bool endElement(const char elem[]); + bool text(const char text[], int len); void* fParser; protected: SkXMLParserError* fError; @@ -84,72 +84,4 @@ private: void reportError(void* parser); }; -#if 0 -class SkXMLPullParser { -public: - SkXMLPullParser(); - explicit SkXMLPullParser(SkStream*); - virtual ~SkXMLPullParser(); - - SkStream* getStream() const { return fStream; } - SkStream* setStream(SkStream* stream); - - enum EventType { - ERROR = -1, - START_DOCUMENT, - END_DOCUMENT, - START_TAG, - END_TAG, - TEXT, - CDSECT, - ENTITY_REF, - IGNORABLE_WHITESPACE, - PROCESSING_INSTRUCTION, - COMMENT, - DOCDECL - }; - - EventType nextToken(); - EventType getEventType() const { return fCurr.fEventType; } - - struct AttrInfo { - const char* fName; - const char* fValue; - }; - - int getDepth() const { return fDepth; } - const char* getName(); - int getAttributeCount(); - void getAttributeInfo(int, AttrInfo*); - const char* getText(); - bool isWhitespace(); - -protected: - virtual bool onEntityReplacement(const char name[], - SkString* replacement); - -public: - struct Curr { - EventType fEventType; - const char* fName; - AttrInfo* fAttrInfos; - int fAttrInfoCount; - bool fIsWhitespace; - }; - -private: - // implemented in the porting layer - bool onInit(); // return false on failure - EventType onNextToken(); - void onExit(); - - SkStream* fStream; - Curr fCurr; - int fDepth; - - struct Impl; - Impl* fImpl; -}; -#endif - #endif diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp deleted file mode 100644 index c7c42bd9a25c..000000000000 --- a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmapRegionCanvas.h" -#include "SkBitmapRegionDecoderPriv.h" -#include "SkCanvas.h" -#include "SkCodecPriv.h" - -SkBitmapRegionCanvas::SkBitmapRegionCanvas(SkCodec* decoder) - : INHERITED(decoder->getInfo().width(), decoder->getInfo().height()) - , fDecoder(decoder) -{} - -bool SkBitmapRegionCanvas::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, - const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, - bool requireUnpremul) { - - // Reject color types not supported by this method - if (kIndex_8_SkColorType == dstColorType || kGray_8_SkColorType == dstColorType) { - SkCodecPrintf("Error: Color type not supported.\n"); - return false; - } - - // Reject requests for unpremultiplied alpha - if (requireUnpremul) { - SkCodecPrintf("Error: Alpha type not supported.\n"); - return false; - } - SkAlphaType dstAlphaType = fDecoder->getInfo().alphaType(); - if (kUnpremul_SkAlphaType == dstAlphaType) { - dstAlphaType = kPremul_SkAlphaType; - } - - // Fix the input sampleSize if necessary. - if (sampleSize < 1) { - sampleSize = 1; - } - - // The size of the output bitmap is determined by the size of the - // requested subset, not by the size of the intersection of the subset - // and the image dimensions. - // If inputX is negative, we will need to place decoded pixels into the - // output bitmap starting at a left offset. Call this outX. - // If outX is non-zero, subsetX must be zero. - // If inputY is negative, we will need to place decoded pixels into the - // output bitmap starting at a top offset. Call this outY. - // If outY is non-zero, subsetY must be zero. - int outX; - int outY; - SkIRect subset = desiredSubset; - SubsetType type = adjust_subset_rect(fDecoder->getInfo().dimensions(), &subset, &outX, &outY); - if (SubsetType::kOutside_SubsetType == type) { - return false; - } - - // Create the image info for the decode - SkImageInfo decodeInfo = SkImageInfo::Make(this->width(), this->height(), - dstColorType, dstAlphaType); - - // Start the scanline decoder - SkCodec::Result r = fDecoder->startScanlineDecode(decodeInfo); - if (SkCodec::kSuccess != r) { - SkCodecPrintf("Error: Could not start scanline decoder.\n"); - return false; - } - - // Allocate a bitmap for the unscaled decode - SkBitmap tmp; - SkImageInfo tmpInfo = decodeInfo.makeWH(this->width(), subset.height()); - if (!tmp.tryAllocPixels(tmpInfo)) { - SkCodecPrintf("Error: Could not allocate pixels.\n"); - return false; - } - - // Skip the unneeded rows - if (!fDecoder->skipScanlines(subset.y())) { - SkCodecPrintf("Error: Failed to skip scanlines.\n"); - return false; - } - - // Decode the necessary rows - fDecoder->getScanlines(tmp.getAddr(0, 0), subset.height(), tmp.rowBytes()); - - // Calculate the size of the output - const int outWidth = get_scaled_dimension(desiredSubset.width(), sampleSize); - const int outHeight = get_scaled_dimension(desiredSubset.height(), sampleSize); - - // Initialize the destination bitmap - SkImageInfo dstInfo = decodeInfo.makeWH(outWidth, outHeight); - bitmap->setInfo(dstInfo, dstInfo.minRowBytes()); - if (!bitmap->tryAllocPixels(allocator, nullptr)) { - SkCodecPrintf("Error: Could not allocate pixels.\n"); - return false; - } - - // Zero the bitmap if the region is not completely within the image. - // TODO (msarett): Can we make this faster by implementing it to only - // zero parts of the image that we won't overwrite with - // pixels? - if (SubsetType::kPartiallyInside_SubsetType == type) { - SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() : - SkCodec::kNo_ZeroInitialized; - if (SkCodec::kNo_ZeroInitialized == zeroInit) { - bitmap->eraseColor(0); - } - } - - // Use a canvas to crop and scale to the destination bitmap - SkCanvas canvas(*bitmap); - // TODO (msarett): Maybe we can take advantage of the fact that SkRect uses floats? - SkRect src = SkRect::MakeXYWH((SkScalar) subset.x(), (SkScalar) 0, - (SkScalar) subset.width(), (SkScalar) subset.height()); - SkRect dst = SkRect::MakeXYWH((SkScalar) (outX / sampleSize), (SkScalar) (outY / sampleSize), - (SkScalar) get_scaled_dimension(subset.width(), sampleSize), - (SkScalar) get_scaled_dimension(subset.height(), sampleSize)); - SkPaint paint; - // Overwrite the dst with the src pixels - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - // TODO (msarett): Test multiple filter qualities. kNone is the default. - canvas.drawBitmapRect(tmp, src, dst, &paint); - - return true; -} - -bool SkBitmapRegionCanvas::conversionSupported(SkColorType colorType) { - // SkCanvas does not draw to these color types. - if (kIndex_8_SkColorType == colorType || kGray_8_SkColorType == colorType) { - return false; - } - - // FIXME: Call virtual function when it lands. - SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fDecoder->getInfo().alphaType(), - fDecoder->getInfo().profileType()); - return conversion_possible(info, fDecoder->getInfo()); -} diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h b/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h deleted file mode 100644 index c01f96be3c43..000000000000 --- a/gfx/skia/skia/src/android/SkBitmapRegionCanvas.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmap.h" -#include "SkBitmapRegionDecoder.h" -#include "SkCodec.h" - -/* - * This class implements SkBitmapRegionDecoder using an SkCodec and - * an SkCanvas. It uses the scanline decoder to subset the height. It then - * will subset the width and scale by drawing to an SkCanvas. - */ -// FIXME: This class works well as a performance/quality comparison for -// SkBitmapRegionCodec, but it lacks several capabilities that are -// required by BitmapRegionDecoder in Android. -// (1) WEBP decodes - because SkWebpCodec does not have a scanline -// decoder. -// (2) Decodes to kGray8 and kIndex8. -// (3) Decodes to kUnpremul. -// (4) Correcting an invalid dstColorType. For example, if the -// client requests kRGB_565 for a non-opaque image, rather than -// fail, we need to go ahead and decode to kN32. -class SkBitmapRegionCanvas : public SkBitmapRegionDecoder { -public: - - /* - * Takes ownership of pointer to decoder - */ - SkBitmapRegionCanvas(SkCodec* decoder); - - bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, - const SkIRect& desiredSubset, int sampleSize, - SkColorType colorType, bool requireUnpremul) override; - - bool conversionSupported(SkColorType colorType) override; - - SkEncodedFormat getEncodedFormat() override { return fDecoder->getEncodedFormat(); } - -private: - - SkAutoTDelete fDecoder; - - typedef SkBitmapRegionDecoder INHERITED; - -}; diff --git a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp index be3d5bcce717..df0a32ca311b 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionCodec.cpp @@ -52,27 +52,19 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat // Create the image info for the decode SkColorType dstColorType = fCodec->computeOutputColorType(prefColorType); SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); + + // Enable legacy behavior to avoid any gamma correction. Android's assets are + // adjusted to expect a non-gamma correct premultiply. + sk_sp colorSpace = nullptr; SkImageInfo decodeInfo = SkImageInfo::Make(scaledSize.width(), scaledSize.height(), - dstColorType, dstAlphaType); + dstColorType, dstAlphaType, colorSpace); // Construct a color table for the decode if necessary SkAutoTUnref colorTable(nullptr); - SkPMColor* colorPtr = nullptr; - int* colorCountPtr = nullptr; int maxColors = 256; SkPMColor colors[256]; if (kIndex_8_SkColorType == dstColorType) { - // TODO (msarett): This performs a copy that is unnecessary since - // we have not yet initialized the color table. - // And then we need to use a const cast to get - // a pointer to the color table that we can - // modify during the decode. We could alternatively - // perform the decode before creating the bitmap and - // the color table. We still would need to copy the - // colors into the color table after the decode. colorTable.reset(new SkColorTable(colors, maxColors)); - colorPtr = const_cast(colorTable->readColors()); - colorCountPtr = &maxColors; } // Initialize the destination bitmap @@ -97,7 +89,7 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat // used kAlpha8 for grayscale images (before kGray8 existed). While // the codec recognizes kGray8, we need to decode into a kAlpha8 // bitmap in order to avoid a behavior change. - outInfo = SkImageInfo::MakeA8(scaledOutWidth, scaledOutHeight); + outInfo = outInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType); } bitmap->setInfo(outInfo); if (!bitmap->tryAllocPixels(allocator, colorTable.get())) { @@ -122,31 +114,29 @@ bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocat SkAndroidCodec::AndroidOptions options; options.fSampleSize = sampleSize; options.fSubset = ⊂ - options.fColorPtr = colorPtr; - options.fColorCount = colorCountPtr; + options.fColorPtr = colors; + options.fColorCount = &maxColors; options.fZeroInitialized = zeroInit; void* dst = bitmap->getAddr(scaledOutX, scaledOutY); - // FIXME: skbug.com/4538 - // It is important that we use the rowBytes on the pixelRef. They may not be - // set properly on the bitmap. - SkPixelRef* pr = SkRef(bitmap->pixelRef()); - size_t rowBytes = pr->rowBytes(); - bitmap->setInfo(outInfo, rowBytes); - bitmap->setPixelRef(pr)->unref(); - bitmap->lockPixels(); - SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, rowBytes, &options); + SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(), + &options); if (SkCodec::kSuccess != result && SkCodec::kIncompleteInput != result) { SkCodecPrintf("Error: Could not get pixels.\n"); return false; } + // Intialize the color table + if (kIndex_8_SkColorType == dstColorType) { + colorTable->dangerous_overwriteColors(colors, maxColors); + } + return true; } bool SkBitmapRegionCodec::conversionSupported(SkColorType colorType) { - // FIXME: Call virtual function when it lands. - SkImageInfo info = SkImageInfo::Make(0, 0, colorType, fCodec->getInfo().alphaType(), - fCodec->getInfo().profileType()); - return conversion_possible(info, fCodec->getInfo()); + // Enable legacy behavior. + sk_sp colorSpace = nullptr; + SkImageInfo dstInfo = fCodec->getInfo().makeColorType(colorType).makeColorSpace(colorSpace); + return conversion_possible_ignore_color_space(dstInfo, fCodec->getInfo()); } diff --git a/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp b/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp index 101efbda452c..6dd48c5f8828 100644 --- a/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp +++ b/gfx/skia/skia/src/android/SkBitmapRegionDecoder.cpp @@ -5,7 +5,6 @@ * found in the LICENSE file. */ -#include "SkBitmapRegionCanvas.h" #include "SkBitmapRegionCodec.h" #include "SkBitmapRegionDecoder.h" #include "SkAndroidCodec.h" @@ -13,7 +12,7 @@ #include "SkCodecPriv.h" SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( - SkData* data, Strategy strategy) { + sk_sp data, Strategy strategy) { return SkBitmapRegionDecoder::Create(new SkMemoryStream(data), strategy); } @@ -22,32 +21,6 @@ SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( SkStreamRewindable* stream, Strategy strategy) { SkAutoTDelete streamDeleter(stream); switch (strategy) { - case kCanvas_Strategy: { - SkAutoTDelete codec(SkCodec::NewFromStream(streamDeleter.release())); - if (nullptr == codec) { - SkCodecPrintf("Error: Failed to create decoder.\n"); - return nullptr; - } - - SkEncodedFormat format = codec->getEncodedFormat(); - switch (format) { - case SkEncodedFormat::kJPEG_SkEncodedFormat: - case SkEncodedFormat::kPNG_SkEncodedFormat: - break; - default: - // FIXME: Support webp using a special case. Webp does not support - // scanline decoding. - return nullptr; - } - - // If the image is a jpeg or a png, the scanline ordering should always be - // kTopDown or kNone. It is relevant to check because this implementation - // only supports these two scanline orderings. - SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder() || - SkCodec::kNone_SkScanlineOrder == codec->getScanlineOrder()); - - return new SkBitmapRegionCanvas(codec.release()); - } case kAndroidCodec_Strategy: { SkAutoTDelete codec = SkAndroidCodec::NewFromStream(streamDeleter.release()); diff --git a/gfx/skia/skia/src/animator/SkAnimateMaker.cpp b/gfx/skia/skia/src/animator/SkAnimateMaker.cpp index 5186da04d814..066f877a9b50 100644 --- a/gfx/skia/skia/src/animator/SkAnimateMaker.cpp +++ b/gfx/skia/skia/src/animator/SkAnimateMaker.cpp @@ -99,9 +99,9 @@ bool SkAnimateMaker::decodeURI(const char uri[]) { // SkDebugf("animator decode %s\n", uri); // SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri); - SkAutoTDelete stream(SkStream::NewFromFile(uri)); - if (stream.get()) { - bool success = decodeStream(stream); + std::unique_ptr stream = SkStream::MakeFromFile(uri); + if (stream) { + bool success = decodeStream(stream.get()); if (hasError() && fError.hasNoun() == false) fError.setNoun(uri); return success; diff --git a/gfx/skia/skia/src/animator/SkAnimator.cpp b/gfx/skia/skia/src/animator/SkAnimator.cpp index ee75ab14affa..c5aabbba4bdc 100644 --- a/gfx/skia/skia/src/animator/SkAnimator.cpp +++ b/gfx/skia/skia/src/animator/SkAnimator.cpp @@ -82,10 +82,10 @@ bool SkAnimator::decodeURI(const char uri[]) { // SkDebugf("animator decode %s\n", uri); // SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri); - SkAutoTDelete stream(SkStream::NewFromFile(uri)); - if (stream.get()) { + std::unique_ptr stream = SkStream::MakeFromFile(uri); + if (stream) { this->setURIBase(uri); - return decodeStream(stream); + return decodeStream(stream.get()); } else { return false; } diff --git a/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp b/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp index 1ee1917d3c15..84a591f2c7dc 100644 --- a/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp +++ b/gfx/skia/skia/src/animator/SkBuildCondensedInfo.cpp @@ -142,11 +142,11 @@ void SkDisplayType::BuildCondensedInfo(SkAnimateMaker* maker) { } while (gUnknowns.count() > 0); qsort(gInfosTypeIDs.begin(), gInfosTypeIDs.count(), sizeof(gInfosTypeIDs[0]), &type_compare); #ifdef SK_DEBUG - FILE* condensed = fopen("../../src/animator/SkCondensedDebug.cpp", "w+"); + FILE* condensed = fopen("../../src/animator/SkCondensedDebug.inc", "w+"); fprintf(condensed, "#include \"SkTypes.h\"\n"); fprintf(condensed, "#ifdef SK_DEBUG\n"); #else - FILE* condensed = fopen("../../src/animator/SkCondensedRelease.cpp", "w+"); + FILE* condensed = fopen("../../src/animator/SkCondensedRelease.inc", "w+"); fprintf(condensed, "#include \"SkTypes.h\"\n"); fprintf(condensed, "#ifdef SK_RELEASE\n"); #endif diff --git a/gfx/skia/skia/src/animator/SkCondensedDebug.cpp b/gfx/skia/skia/src/animator/SkCondensedDebug.inc similarity index 100% rename from gfx/skia/skia/src/animator/SkCondensedDebug.cpp rename to gfx/skia/skia/src/animator/SkCondensedDebug.inc diff --git a/gfx/skia/skia/src/animator/SkCondensedRelease.cpp b/gfx/skia/skia/src/animator/SkCondensedRelease.inc similarity index 100% rename from gfx/skia/skia/src/animator/SkCondensedRelease.cpp rename to gfx/skia/skia/src/animator/SkCondensedRelease.inc diff --git a/gfx/skia/skia/src/animator/SkDrawBitmap.cpp b/gfx/skia/skia/src/animator/SkDrawBitmap.cpp index 64c2850a3e40..191240855c9d 100644 --- a/gfx/skia/skia/src/animator/SkDrawBitmap.cpp +++ b/gfx/skia/skia/src/animator/SkDrawBitmap.cpp @@ -73,7 +73,7 @@ void SkDrawBitmap::dump(SkAnimateMaker* maker) { SkColorGetG(fColor), SkColorGetB(fColor)); if (rowBytes > 0) SkDebugf("rowBytes=\"%d\" ", rowBytes); - const char* formatName; + const char* formatName SK_INIT_TO_AVOID_WARNING; switch (format) { case 0: formatName = "none"; break; case 1: formatName = "A8"; break; diff --git a/gfx/skia/skia/src/animator/SkDrawPaint.cpp b/gfx/skia/skia/src/animator/SkDrawPaint.cpp index 1336ea2dc429..1026630eb11f 100644 --- a/gfx/skia/skia/src/animator/SkDrawPaint.cpp +++ b/gfx/skia/skia/src/animator/SkDrawPaint.cpp @@ -259,7 +259,7 @@ void SkDrawPaint::setupPaint(SkPaint* paint) const { if (typeface == nullptr) paint->setTypeface(nullptr); else if (typeface != (SkDrawTypeface*) -1) - SkSafeUnref(paint->setTypeface(typeface->getTypeface())); + paint->setTypeface(typeface->getTypeface()); if (underline != -1) paint->setUnderlineText(SkToBool(underline)); if (xfermode != -1) diff --git a/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp b/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp index de6fa184b572..4c6532562409 100644 --- a/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp +++ b/gfx/skia/skia/src/animator/SkGetCondensedInfo.cpp @@ -11,12 +11,12 @@ #if SK_USE_CONDENSED_INFO == 1 -// SkCondensed.cpp is auto-generated +// SkCondensed.inc is auto-generated // To generate it, execute SkDisplayType::BuildCondensedInfo() #ifdef SK_DEBUG -#include "SkCondensedDebug.cpp" +#include "SkCondensedDebug.inc" #else -#include "SkCondensedRelease.cpp" +#include "SkCondensedRelease.inc" #endif static int _searchByName(const unsigned char* lengths, int count, const char* strings, const char target[]) { diff --git a/gfx/skia/skia/src/animator/SkPaintPart.h b/gfx/skia/skia/src/animator/SkPaintPart.h index a7e28ed3e27c..5d94f049e864 100644 --- a/gfx/skia/skia/src/animator/SkPaintPart.h +++ b/gfx/skia/skia/src/animator/SkPaintPart.h @@ -62,8 +62,7 @@ class SkDrawTypeface : public SkPaintPart { #ifdef SK_DUMP_ENABLED void dump(SkAnimateMaker *) override; #endif - SkTypeface* getTypeface() { - return SkTypeface::CreateFromName(fontName.c_str(), style); } + sk_sp getTypeface() { return SkTypeface::MakeFromName(fontName.c_str(), style); } protected: bool add() override; SkString fontName; diff --git a/gfx/skia/skia/src/animator/SkSnapshot.cpp b/gfx/skia/skia/src/animator/SkSnapshot.cpp index b61d602047a6..4d35432bd7e3 100644 --- a/gfx/skia/skia/src/animator/SkSnapshot.cpp +++ b/gfx/skia/skia/src/animator/SkSnapshot.cpp @@ -35,8 +35,6 @@ SkSnapshot::SkSnapshot() fSeqVal = 0; } -#include "SkDevice.h" - bool SkSnapshot::draw(SkAnimateMaker& maker) { SkASSERT(type >= 0); SkASSERT(filename.size() > 0); diff --git a/gfx/skia/skia/src/c/sk_paint.cpp b/gfx/skia/skia/src/c/sk_paint.cpp index f82cd815c1ea..126170ca4cbb 100644 --- a/gfx/skia/skia/src/c/sk_paint.cpp +++ b/gfx/skia/skia/src/c/sk_paint.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkBlendMode.h" #include "SkMaskFilter.h" #include "SkPaint.h" #include "SkShader.h" @@ -132,41 +133,41 @@ void sk_paint_set_stroke_join(sk_paint_t* cpaint, sk_stroke_join_t cjoin) { void sk_paint_set_xfermode_mode(sk_paint_t* paint, sk_xfermode_mode_t mode) { SkASSERT(paint); - SkXfermode::Mode skmode; + SkBlendMode skmode; switch (mode) { #define MAP(X, Y) case (X): skmode = (Y); break - MAP( CLEAR_SK_XFERMODE_MODE, SkXfermode::kClear_Mode ); - MAP( SRC_SK_XFERMODE_MODE, SkXfermode::kSrc_Mode ); - MAP( DST_SK_XFERMODE_MODE, SkXfermode::kDst_Mode ); - MAP( SRCOVER_SK_XFERMODE_MODE, SkXfermode::kSrcOver_Mode ); - MAP( DSTOVER_SK_XFERMODE_MODE, SkXfermode::kDstOver_Mode ); - MAP( SRCIN_SK_XFERMODE_MODE, SkXfermode::kSrcIn_Mode ); - MAP( DSTIN_SK_XFERMODE_MODE, SkXfermode::kDstIn_Mode ); - MAP( SRCOUT_SK_XFERMODE_MODE, SkXfermode::kSrcOut_Mode ); - MAP( DSTOUT_SK_XFERMODE_MODE, SkXfermode::kDstOut_Mode ); - MAP( SRCATOP_SK_XFERMODE_MODE, SkXfermode::kSrcATop_Mode ); - MAP( DSTATOP_SK_XFERMODE_MODE, SkXfermode::kDstATop_Mode ); - MAP( XOR_SK_XFERMODE_MODE, SkXfermode::kXor_Mode ); - MAP( PLUS_SK_XFERMODE_MODE, SkXfermode::kPlus_Mode ); - MAP( MODULATE_SK_XFERMODE_MODE, SkXfermode::kModulate_Mode ); - MAP( SCREEN_SK_XFERMODE_MODE, SkXfermode::kScreen_Mode ); - MAP( OVERLAY_SK_XFERMODE_MODE, SkXfermode::kOverlay_Mode ); - MAP( DARKEN_SK_XFERMODE_MODE, SkXfermode::kDarken_Mode ); - MAP( LIGHTEN_SK_XFERMODE_MODE, SkXfermode::kLighten_Mode ); - MAP( COLORDODGE_SK_XFERMODE_MODE, SkXfermode::kColorDodge_Mode ); - MAP( COLORBURN_SK_XFERMODE_MODE, SkXfermode::kColorBurn_Mode ); - MAP( HARDLIGHT_SK_XFERMODE_MODE, SkXfermode::kHardLight_Mode ); - MAP( SOFTLIGHT_SK_XFERMODE_MODE, SkXfermode::kSoftLight_Mode ); - MAP( DIFFERENCE_SK_XFERMODE_MODE, SkXfermode::kDifference_Mode ); - MAP( EXCLUSION_SK_XFERMODE_MODE, SkXfermode::kExclusion_Mode ); - MAP( MULTIPLY_SK_XFERMODE_MODE, SkXfermode::kMultiply_Mode ); - MAP( HUE_SK_XFERMODE_MODE, SkXfermode::kHue_Mode ); - MAP( SATURATION_SK_XFERMODE_MODE, SkXfermode::kSaturation_Mode ); - MAP( COLOR_SK_XFERMODE_MODE, SkXfermode::kColor_Mode ); - MAP( LUMINOSITY_SK_XFERMODE_MODE, SkXfermode::kLuminosity_Mode ); + MAP( CLEAR_SK_XFERMODE_MODE, SkBlendMode::kClear ); + MAP( SRC_SK_XFERMODE_MODE, SkBlendMode::kSrc ); + MAP( DST_SK_XFERMODE_MODE, SkBlendMode::kDst ); + MAP( SRCOVER_SK_XFERMODE_MODE, SkBlendMode::kSrcOver ); + MAP( DSTOVER_SK_XFERMODE_MODE, SkBlendMode::kDstOver ); + MAP( SRCIN_SK_XFERMODE_MODE, SkBlendMode::kSrcIn ); + MAP( DSTIN_SK_XFERMODE_MODE, SkBlendMode::kDstIn ); + MAP( SRCOUT_SK_XFERMODE_MODE, SkBlendMode::kSrcOut ); + MAP( DSTOUT_SK_XFERMODE_MODE, SkBlendMode::kDstOut ); + MAP( SRCATOP_SK_XFERMODE_MODE, SkBlendMode::kSrcATop ); + MAP( DSTATOP_SK_XFERMODE_MODE, SkBlendMode::kDstATop ); + MAP( XOR_SK_XFERMODE_MODE, SkBlendMode::kXor ); + MAP( PLUS_SK_XFERMODE_MODE, SkBlendMode::kPlus ); + MAP( MODULATE_SK_XFERMODE_MODE, SkBlendMode::kModulate ); + MAP( SCREEN_SK_XFERMODE_MODE, SkBlendMode::kScreen ); + MAP( OVERLAY_SK_XFERMODE_MODE, SkBlendMode::kOverlay ); + MAP( DARKEN_SK_XFERMODE_MODE, SkBlendMode::kDarken ); + MAP( LIGHTEN_SK_XFERMODE_MODE, SkBlendMode::kLighten ); + MAP( COLORDODGE_SK_XFERMODE_MODE, SkBlendMode::kColorDodge ); + MAP( COLORBURN_SK_XFERMODE_MODE, SkBlendMode::kColorBurn ); + MAP( HARDLIGHT_SK_XFERMODE_MODE, SkBlendMode::kHardLight ); + MAP( SOFTLIGHT_SK_XFERMODE_MODE, SkBlendMode::kSoftLight ); + MAP( DIFFERENCE_SK_XFERMODE_MODE, SkBlendMode::kDifference ); + MAP( EXCLUSION_SK_XFERMODE_MODE, SkBlendMode::kExclusion ); + MAP( MULTIPLY_SK_XFERMODE_MODE, SkBlendMode::kMultiply ); + MAP( HUE_SK_XFERMODE_MODE, SkBlendMode::kHue ); + MAP( SATURATION_SK_XFERMODE_MODE, SkBlendMode::kSaturation ); + MAP( COLOR_SK_XFERMODE_MODE, SkBlendMode::kColor ); + MAP( LUMINOSITY_SK_XFERMODE_MODE, SkBlendMode::kLuminosity ); #undef MAP default: return; } - AsPaint(paint)->setXfermodeMode(skmode); + AsPaint(paint)->setBlendMode(skmode); } diff --git a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp index 6db0991c0d6c..23242433bfcc 100644 --- a/gfx/skia/skia/src/codec/SkAndroidCodec.cpp +++ b/gfx/skia/skia/src/codec/SkAndroidCodec.cpp @@ -29,20 +29,20 @@ SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader } switch (codec->getEncodedFormat()) { -#ifdef SK_CODEC_DECODES_PNG +#ifdef SK_HAS_PNG_LIBRARY case kPNG_SkEncodedFormat: case kICO_SkEncodedFormat: #endif -#ifdef SK_CODEC_DECODES_JPEG +#ifdef SK_HAS_JPEG_LIBRARY case kJPEG_SkEncodedFormat: #endif -#ifdef SK_CODEC_DECODES_GIF +#ifdef SK_HAS_GIF_LIBRARY case kGIF_SkEncodedFormat: #endif case kBMP_SkEncodedFormat: case kWBMP_SkEncodedFormat: return new SkSampledCodec(codec.release()); -#ifdef SK_CODEC_DECODES_WEBP +#ifdef SK_HAS_WEBP_LIBRARY case kWEBP_SkEncodedFormat: return new SkWebpAdapterCodec((SkWebpCodec*) codec.release()); #endif @@ -55,7 +55,7 @@ SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader } } -SkAndroidCodec* SkAndroidCodec::NewFromData(SkData* data, SkPngChunkReader* chunkReader) { +SkAndroidCodec* SkAndroidCodec::NewFromData(sk_sp data, SkPngChunkReader* chunkReader) { if (!data) { return nullptr; } diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.cpp b/gfx/skia/skia/src/codec/SkBmpCodec.cpp index ad6f0ddc4d53..2f796ad667fa 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpCodec.cpp @@ -415,33 +415,49 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { switch (inputFormat) { case kStandard_BmpInputFormat: { - // BMPs-in-ICOs often contain an alpha mask after the image, which - // means we cannot guarantee that an image is opaque, even if the - // embedded bmp is opaque. - // We use |isOpaque| to indicate if the BMP itself is opaque, but - // still need to recommend kUnpremul when it is contained in an ICO. - SkColorType colorType = kN32_SkColorType; - SkAlphaType alphaType = inIco ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType; + // BMPs are generally opaque, however BMPs-in-ICOs may contain + // a transparency mask after the image. Therefore, we mark the + // alpha as kBinary if the BMP is contained in an ICO. + // We use |isOpaque| to indicate if the BMP itself is opaque. + SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha : + SkEncodedInfo::kOpaque_Alpha; bool isOpaque = true; + + SkEncodedInfo::Color color; + uint8_t bitsPerComponent; switch (bitsPerPixel) { // Palette formats case 1: case 2: case 4: case 8: - // We cannot recommend a palette color type for ICOs because they - // may contain a transparency mask. - if (!inIco) { - colorType = kIndex_8_SkColorType; + // In the case of ICO, kBGRA is actually the closest match, + // since we will need to apply a transparency mask. + if (inIco) { + color = SkEncodedInfo::kBGRA_Color; + bitsPerComponent = 8; + } else { + color = SkEncodedInfo::kPalette_Color; + bitsPerComponent = (uint8_t) bitsPerPixel; } break; case 24: + // In the case of ICO, kBGRA is actually the closest match, + // since we will need to apply a transparency mask. + color = inIco ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kBGR_Color; + bitsPerComponent = 8; + break; case 32: // 32-bit BMP-in-ICOs actually use the alpha channel in place of a // transparency mask. if (inIco) { isOpaque = false; + alpha = SkEncodedInfo::kUnpremul_Alpha; + color = SkEncodedInfo::kBGRA_Color; + } else { + color = SkEncodedInfo::kBGRX_Color; } + bitsPerComponent = 8; break; default: SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); @@ -453,11 +469,9 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { SkASSERT(!inIco || nullptr != stream->getMemoryBase()); // Set the image info and create a codec. - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, colorType, - alphaType); - *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPixel, numColors, - bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco); - + const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent); + *codecOut = new SkBmpStandardCodec(width, height, info, stream, bitsPerPixel, + numColors, bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco); } return true; } @@ -495,13 +509,22 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { return false; } - // Set the image info - SkAlphaType alphaType = masks->getAlphaMask() ? kUnpremul_SkAlphaType : - kOpaque_SkAlphaType; - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, - alphaType); - *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel, masks.release(), - rowOrder); + // Masked bmps are not a great fit for SkEncodedInfo, since they have + // arbitrary component orderings and bits per component. Here we choose + // somewhat reasonable values - it's ok that we don't match exactly + // because SkBmpMaskCodec has its own mask swizzler anyway. + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; + if (masks->getAlphaMask()) { + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + } else { + color = SkEncodedInfo::kBGR_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; + } + const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); + *codecOut = new SkBmpMaskCodec(width, height, info, stream, bitsPerPixel, + masks.release(), rowOrder); } return true; } @@ -526,10 +549,11 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { if (codecOut) { // RLE inputs may skip pixels, leaving them as transparent. This // is uncommon, but we cannot be certain that an RLE bmp will be - // opaque. - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, - kUnpremul_SkAlphaType); - *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, numColors, + // opaque or that we will be able to represent it with a palette. + // For that reason, we always indicate that we are kBGRA. + const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color, + SkEncodedInfo::kBinary_Alpha, 8); + *codecOut = new SkBmpRLECodec(width, height, info, stream, bitsPerPixel, numColors, bytesPerColor, offset - bytesRead, rowOrder, RLEBytes); } return true; @@ -557,12 +581,12 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { return nullptr; } -SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, +SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) - : INHERITED(info, stream) + : INHERITED(width, height, info, stream) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) - , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel))) + , fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel))) {} bool SkBmpCodec::onRewind() { @@ -579,7 +603,7 @@ int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const { SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { - if (!conversion_possible(dstInfo, this->getInfo())) { + if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } diff --git a/gfx/skia/skia/src/codec/SkBmpCodec.h b/gfx/skia/skia/src/codec/SkBmpCodec.h index a7e8e58431ba..0ece7ad6ce2f 100644 --- a/gfx/skia/skia/src/codec/SkBmpCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpCodec.h @@ -38,8 +38,8 @@ public: protected: - SkBmpCodec(const SkImageInfo& info, SkStream* stream, uint16_t bitsPerPixel, - SkCodec::SkScanlineOrder rowOrder); + SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder); SkEncodedFormat onGetEncodedFormat() const override { return kBMP_SkEncodedFormat; } diff --git a/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp b/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp index 21d231b15f01..5b28252f7c1d 100644 --- a/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpMaskCodec.cpp @@ -12,10 +12,10 @@ /* * Creates an instance of the decoder */ -SkBmpMaskCodec::SkBmpMaskCodec(const SkImageInfo& info, SkStream* stream, +SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkMasks* masks, SkCodec::SkScanlineOrder rowOrder) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fMasks(masks) , fMaskSwizzler(nullptr) , fSrcBuffer(new uint8_t [this->srcRowBytes()]) @@ -39,7 +39,7 @@ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidScale; } - if (!conversion_possible(dstInfo, this->getInfo())) { + if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } diff --git a/gfx/skia/skia/src/codec/SkBmpMaskCodec.h b/gfx/skia/skia/src/codec/SkBmpMaskCodec.h index 93b3bca5a062..cc8af856e8fd 100644 --- a/gfx/skia/skia/src/codec/SkBmpMaskCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpMaskCodec.h @@ -22,13 +22,13 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param masks color masks for certain bmp formats * @param rowOrder indicates whether rows are ordered top-down or bottom-up */ - SkBmpMaskCodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkMasks* masks, SkCodec::SkScanlineOrder rowOrder); diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp index 793bbfd2609e..dc5d689235c9 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.cpp @@ -14,12 +14,12 @@ * Creates an instance of the decoder * Called only by NewFromStream */ -SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream, +SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, size_t RLEBytes) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) , fNumColors(numColors) , fBytesPerColor(bytesPerColor) @@ -44,7 +44,7 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, // Subsets are not supported. return kUnimplemented; } - if (!conversion_possible(dstInfo, this->getInfo())) { + if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } @@ -70,7 +70,7 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, /* * Process the color table for the bmp input */ - bool SkBmpRLECodec::createColorTable(int* numColors) { + bool SkBmpRLECodec::createColorTable(SkColorType dstColorType, int* numColors) { // Allocate memory for color table uint32_t colorBytes = 0; SkPMColor colorTable[256]; @@ -96,12 +96,13 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, } // Fill in the color table + PackColorProc packARGB = choose_pack_color_proc(false, dstColorType); uint32_t i = 0; for (; i < numColorsToRead; i++) { uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); - colorTable[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); + colorTable[i] = packARGB(0xFF, red, green, blue); } // To avoid segmentation faults on bad pixel data, fill the end of the @@ -208,7 +209,8 @@ void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes, // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { - case kN32_SkColorType: { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset(dst, row * (int) dstRowBytes); dstRow[dstX] = fColorTable->operator[](index); break; @@ -241,9 +243,14 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { - case kN32_SkColorType: { + case kRGBA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset(dst, row * (int) dstRowBytes); - dstRow[dstX] = SkPackARGB32NoCheck(0xFF, red, green, blue); + dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue); + break; + } + case kBGRA_8888_SkColorType: { + SkPMColor* dstRow = SkTAddOffset(dst, row * (int) dstRowBytes); + dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { @@ -275,7 +282,7 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo, // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified - if (!this->createColorTable(inputColorCount)) { + if (!this->createColorTable(dstInfo.colorType(), inputColorCount)) { SkCodecPrintf("Error: could not create color table.\n"); return SkCodec::kInvalidInput; } @@ -315,7 +322,8 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB // the skipped pixels will be transparent. // Because of the need for transparent pixels, kN32 is the only color // type that makes sense for the destination format. - SkASSERT(kN32_SkColorType == dstInfo.colorType()); + SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || + kBGRA_8888_SkColorType == dstInfo.colorType()); if (dst) { SkSampler::Fill(dstInfo, dst, dstRowBytes, SK_ColorTRANSPARENT, opts.fZeroInitialized); } @@ -443,6 +451,7 @@ int SkBmpRLECodec::decodeRows(const SkImageInfo& info, void* dst, size_t dstRowB setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue); numPixels--; + break; } default: SkASSERT(false); diff --git a/gfx/skia/skia/src/codec/SkBmpRLECodec.h b/gfx/skia/skia/src/codec/SkBmpRLECodec.h index 2ddf8d8b90c9..c5236a810073 100644 --- a/gfx/skia/skia/src/codec/SkBmpRLECodec.h +++ b/gfx/skia/skia/src/codec/SkBmpRLECodec.h @@ -23,7 +23,7 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param numColors the number of colors in the color table @@ -35,7 +35,7 @@ public: * @param RLEBytes indicates the amount of data left in the stream * after decoding the headers */ - SkBmpRLECodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, size_t RLEBytes); @@ -58,7 +58,7 @@ private: * Creates the color table * Sets colorCount to the new color count if it is non-nullptr */ - bool createColorTable(int* colorCount); + bool createColorTable(SkColorType dstColorType, int* colorCount); bool initializeStreamBuffer(); diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp index 80a989ae4d6e..7d67d18c8ff3 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.cpp @@ -14,12 +14,12 @@ * Creates an instance of the decoder * Called only by NewFromStream */ -SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream, - uint16_t bitsPerPixel, uint32_t numColors, +SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info, + SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, bool isOpaque, bool inIco) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) , fNumColors(numColors) , fBytesPerColor(bytesPerColor) @@ -48,7 +48,7 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, SkCodecPrintf("Error: scaling not supported.\n"); return kInvalidScale; } - if (!conversion_possible(dstInfo, this->getInfo())) { + if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } @@ -68,7 +68,8 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, /* * Process the color table for the bmp input */ - bool SkBmpStandardCodec::createColorTable(SkAlphaType dstAlphaType, int* numColors) { + bool SkBmpStandardCodec::createColorTable(SkColorType dstColorType, SkAlphaType dstAlphaType, + int* numColors) { // Allocate memory for color table uint32_t colorBytes = 0; SkPMColor colorTable[256]; @@ -94,12 +95,8 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, } // Choose the proper packing function - SkPMColor (*packARGB) (uint32_t, uint32_t, uint32_t, uint32_t); - if (fIsOpaque || kUnpremul_SkAlphaType == dstAlphaType) { - packARGB = &SkPackARGB32NoCheck; - } else { - packARGB = &SkPremultiplyARGBInline; - } + bool isPremul = (kPremul_SkAlphaType == dstAlphaType) && !fIsOpaque; + PackColorProc packARGB = choose_pack_color_proc(isPremul, dstColorType); // Fill in the color table uint32_t i = 0; @@ -153,40 +150,25 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo, } void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { - // Get swizzler configuration - SkSwizzler::SrcConfig config = SkSwizzler::kUnknown; - switch (this->bitsPerPixel()) { - case 1: - config = SkSwizzler::kIndex1; - break; - case 2: - config = SkSwizzler::kIndex2; - break; - case 4: - config = SkSwizzler::kIndex4; - break; - case 8: - config = SkSwizzler::kIndex; - break; - case 24: - config = SkSwizzler::kBGR; - break; - case 32: - if (fIsOpaque) { - config = SkSwizzler::kBGRX; - } else { - config = SkSwizzler::kBGRA; - } - break; - default: - SkASSERT(false); + // In the case of bmp-in-icos, we will report BGRA to the client, + // since we may be required to apply an alpha mask after the decode. + // However, the swizzler needs to know the actual format of the bmp. + SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); + if (fInIco) { + if (this->bitsPerPixel() <= 8) { + swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, + swizzlerInfo.alpha(), this->bitsPerPixel()); + } else if (this->bitsPerPixel() == 24) { + swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color, + SkEncodedInfo::kOpaque_Alpha, 8); + } } // Get a pointer to the color table if it exists const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); // Create swizzler - fSwizzler.reset(SkSwizzler::CreateSwizzler(config, colorPtr, dstInfo, opts)); + fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, colorPtr, dstInfo, opts)); SkASSERT(fSwizzler); } @@ -194,7 +176,7 @@ SkCodec::Result SkBmpStandardCodec::prepareToDecode(const SkImageInfo& dstInfo, const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) { // Create the color table if necessary and prepare the stream for decode // Note that if it is non-NULL, inputColorCount will be modified - if (!this->createColorTable(dstInfo.alphaType(), inputColorCount)) { + if (!this->createColorTable(dstInfo.colorType(), dstInfo.alphaType(), inputColorCount)) { SkCodecPrintf("Error: could not create color table.\n"); return SkCodec::kInvalidInput; } @@ -283,7 +265,8 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI // BMP in ICO have transparency, so this cannot be 565, and this mask // prevents us from using kIndex8. The below code depends on the output // being an SkPMColor. - SkASSERT(dstInfo.colorType() == kN32_SkColorType); + SkASSERT(kRGBA_8888_SkColorType == dstInfo.colorType() || + kBGRA_8888_SkColorType == dstInfo.colorType()); // If we are sampling, make sure that we only mask the sampled pixels. // We do not need to worry about sampling in the y-dimension because that @@ -319,10 +302,11 @@ void SkBmpStandardCodec::decodeIcoMask(SkStream* stream, const SkImageInfo& dstI } } -uint32_t SkBmpStandardCodec::onGetFillValue(SkColorType colorType) const { +uint64_t SkBmpStandardCodec::onGetFillValue(const SkImageInfo& dstInfo) const { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); if (colorPtr) { - return get_color_table_fill_value(colorType, colorPtr, 0); + return get_color_table_fill_value(dstInfo.colorType(), dstInfo.alphaType(), colorPtr, 0, + nullptr); } - return INHERITED::onGetFillValue(colorType); + return INHERITED::onGetFillValue(dstInfo); } diff --git a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h index 557f6535c95f..7039cf7efea5 100644 --- a/gfx/skia/skia/src/codec/SkBmpStandardCodec.h +++ b/gfx/skia/skia/src/codec/SkBmpStandardCodec.h @@ -24,7 +24,7 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param numColors the number of colors in the color table @@ -37,7 +37,7 @@ public: * the icp mask, if there is one) * @param inIco indicates if the bmp is embedded in an ico file */ - SkBmpStandardCodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, bool isOpaque, bool inIco); @@ -57,7 +57,7 @@ protected: int* inputColorCount) override; - uint32_t onGetFillValue(SkColorType) const override; + uint64_t onGetFillValue(const SkImageInfo&) const override; SkSampler* getSampler(bool createIfNecessary) override { SkASSERT(fSwizzler); @@ -70,7 +70,7 @@ private: * Creates the color table * Sets colorCount to the new color count if it is non-nullptr */ - bool createColorTable(SkAlphaType alphaType, int* colorCount); + bool createColorTable(SkColorType colorType, SkAlphaType alphaType, int* colorCount); void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts); diff --git a/gfx/skia/skia/src/codec/SkCodec.cpp b/gfx/skia/skia/src/codec/SkCodec.cpp index 7bc831a6ac52..84afc2bdee28 100644 --- a/gfx/skia/skia/src/codec/SkCodec.cpp +++ b/gfx/skia/skia/src/codec/SkCodec.cpp @@ -11,9 +11,10 @@ #include "SkColorSpace.h" #include "SkData.h" #include "SkGifCodec.h" +#include "SkHalf.h" #include "SkIcoCodec.h" #include "SkJpegCodec.h" -#ifdef SK_CODEC_DECODES_PNG +#ifdef SK_HAS_PNG_LIBRARY #include "SkPngCodec.h" #endif #include "SkRawCodec.h" @@ -27,16 +28,16 @@ struct DecoderProc { }; static const DecoderProc gDecoderProcs[] = { -#ifdef SK_CODEC_DECODES_JPEG +#ifdef SK_HAS_JPEG_LIBRARY { SkJpegCodec::IsJpeg, SkJpegCodec::NewFromStream }, #endif -#ifdef SK_CODEC_DECODES_WEBP +#ifdef SK_HAS_WEBP_LIBRARY { SkWebpCodec::IsWebp, SkWebpCodec::NewFromStream }, #endif -#ifdef SK_CODEC_DECODES_GIF +#ifdef SK_HAS_GIF_LIBRARY { SkGifCodec::IsGif, SkGifCodec::NewFromStream }, #endif -#ifdef SK_CODEC_DECODES_PNG +#ifdef SK_HAS_PNG_LIBRARY { SkIcoCodec::IsIco, SkIcoCodec::NewFromStream }, #endif { SkBmpCodec::IsBmp, SkBmpCodec::NewFromStream }, @@ -86,7 +87,7 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, // PNG is special, since we want to be able to supply an SkPngChunkReader. // But this code follows the same pattern as the loop. -#ifdef SK_CODEC_DECODES_PNG +#ifdef SK_HAS_PNG_LIBRARY if (SkPngCodec::IsPng(buffer, bytesRead)) { return SkPngCodec::NewFromStream(streamDeleter.release(), chunkReader); } else @@ -107,19 +108,31 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, return nullptr; } -SkCodec* SkCodec::NewFromData(SkData* data, SkPngChunkReader* reader) { +SkCodec* SkCodec::NewFromData(sk_sp data, SkPngChunkReader* reader) { if (!data) { return nullptr; } return NewFromStream(new SkMemoryStream(data), reader); } -SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream, sk_sp colorSpace, - Origin origin) - : fSrcInfo(info) +SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + sk_sp colorSpace, Origin origin) + : fEncodedInfo(info) + , fSrcInfo(info.makeImageInfo(width, height, std::move(colorSpace))) + , fStream(stream) + , fNeedsRewind(false) + , fOrigin(origin) + , fDstInfo() + , fOptions() + , fCurrScanline(-1) +{} + +SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream, + Origin origin) + : fEncodedInfo(info) + , fSrcInfo(imageInfo) , fStream(stream) , fNeedsRewind(false) - , fColorSpace(colorSpace) , fOrigin(origin) , fDstInfo() , fOptions() @@ -130,8 +143,8 @@ SkCodec::~SkCodec() {} bool SkCodec::rewindIfNeeded() { if (!fStream) { - // Some codecs do not have a stream, but they hold others that do. They - // must handle rewinding themselves. + // Some codecs do not have a stream. They may hold onto their own data or another codec. + // They must handle rewinding themselves. return true; } @@ -145,6 +158,8 @@ bool SkCodec::rewindIfNeeded() { // startScanlineDecode will need to be called before decoding scanlines. fCurrScanline = -1; + // startIncrementalDecode will need to be called before incrementalDecode. + fStartedIncrementalDecode = false; if (!fStream->rewind()) { return false; @@ -153,6 +168,20 @@ bool SkCodec::rewindIfNeeded() { return this->onRewind(); } +#define CHECK_COLOR_TABLE \ + if (kIndex_8_SkColorType == info.colorType()) { \ + if (nullptr == ctable || nullptr == ctableCount) { \ + return SkCodec::kInvalidParameters; \ + } \ + } else { \ + if (ctableCount) { \ + *ctableCount = 0; \ + } \ + ctableCount = nullptr; \ + ctable = nullptr; \ + } + + SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options* options, SkPMColor ctable[], int* ctableCount) { if (kUnknown_SkColorType == info.colorType()) { @@ -165,17 +194,7 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t return kInvalidParameters; } - if (kIndex_8_SkColorType == info.colorType()) { - if (nullptr == ctable || nullptr == ctableCount) { - return kInvalidParameters; - } - } else { - if (ctableCount) { - *ctableCount = 0; - } - ctableCount = nullptr; - ctable = nullptr; - } + CHECK_COLOR_TABLE; if (!this->rewindIfNeeded()) { return kCouldNotRewind; @@ -200,6 +219,11 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t return kInvalidScale; } + fDstInfo = info; + // FIXME: fOptions should be updated to options here, since fillIncompleteImage (called below + // in this method) accesses it. Without updating, it uses the old value. + //fOptions = *options; + // On an incomplete decode, the subclass will specify the number of scanlines that it decoded // successfully. int rowsDecoded = 0; @@ -227,22 +251,77 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); } -SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, +SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* pixels, + size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int* ctableCount) { + fStartedIncrementalDecode = false; + + if (kUnknown_SkColorType == info.colorType()) { + return kInvalidConversion; + } + if (nullptr == pixels) { + return kInvalidParameters; + } + + // Ensure that valid color ptrs are passed in for kIndex8 color type + CHECK_COLOR_TABLE; + + // FIXME: If the rows come after the rows of a previous incremental decode, + // we might be able to skip the rewind, but only the implementation knows + // that. (e.g. PNG will always need to rewind, since we called longjmp, but + // a bottom-up BMP could skip rewinding if the new rows are above the old + // rows.) + if (!this->rewindIfNeeded()) { + return kCouldNotRewind; + } + + // Set options. + Options optsStorage; + if (nullptr == options) { + options = &optsStorage; + } else if (options->fSubset) { + SkIRect size = SkIRect::MakeSize(info.dimensions()); + if (!size.contains(*options->fSubset)) { + return kInvalidParameters; + } + + const int top = options->fSubset->top(); + const int bottom = options->fSubset->bottom(); + if (top < 0 || top >= info.height() || top >= bottom || bottom > info.height()) { + return kInvalidParameters; + } + } + + if (!this->dimensionsSupported(info.dimensions())) { + return kInvalidScale; + } + + fDstInfo = info; + fOptions = *options; + + const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, + fOptions, ctable, ctableCount); + if (kSuccess == result) { + fStartedIncrementalDecode = true; + } else if (kUnimplemented == result) { + // FIXME: This is temporarily necessary, until we transition SkCodec + // implementations from scanline decoding to incremental decoding. + // SkAndroidCodec will first attempt to use incremental decoding, but + // will fall back to scanline decoding if incremental returns + // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true + // (after potentially rewinding), but we do not want the next call to + // startScanlineDecode() to do a rewind. + fNeedsRewind = false; + } + return result; +} + + +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { // Reset fCurrScanline in case of failure. fCurrScanline = -1; // Ensure that valid color ptrs are passed in for kIndex8 color type - if (kIndex_8_SkColorType == dstInfo.colorType()) { - if (nullptr == ctable || nullptr == ctableCount) { - return SkCodec::kInvalidParameters; - } - } else { - if (ctableCount) { - *ctableCount = 0; - } - ctableCount = nullptr; - ctable = nullptr; - } + CHECK_COLOR_TABLE; if (!this->rewindIfNeeded()) { return kCouldNotRewind; @@ -253,36 +332,38 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, if (nullptr == options) { options = &optsStorage; } else if (options->fSubset) { - SkIRect size = SkIRect::MakeSize(dstInfo.dimensions()); + SkIRect size = SkIRect::MakeSize(info.dimensions()); if (!size.contains(*options->fSubset)) { return kInvalidInput; } // We only support subsetting in the x-dimension for scanline decoder. // Subsetting in the y-dimension can be accomplished using skipScanlines(). - if (options->fSubset->top() != 0 || options->fSubset->height() != dstInfo.height()) { + if (options->fSubset->top() != 0 || options->fSubset->height() != info.height()) { return kInvalidInput; } } // FIXME: Support subsets somehow? - if (!this->dimensionsSupported(dstInfo.dimensions())) { + if (!this->dimensionsSupported(info.dimensions())) { return kInvalidScale; } - const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); + const Result result = this->onStartScanlineDecode(info, *options, ctable, ctableCount); if (result != SkCodec::kSuccess) { return result; } fCurrScanline = 0; - fDstInfo = dstInfo; + fDstInfo = info; fOptions = *options; return kSuccess; } -SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { - return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); +#undef CHECK_COLOR_TABLE + +SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) { + return this->startScanlineDecode(info, nullptr, nullptr, nullptr); } int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { @@ -330,7 +411,6 @@ int SkCodec::outputScanline(int inputScanline) const { int SkCodec::onOutputScanline(int inputScanline) const { switch (this->getScanlineOrder()) { case kTopDown_SkScanlineOrder: - case kNone_SkScanlineOrder: return inputScanline; case kBottomUp_SkScanlineOrder: return this->getInfo().height() - inputScanline - 1; @@ -341,8 +421,24 @@ int SkCodec::onOutputScanline(int inputScanline) const { } } +uint64_t SkCodec::onGetFillValue(const SkImageInfo& dstInfo) const { + switch (dstInfo.colorType()) { + case kRGBA_F16_SkColorType: { + static constexpr uint64_t transparentColor = 0; + static constexpr uint64_t opaqueColor = ((uint64_t) SK_Half1) << 48; + return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? opaqueColor : transparentColor; + } + default: { + // This not only handles the kN32 case, but also k565, kGray8, kIndex8, since + // the low bits are zeros. + return (kOpaque_SkAlphaType == fSrcInfo.alphaType()) ? + SK_ColorBLACK : SK_ColorTRANSPARENT; + } + } +} + static void fill_proc(const SkImageInfo& info, void* dst, size_t rowBytes, - uint32_t colorOrIndex, SkCodec::ZeroInitialized zeroInit, SkSampler* sampler) { + uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit, SkSampler* sampler) { if (sampler) { sampler->fill(info, dst, rowBytes, colorOrIndex, zeroInit); } else { @@ -354,7 +450,7 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { void* fillDst; - const uint32_t fillValue = this->getFillValue(info.colorType()); + const uint64_t fillValue = this->getFillValue(info); const int linesRemaining = linesRequested - linesDecoded; SkSampler* sampler = this->getSampler(false); @@ -364,8 +460,7 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row } switch (this->getScanlineOrder()) { - case kTopDown_SkScanlineOrder: - case kNone_SkScanlineOrder: { + case kTopDown_SkScanlineOrder: { const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); fillDst = SkTAddOffset(dst, linesDecoded * rowBytes); fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler); diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp index db13aaea2973..8108f0de441c 100644 --- a/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.cpp @@ -7,7 +7,7 @@ #include "SkCodecImageGenerator.h" -SkImageGenerator* SkCodecImageGenerator::NewFromEncodedCodec(SkData* data) { +SkImageGenerator* SkCodecImageGenerator::NewFromEncodedCodec(sk_sp data) { SkCodec* codec = SkCodec::NewFromData(data); if (nullptr == codec) { return nullptr; @@ -16,26 +16,18 @@ SkImageGenerator* SkCodecImageGenerator::NewFromEncodedCodec(SkData* data) { return new SkCodecImageGenerator(codec, data); } -// FIXME: We should expose information about the encoded format on the -// SkImageGenerator, so the client can interpret the encoded -// format and request an output format. For now, as a workaround, -// we guess what output format the client wants. -static SkImageInfo fix_info(const SkCodec& codec) { - const SkImageInfo& info = codec.getInfo(); - SkAlphaType alphaType = (kUnpremul_SkAlphaType == info.alphaType()) ? kPremul_SkAlphaType : - info.alphaType(); +static SkImageInfo make_premul(const SkImageInfo& info) { + if (kUnpremul_SkAlphaType == info.alphaType()) { + return info.makeAlphaType(kPremul_SkAlphaType); + } - // Crudely guess that the presence of a color space means sRGB. - SkColorProfileType profileType = (codec.getColorSpace()) ? kSRGB_SkColorProfileType : - kLinear_SkColorProfileType; - - return SkImageInfo::Make(info.width(), info.height(), info.colorType(), alphaType, profileType); + return info; } -SkCodecImageGenerator::SkCodecImageGenerator(SkCodec* codec, SkData* data) - : INHERITED(fix_info(*codec)) +SkCodecImageGenerator::SkCodecImageGenerator(SkCodec* codec, sk_sp data) + : INHERITED(make_premul(codec->getInfo())) , fCodec(codec) - , fData(SkRef(data)) + , fData(std::move(data)) {} SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { @@ -45,7 +37,12 @@ SkData* SkCodecImageGenerator::onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) { bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { - SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, nullptr, ctable, + // FIXME (msarett): + // We don't give the client the chance to request an SkColorSpace. Until we improve + // the API, let's assume that they want legacy mode. + SkImageInfo decodeInfo = info.makeColorSpace(nullptr); + + SkCodec::Result result = fCodec->getPixels(decodeInfo, pixels, rowBytes, nullptr, ctable, ctableCount); switch (result) { case SkCodec::kSuccess: diff --git a/gfx/skia/skia/src/codec/SkCodecImageGenerator.h b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h index 6d3422311072..22a39aaaa90e 100644 --- a/gfx/skia/skia/src/codec/SkCodecImageGenerator.h +++ b/gfx/skia/skia/src/codec/SkCodecImageGenerator.h @@ -14,11 +14,11 @@ public: /* * If this data represents an encoded image that we know how to decode, * return an SkCodecImageGenerator. Otherwise return nullptr. - * - * Refs the data if an image generator can be returned. Otherwise does - * not affect the data. */ - static SkImageGenerator* NewFromEncodedCodec(SkData* data); + static SkImageGenerator* NewFromEncodedCodec(sk_sp); + static SkImageGenerator* NewFromEncodedCodec(SkData* data) { + return NewFromEncodedCodec(sk_ref_sp(data)); + } protected: SkData* onRefEncodedData(SK_REFENCODEDDATA_CTXPARAM) override; @@ -33,12 +33,11 @@ protected: private: /* * Takes ownership of codec - * Refs the data */ - SkCodecImageGenerator(SkCodec* codec, SkData* data); + SkCodecImageGenerator(SkCodec* codec, sk_sp); SkAutoTDelete fCodec; - SkAutoTUnref fData; + sk_sp fData; typedef SkImageGenerator INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkCodecPriv.h b/gfx/skia/skia/src/codec/SkCodecPriv.h index 8dde60fcd3c7..b93def879022 100644 --- a/gfx/skia/skia/src/codec/SkCodecPriv.h +++ b/gfx/skia/skia/src/codec/SkCodecPriv.h @@ -9,6 +9,7 @@ #define SkCodecPriv_DEFINED #include "SkColorPriv.h" +#include "SkColorSpaceXform.h" #include "SkColorTable.h" #include "SkImageInfo.h" #include "SkTypes.h" @@ -20,11 +21,11 @@ #endif // FIXME: Consider sharing with dm, nanbench, and tools. -inline float get_scale_from_sample_size(int sampleSize) { +static inline float get_scale_from_sample_size(int sampleSize) { return 1.0f / ((float) sampleSize); } -inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) { +static inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) { return SkIRect::MakeSize(imageDims).contains(subset); } @@ -33,7 +34,7 @@ inline bool is_valid_subset(const SkIRect& subset, const SkISize& imageDims) { * NOTE: we round down here for scaled dimension to match the behavior of SkImageDecoder * FIXME: I think we should call this get_sampled_dimension(). */ -inline int get_scaled_dimension(int srcDimension, int sampleSize) { +static inline int get_scaled_dimension(int srcDimension, int sampleSize) { if (sampleSize > srcDimension) { return 1; } @@ -46,7 +47,7 @@ inline int get_scaled_dimension(int srcDimension, int sampleSize) { * * This does not need to be called and is not called when sampleFactor == 1. */ -inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; }; +static inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; }; /* * Given a coordinate in the original image, this returns the corresponding @@ -56,7 +57,7 @@ inline int get_start_coord(int sampleFactor) { return sampleFactor / 2; }; * * This does not need to be called and is not called when sampleFactor == 1. */ -inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; }; +static inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sampleFactor; }; /* * When scaling, we will discard certain y-coordinates (rows) and @@ -66,7 +67,7 @@ inline int get_dst_coord(int srcCoord, int sampleFactor) { return srcCoord / sam * * This does not need to be called and is not called when sampleFactor == 1. */ -inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) { +static inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) { // Get the first coordinate that we want to keep int startCoord = get_start_coord(sampleFactor); @@ -79,7 +80,7 @@ inline bool is_coord_necessary(int srcCoord, int sampleFactor, int scaledDim) { return ((srcCoord - startCoord) % sampleFactor) == 0; } -inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { +static inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { if (kUnknown_SkAlphaType == dstAlpha) { return false; } @@ -107,20 +108,18 @@ inline bool valid_alpha(SkAlphaType dstAlpha, SkAlphaType srcAlpha) { } /* + * Original version of conversion_possible that does not account for color spaces. + * Used by codecs that have not been updated to support color spaces. + * * Most of our codecs support the same conversions: - * - profileType must be the same * - opaque to any alpha type * - 565 only if opaque * - premul to unpremul and vice versa - * - always support N32 + * - always support RGBA, BGRA * - otherwise match the src color type */ -inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { - // FIXME: skbug.com/4895 - // Currently, we ignore the SkColorProfileType on the SkImageInfo. We - // will treat the encoded data as linear regardless of what the client - // requests. - +static inline bool conversion_possible_ignore_color_space(const SkImageInfo& dst, + const SkImageInfo& src) { // Ensure the alpha type is valid if (!valid_alpha(dst.alphaType(), src.alphaType())) { return false; @@ -128,15 +127,11 @@ inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) // Check for supported color types switch (dst.colorType()) { - case kN32_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: return true; case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == dst.alphaType(); - case kGray_8_SkColorType: - if (kOpaque_SkAlphaType != dst.alphaType()) { - return false; - } - // Fall through + return kOpaque_SkAlphaType == src.alphaType(); default: return dst.colorType() == src.colorType(); } @@ -145,23 +140,46 @@ inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) /* * If there is a color table, get a pointer to the colors, otherwise return nullptr */ -inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { +static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { return nullptr != colorTable ? colorTable->readColors() : nullptr; } +static inline SkColorSpaceXform::ColorFormat select_xform_format(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + case kBGRA_8888_SkColorType: + return SkColorSpaceXform::kBGRA_8888_ColorFormat; + case kRGBA_F16_SkColorType: + return SkColorSpaceXform::kRGBA_F16_ColorFormat; + default: + SkASSERT(false); + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + } +} + /* * Given that the encoded image uses a color table, return the fill value */ -inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColor* colorPtr, - uint8_t fillIndex) { +static inline uint64_t get_color_table_fill_value(SkColorType dstColorType, SkAlphaType alphaType, + const SkPMColor* colorPtr, uint8_t fillIndex, SkColorSpaceXform* colorXform) { SkASSERT(nullptr != colorPtr); - switch (colorType) { - case kN32_SkColorType: + switch (dstColorType) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: return colorPtr[fillIndex]; case kRGB_565_SkColorType: return SkPixel32ToPixel16(colorPtr[fillIndex]); case kIndex_8_SkColorType: return fillIndex; + case kRGBA_F16_SkColorType: { + SkASSERT(colorXform); + uint64_t dstColor; + uint32_t srcColor = colorPtr[fillIndex]; + colorXform->apply(&dstColor, &srcColor, 1, select_xform_format(dstColorType), + SkColorSpaceXform::kRGBA_8888_ColorFormat, alphaType); + return dstColor; + } default: SkASSERT(false); return 0; @@ -172,7 +190,7 @@ inline uint32_t get_color_table_fill_value(SkColorType colorType, const SkPMColo * * Copy the codec color table back to the client when kIndex8 color type is requested */ -inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable, +static inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTable, SkPMColor* inputColorPtr, int* inputColorCount) { if (kIndex_8_SkColorType == dstInfo.colorType()) { SkASSERT(nullptr != inputColorPtr); @@ -185,21 +203,21 @@ inline void copy_color_table(const SkImageInfo& dstInfo, SkColorTable* colorTabl /* * Compute row bytes for an image using pixels per byte */ -inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) { +static inline size_t compute_row_bytes_ppb(int width, uint32_t pixelsPerByte) { return (width + pixelsPerByte - 1) / pixelsPerByte; } /* * Compute row bytes for an image using bytes per pixel */ -inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) { +static inline size_t compute_row_bytes_bpp(int width, uint32_t bytesPerPixel) { return width * bytesPerPixel; } /* * Compute row bytes for an image */ -inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { +static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { if (bitsPerPixel < 16) { SkASSERT(0 == 8 % bitsPerPixel); const uint32_t pixelsPerByte = 8 / bitsPerPixel; @@ -215,7 +233,7 @@ inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { * Get a byte from a buffer * This method is unsafe, the caller is responsible for performing a check */ -inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { +static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { return buffer[i]; } @@ -223,7 +241,7 @@ inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { * Get a short from a buffer * This method is unsafe, the caller is responsible for performing a check */ -inline uint16_t get_short(uint8_t* buffer, uint32_t i) { +static inline uint16_t get_short(uint8_t* buffer, uint32_t i) { uint16_t result; memcpy(&result, &(buffer[i]), 2); #ifdef SK_CPU_BENDIAN @@ -237,7 +255,7 @@ inline uint16_t get_short(uint8_t* buffer, uint32_t i) { * Get an int from a buffer * This method is unsafe, the caller is responsible for performing a check */ -inline uint32_t get_int(uint8_t* buffer, uint32_t i) { +static inline uint32_t get_int(uint8_t* buffer, uint32_t i) { uint32_t result; memcpy(&result, &(buffer[i]), 4); #ifdef SK_CPU_BENDIAN @@ -253,7 +271,7 @@ inline uint32_t get_int(uint8_t* buffer, uint32_t i) { * Indicates if the data is little endian * Is unaffected on false returns */ -inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) { +static inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) { // II indicates Intel (little endian) and MM indicates motorola (big endian). if (('I' != data[0] || 'I' != data[1]) && ('M' != data[0] || 'M' != data[1])) { return false; @@ -263,7 +281,7 @@ inline bool is_valid_endian_marker(const uint8_t* data, bool* isLittleEndian) { return true; } -inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) { +static inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) { if (littleEndian) { return (data[1] << 8) | (data[0]); } @@ -271,4 +289,114 @@ inline uint16_t get_endian_short(const uint8_t* data, bool littleEndian) { return (data[0] << 8) | (data[1]); } +static inline SkPMColor premultiply_argb_as_rgba(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + + return SkPackARGB_as_RGBA(a, r, g, b); +} + +static inline SkPMColor premultiply_argb_as_bgra(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + + return SkPackARGB_as_BGRA(a, r, g, b); +} + +static inline bool is_rgba(SkColorType colorType) { +#ifdef SK_PMCOLOR_IS_RGBA + return (kBGRA_8888_SkColorType != colorType); +#else + return (kRGBA_8888_SkColorType == colorType); +#endif +} + +// Method for coverting to a 32 bit pixel. +typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); + +static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType colorType) { + bool isRGBA = is_rgba(colorType); + if (isPremul) { + if (isRGBA) { + return &premultiply_argb_as_rgba; + } else { + return &premultiply_argb_as_bgra; + } + } else { + if (isRGBA) { + return &SkPackARGB_as_RGBA; + } else { + return &SkPackARGB_as_BGRA; + } + } +} + +static inline bool needs_premul(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { + return kPremul_SkAlphaType == dstInfo.alphaType() && + kUnpremul_SkAlphaType == srcInfo.alphaType(); +} + +static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { + // Color xform is necessary in order to correctly perform premultiply in linear space. + bool needsPremul = needs_premul(dstInfo, srcInfo); + + // F16 is by definition a linear space, so we always must perform a color xform. + bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType(); + + // Need a color xform when dst space does not match the src. + bool srcDstNotEqual = !SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace()); + + // We never perform a color xform in legacy mode. + bool isLegacy = nullptr == dstInfo.colorSpace(); + + return !isLegacy && (needsPremul || isF16 || srcDstNotEqual); +} + +static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) { + return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType; +} + +/* + * Alpha Type Conversions + * - kOpaque to kOpaque, kUnpremul, kPremul is valid + * - kUnpremul to kUnpremul, kPremul is valid + * + * Color Type Conversions + * - Always support kRGBA_8888, kBGRA_8888 + * - Support kRGBA_F16 when there is a linear dst color space + * - Support kIndex8 if it matches the src + * - Support k565 if kOpaque and color correction is not required + * - Support k565 if it matches the src, kOpaque, and color correction is not required + */ +static inline bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { + // Ensure the alpha type is valid. + if (!valid_alpha(dst.alphaType(), src.alphaType())) { + return false; + } + + // Check for supported color types. + switch (dst.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + return true; + case kRGBA_F16_SkColorType: + return dst.colorSpace() && dst.colorSpace()->gammaIsLinear(); + case kIndex_8_SkColorType: + return kIndex_8_SkColorType == src.colorType(); + case kRGB_565_SkColorType: + return kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + case kGray_8_SkColorType: + return kGray_8_SkColorType == src.colorType() && + kOpaque_SkAlphaType == src.alphaType() && !needs_color_xform(dst, src); + default: + return false; + } +} + #endif // SkCodecPriv_DEFINED diff --git a/gfx/skia/skia/src/codec/SkGifCodec.cpp b/gfx/skia/skia/src/codec/SkGifCodec.cpp index 2233c66c19f5..c35cd24ae498 100644 --- a/gfx/skia/skia/src/codec/SkGifCodec.cpp +++ b/gfx/skia/skia/src/codec/SkGifCodec.cpp @@ -199,25 +199,23 @@ bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** } bool frameIsSubset = (size != frameRect.size()); - // Determine the recommended alpha type. The transIndex might be valid if it less + // Determine the encoded alpha type. The transIndex might be valid if it less // than 256. We are not certain that the index is valid until we process the color // table, since some gifs have color tables with less than 256 colors. If // there might be a valid transparent index, we must indicate that the image has // alpha. - // In the case where we must support alpha, we have the option to set the - // suggested alpha type to kPremul or kUnpremul. Both are valid since the alpha - // component will always be 0xFF or the entire 32-bit pixel will be set to zero. - // We prefer kPremul because we support kPremul, and it is more efficient to use - // kPremul directly even when kUnpremul is supported. - SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaque_SkAlphaType; + // In the case where we must support alpha, we indicate kBinary, since every + // pixel will either be fully opaque or fully transparent. + SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha : + SkEncodedInfo::kOpaque_Alpha; // Return the codec - // kIndex is the most natural color type for gifs, so we set this as - // the default. - SkImageInfo imageInfo = SkImageInfo::Make(size.width(), size.height(), kIndex_8_SkColorType, - alphaType); - *codecOut = new SkGifCodec(imageInfo, streamDeleter.release(), gif.release(), transIndex, - frameRect, frameIsSubset); + // Use kPalette since Gifs are encoded with a color table. + // Use 8-bits per component, since this is the output we get from giflib. + // FIXME: Gifs can actually be encoded with 4-bits per pixel. Can we support this? + SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); + *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(), + gif.release(), transIndex, frameRect, frameIsSubset); } else { SkASSERT(nullptr != gifOut); streamDeleter.release(); @@ -239,9 +237,9 @@ SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { return nullptr; } -SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, - uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) - : INHERITED(srcInfo, stream) +SkGifCodec::SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) + : INHERITED(width, height, info, stream) , fGif(gif) , fSrcBuffer(new uint8_t[this->getInfo().width()]) , fFrameRect(frameRect) @@ -412,8 +410,9 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp // giflib guarantees these properties SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); SkASSERT(colorCount <= 256); + PackColorProc proc = choose_pack_color_proc(false, dstInfo.colorType()); for (uint32_t i = 0; i < colorCount; i++) { - colorPtr[i] = SkPackARGB32(0xFF, colorMap->Colors[i].Red, + colorPtr[i] = proc(0xFF, colorMap->Colors[i].Red, colorMap->Colors[i].Green, colorMap->Colors[i].Blue); } } @@ -451,9 +450,8 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inp SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount, const Options& opts) { // Check for valid input parameters - if (!conversion_possible(dstInfo, this->getInfo())) { - return gif_error("Cannot convert input type to output type.\n", - kInvalidConversion); + if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { + return gif_error("Cannot convert input type to output type.\n", kInvalidConversion); } // Initialize color table and copy to the client if necessary @@ -466,7 +464,7 @@ SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo void SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); const SkIRect* frameRect = fFrameIsSubset ? &fFrameRect : nullptr; - fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dstInfo, opts, + fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colorPtr, dstInfo, opts, frameRect)); SkASSERT(fSwizzler); } @@ -496,7 +494,7 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, // Initialize the swizzler if (fFrameIsSubset) { // Fill the background - SkSampler::Fill(dstInfo, dst, dstRowBytes, this->getFillValue(dstInfo.colorType()), + SkSampler::Fill(dstInfo, dst, dstRowBytes, this->getFillValue(dstInfo), opts.fZeroInitialized); } @@ -514,14 +512,15 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, // FIXME: This is similar to the implementation for bmp and png. Can we share more code or // possibly make this non-virtual? -uint32_t SkGifCodec::onGetFillValue(SkColorType colorType) const { +uint64_t SkGifCodec::onGetFillValue(const SkImageInfo& dstInfo) const { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - return get_color_table_fill_value(colorType, colorPtr, fFillIndex); + return get_color_table_fill_value(dstInfo.colorType(), dstInfo.alphaType(), colorPtr, + fFillIndex, nullptr); } SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColorCount) { - return this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, this->options()); + return this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); } void SkGifCodec::handleScanlineFrame(int count, int* rowsBeforeFrame, int* rowsInFrame) { @@ -557,7 +556,7 @@ int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { if (fFrameIsSubset) { // Fill the requested rows SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), count); - uint32_t fillValue = this->onGetFillValue(this->dstInfo().colorType()); + uint64_t fillValue = this->onGetFillValue(this->dstInfo()); fSwizzler->fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized); // Start to write pixels at the start of the image frame diff --git a/gfx/skia/skia/src/codec/SkGifCodec.h b/gfx/skia/skia/src/codec/SkGifCodec.h index a08e7ee552f5..c56d3719a9e0 100644 --- a/gfx/skia/skia/src/codec/SkGifCodec.h +++ b/gfx/skia/skia/src/codec/SkGifCodec.h @@ -66,7 +66,7 @@ protected: bool onRewind() override; - uint32_t onGetFillValue(SkColorType) const override; + uint64_t onGetFillValue(const SkImageInfo&) const override; int onOutputScanline(int inputScanline) const override; @@ -182,15 +182,15 @@ private: * Creates an instance of the decoder * Called only by NewFromStream * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of image data * @param gif pointer to library type that manages gif decode * takes ownership * @param transIndex The transparent index. An invalid value * indicates that there is no transparent index. */ - SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, uint32_t transIndex, - const SkIRect& frameRect, bool frameIsSubset); + SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset); SkAutoTCallVProc fGif; // owned SkAutoTDeleteArray fSrcBuffer; diff --git a/gfx/skia/skia/src/codec/SkIcoCodec.cpp b/gfx/skia/skia/src/codec/SkIcoCodec.cpp index d74c150ff5c8..63b72c40391a 100644 --- a/gfx/skia/skia/src/codec/SkIcoCodec.cpp +++ b/gfx/skia/skia/src/codec/SkIcoCodec.cpp @@ -128,13 +128,12 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { bytesRead = offset; // Create a new stream for the embedded codec - SkAutoTUnref data( - SkData::NewFromStream(inputStream.get(), size)); + sk_sp data(SkData::MakeFromStream(inputStream.get(), size)); if (nullptr == data.get()) { SkCodecPrintf("Warning: could not create embedded stream.\n"); break; } - SkAutoTDelete embeddedStream(new SkMemoryStream(data.get())); + SkAutoTDelete embeddedStream(new SkMemoryStream(data)); bytesRead += size; // Check if the embedded codec is bmp or png and create the codec @@ -168,22 +167,25 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { maxIndex = i; } } - SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); + int width = codecs->operator[](maxIndex)->getInfo().width(); + int height = codecs->operator[](maxIndex)->getInfo().height(); + SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo(); // Note that stream is owned by the embedded codec, the ico does not need // direct access to the stream. - return new SkIcoCodec(info, codecs.release()); + return new SkIcoCodec(width, height, info, codecs.release()); } /* * Creates an instance of the decoder * Called only by NewFromStream */ -SkIcoCodec::SkIcoCodec(const SkImageInfo& info, +SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info, SkTArray, true>* codecs) - : INHERITED(info, nullptr) + : INHERITED(width, height, info, nullptr) , fEmbeddedCodecs(codecs) , fCurrScanlineCodec(nullptr) + , fCurrIncrementalCodec(nullptr) {} /* @@ -287,6 +289,7 @@ SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, result = embeddedCodec->startScanlineDecode(dstInfo, &options, colorTable, colorCount); if (kSuccess == result) { fCurrScanlineCodec = embeddedCodec; + fCurrIncrementalCodec = nullptr; return result; } @@ -307,13 +310,82 @@ bool SkIcoCodec::onSkipScanlines(int count) { return fCurrScanlineCodec->skipScanlines(count); } +SkCodec::Result SkIcoCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, + void* pixels, size_t rowBytes, const SkCodec::Options& options, + SkPMColor* colorTable, int* colorCount) { + int index = 0; + while (true) { + index = this->chooseCodec(dstInfo.dimensions(), index); + if (index < 0) { + break; + } + + SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index); + switch (embeddedCodec->startIncrementalDecode(dstInfo, + pixels, rowBytes, &options, colorTable, colorCount)) { + case kSuccess: + fCurrIncrementalCodec = embeddedCodec; + fCurrScanlineCodec = nullptr; + return kSuccess; + case kUnimplemented: + // FIXME: embeddedCodec is a BMP. If scanline decoding would work, + // return kUnimplemented so that SkSampledCodec will fall through + // to use the scanline decoder. + // Note that calling startScanlineDecode will require an extra + // rewind. The embedded codec has an SkMemoryStream, which is + // cheap to rewind, though it will do extra work re-reading the + // header. + // Also note that we pass nullptr for Options. This is because + // Options that are valid for incremental decoding may not be + // valid for scanline decoding. + // Once BMP supports incremental decoding this workaround can go + // away. + if (embeddedCodec->startScanlineDecode(dstInfo, nullptr, + colorTable, colorCount) == kSuccess) { + return kUnimplemented; + } + // Move on to the next embedded codec. + break; + default: + break; + } + + index++; + } + + SkCodecPrintf("Error: No matching candidate image in ico.\n"); + return kInvalidScale; +} + +SkCodec::Result SkIcoCodec::onIncrementalDecode(int* rowsDecoded) { + SkASSERT(fCurrIncrementalCodec); + return fCurrIncrementalCodec->incrementalDecode(rowsDecoded); +} + SkCodec::SkScanlineOrder SkIcoCodec::onGetScanlineOrder() const { // FIXME: This function will possibly return the wrong value if it is called - // before startScanlineDecode(). - return fCurrScanlineCodec ? fCurrScanlineCodec->getScanlineOrder() : - INHERITED::onGetScanlineOrder(); + // before startScanlineDecode()/startIncrementalDecode(). + if (fCurrScanlineCodec) { + SkASSERT(!fCurrIncrementalCodec); + return fCurrScanlineCodec->getScanlineOrder(); + } + + if (fCurrIncrementalCodec) { + return fCurrIncrementalCodec->getScanlineOrder(); + } + + return INHERITED::onGetScanlineOrder(); } SkSampler* SkIcoCodec::getSampler(bool createIfNecessary) { - return fCurrScanlineCodec ? fCurrScanlineCodec->getSampler(createIfNecessary) : nullptr; + if (fCurrScanlineCodec) { + SkASSERT(!fCurrIncrementalCodec); + return fCurrScanlineCodec->getSampler(createIfNecessary); + } + + if (fCurrIncrementalCodec) { + return fCurrIncrementalCodec->getSampler(createIfNecessary); + } + + return nullptr; } diff --git a/gfx/skia/skia/src/codec/SkIcoCodec.h b/gfx/skia/skia/src/codec/SkIcoCodec.h index 9a3f248af586..a227d8c67100 100644 --- a/gfx/skia/skia/src/codec/SkIcoCodec.h +++ b/gfx/skia/skia/src/codec/SkIcoCodec.h @@ -54,6 +54,11 @@ private: bool onSkipScanlines(int count) override; + Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, + const SkCodec::Options&, SkPMColor*, int*) override; + + Result onIncrementalDecode(int* rowsDecoded) override; + SkSampler* getSampler(bool createIfNecessary) override; /* @@ -71,7 +76,8 @@ private: * Constructor called by NewFromStream * @param embeddedCodecs codecs for the embedded images, takes ownership */ - SkIcoCodec(const SkImageInfo& srcInfo, SkTArray, true>* embeddedCodecs); + SkIcoCodec(int width, int height, const SkEncodedInfo& info, + SkTArray, true>* embeddedCodecs); SkAutoTDelete, true>> fEmbeddedCodecs; // owned @@ -83,5 +89,13 @@ private: // SkAutoTDelete. It will be deleted by the destructor of fEmbeddedCodecs. SkCodec* fCurrScanlineCodec; + // Only used by incremental decoder. onStartIncrementalDecode() will set + // fCurrIncrementalCodec to one of the fEmbeddedCodecs, if it can find a + // codec of the appropriate size. We will use fCurrIncrementalCodec for + // subsequent calls to incrementalDecode(). + // fCurrIncrementalCodec is owned by this class, but should not be an + // SkAutoTDelete. It will be deleted by the destructor of fEmbeddedCodecs. + SkCodec* fCurrIncrementalCodec; + typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.cpp b/gfx/skia/skia/src/codec/SkJpegCodec.cpp index 76d2ee85727f..f6c856ee1d7a 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.cpp +++ b/gfx/skia/skia/src/codec/SkJpegCodec.cpp @@ -19,6 +19,11 @@ #include #include "SkJpegUtility.h" +// This warning triggers false postives way too often in here. +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic ignored "-Wclobbered" +#endif + extern "C" { #include "jerror.h" #include "jpeglib.h" @@ -120,7 +125,7 @@ static bool is_icc_marker(jpeg_marker_struct* marker) { * (1) Discover all ICC profile markers and verify that they are numbered properly. * (2) Copy the data from each marker into a contiguous ICC profile. */ -static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { +static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { // Note that 256 will be enough storage space since each markerIndex is stored in 8-bits. jpeg_marker_struct* markerSequence[256]; memset(markerSequence, 0, sizeof(markerSequence)); @@ -165,8 +170,8 @@ static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { } // Combine the ICC marker data into a contiguous profile. - SkAutoMalloc iccData(totalBytes); - void* dst = iccData.get(); + sk_sp iccData = SkData::MakeUninitialized(totalBytes); + void* dst = iccData->writable_data(); for (uint32_t i = 1; i <= numMarkers; i++) { jpeg_marker_struct* marker = markerSequence[i]; if (!marker) { @@ -180,7 +185,7 @@ static sk_sp get_icc_profile(jpeg_decompress_struct* dinfo) { dst = SkTAddOffset(dst, bytes); } - return SkColorSpace::NewICC(iccData.get(), totalBytes); + return iccData; } bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, @@ -191,7 +196,7 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, // libjpeg errors will be caught and reported here if (setjmp(decoderMgr->getJmpBuf())) { - return decoderMgr->returnFalse("setjmp"); + return decoderMgr->returnFalse("ReadHeader"); } // Initialize the decompress info and the source manager @@ -207,22 +212,37 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, // Read the jpeg header if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) { - return decoderMgr->returnFalse("read_header"); + return decoderMgr->returnFalse("ReadHeader"); } if (codecOut) { - // Recommend the color type to decode to - const SkColorType colorType = decoderMgr->getColorType(); + // Get the encoded color type + SkEncodedInfo::Color color; + if (!decoderMgr->getEncodedColor(&color)) { + return false; + } // Create image info object and the codec - const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->image_width, - decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaType); + SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8); Origin orientation = get_exif_orientation(decoderMgr->dinfo()); - sk_sp colorSpace = get_icc_profile(decoderMgr->dinfo()); + sk_sp iccData = get_icc_profile(decoderMgr->dinfo()); + sk_sp colorSpace = nullptr; + if (iccData) { + colorSpace = SkColorSpace::NewICC(iccData->data(), iccData->size()); + if (!colorSpace) { + SkCodecPrintf("Could not create SkColorSpace from ICC data.\n"); + } + } + if (!colorSpace) { + // Treat unmarked jpegs as sRGB. + colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + } - *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.release(), colorSpace, - orientation); + const int width = decoderMgr->dinfo()->image_width; + const int height = decoderMgr->dinfo()->image_height; + *codecOut = new SkJpegCodec(width, height, info, stream, decoderMgr.release(), + std::move(colorSpace), orientation, std::move(iccData)); } else { SkASSERT(nullptr != decoderMgrOut); *decoderMgrOut = decoderMgr.release(); @@ -242,24 +262,24 @@ SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { return nullptr; } -SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, - JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin) - : INHERITED(srcInfo, stream, colorSpace, origin) +SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin, + sk_sp iccData) + : INHERITED(width, height, info, stream, std::move(colorSpace), origin) , fDecoderMgr(decoderMgr) , fReadyState(decoderMgr->dinfo()->global_state) + , fSwizzleSrcRow(nullptr) + , fColorXformSrcRow(nullptr) , fSwizzlerSubset(SkIRect::MakeEmpty()) + , fICCData(std::move(iccData)) {} /* * Return the row bytes of a particular image type and width */ static size_t get_row_bytes(const j_decompress_ptr dinfo) { -#ifdef TURBO_HAS_565 const size_t colorBytes = (dinfo->out_color_space == JCS_RGB565) ? 2 : dinfo->out_color_components; -#else - const size_t colorBytes = dinfo->out_color_components; -#endif return dinfo->output_width * colorBytes; } @@ -318,10 +338,17 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const { bool SkJpegCodec::onRewind() { JpegDecoderMgr* decoderMgr = nullptr; if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) { - return fDecoderMgr->returnFalse("could not rewind"); + return fDecoderMgr->returnFalse("onRewind"); } SkASSERT(nullptr != decoderMgr); fDecoderMgr.reset(decoderMgr); + + fSwizzler.reset(nullptr); + fSwizzleSrcRow = nullptr; + fColorXformSrcRow = nullptr; + fStorage.reset(); + fColorXform.reset(nullptr); + return true; } @@ -330,58 +357,70 @@ bool SkJpegCodec::onRewind() { * image has been implemented * Sets the output color space */ -bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) { - if (kUnknown_SkAlphaType == dst.alphaType()) { +bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) { + if (kUnknown_SkAlphaType == dstInfo.alphaType()) { return false; } - if (kOpaque_SkAlphaType != dst.alphaType()) { + if (kOpaque_SkAlphaType != dstInfo.alphaType()) { SkCodecPrintf("Warning: an opaque image should be decoded as opaque " "- it is being decoded as non-opaque, which will draw slower\n"); } - // Check if we will decode to CMYK because a conversion to RGBA is not supported - J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space; - bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace; + // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so + // we must do it ourselves. + J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space; + bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType); // Check for valid color types and set the output color space - switch (dst.colorType()) { - case kN32_SkColorType: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: if (isCMYK) { fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; } else { -#ifdef LIBJPEG_TURBO_VERSION - // Check the byte ordering of the RGBA color space for the - // current platform - #ifdef SK_PMCOLOR_IS_RGBA - fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; - #else - fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; - #endif -#else - fDecoderMgr->dinfo()->out_color_space = JCS_RGB; -#endif + fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; + } + return true; + case kBGRA_8888_SkColorType: + if (isCMYK) { + fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; + } else if (fColorXform) { + // Our color transformation code requires RGBA order inputs, but it'll swizzle + // to BGRA for us. + fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; + } else { + fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA; } return true; case kRGB_565_SkColorType: + if (fColorXform) { + return false; + } + if (isCMYK) { fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; } else { -#ifdef TURBO_HAS_565 fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE; fDecoderMgr->dinfo()->out_color_space = JCS_RGB565; -#else - fDecoderMgr->dinfo()->out_color_space = JCS_RGB; -#endif } return true; case kGray_8_SkColorType: - if (isCMYK) { + if (fColorXform || JCS_GRAYSCALE != encodedColorType) { return false; + } + + fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; + return true; + case kRGBA_F16_SkColorType: + SkASSERT(fColorXform); + if (!dstInfo.colorSpace()->gammaIsLinear()) { + return false; + } + + if (isCMYK) { + fDecoderMgr->dinfo()->out_color_space = JCS_CMYK; } else { - // We will enable decodes to gray even if the image is color because this is - // much faster than decoding to color and then converting - fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE; + fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA; } return true; default: @@ -395,7 +434,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) { */ bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { if (setjmp(fDecoderMgr->getJmpBuf())) { - return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp"); + return fDecoderMgr->returnFalse("onDimensionsSupported"); } const unsigned int dstWidth = size.width(); @@ -430,6 +469,66 @@ bool SkJpegCodec::onDimensionsSupported(const SkISize& size) { return true; } +int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) { + // Set the jump location for libjpeg-turbo errors + if (setjmp(fDecoderMgr->getJmpBuf())) { + return 0; + } + + // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case, + // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer. + // We can never swizzle "in place" because the swizzler may perform sampling and/or + // subsetting. + // When fColorXformSrcRow is non-null, it means that we need to color xform and that + // we cannot color xform "in place" (many times we can, but not when the dst is F16). + // In this case, we will color xform from fColorXformSrc into the dst. + JSAMPLE* decodeDst = (JSAMPLE*) dst; + uint32_t* swizzleDst = (uint32_t*) dst; + size_t decodeDstRowBytes = rowBytes; + size_t swizzleDstRowBytes = rowBytes; + int dstWidth = dstInfo.width(); + if (fSwizzleSrcRow && fColorXformSrcRow) { + decodeDst = (JSAMPLE*) fSwizzleSrcRow; + swizzleDst = fColorXformSrcRow; + decodeDstRowBytes = 0; + swizzleDstRowBytes = 0; + dstWidth = fSwizzler->swizzleWidth(); + } else if (fColorXformSrcRow) { + decodeDst = (JSAMPLE*) fColorXformSrcRow; + swizzleDst = fColorXformSrcRow; + decodeDstRowBytes = 0; + swizzleDstRowBytes = 0; + } else if (fSwizzleSrcRow) { + decodeDst = (JSAMPLE*) fSwizzleSrcRow; + decodeDstRowBytes = 0; + dstWidth = fSwizzler->swizzleWidth(); + } + + for (int y = 0; y < count; y++) { + uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1); + size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); + sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550"); + if (0 == lines) { + return y; + } + + if (fSwizzler) { + fSwizzler->swizzle(swizzleDst, decodeDst); + } + + if (fColorXform) { + fColorXform->apply(dst, swizzleDst, dstWidth, select_xform_format(dstInfo.colorType()), + SkColorSpaceXform::kRGBA_8888_ColorFormat, kOpaque_SkAlphaType); + dst = SkTAddOffset(dst, rowBytes); + } + + decodeDst = SkTAddOffset(decodeDst, decodeDstRowBytes); + swizzleDst = SkTAddOffset(swizzleDst, swizzleDstRowBytes); + } + + return count; +} + /* * Performs the jpeg decode */ @@ -450,12 +549,13 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } + this->initializeColorXform(dstInfo); + // Check if we can decode to the requested destination and set the output color space if (!this->setOutputColorSpace(dstInfo)) { - return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion); + return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion); } - // Now, given valid output dimensions, we can start the decompress if (!jpeg_start_decompress(dinfo)) { return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); } @@ -465,71 +565,56 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, SkASSERT(1 == dinfo->rec_outbuf_height); J_COLOR_SPACE colorSpace = dinfo->out_color_space; - if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { + if (JCS_CMYK == colorSpace) { this->initializeSwizzler(dstInfo, options); } - // Perform the decode a single row at a time - uint32_t dstHeight = dstInfo.height(); + this->allocateStorage(dstInfo); - JSAMPLE* dstRow; - if (fSwizzler) { - // write data to storage row, then sample using swizzler - dstRow = fSrcRow; - } else { - // write data directly to dst - dstRow = (JSAMPLE*) dst; - } - - for (uint32_t y = 0; y < dstHeight; y++) { - // Read rows of the image - uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1); - sk_msan_mark_initialized(dstRow, dstRow + dstRowBytes, "skbug.com/4550"); - - // If we cannot read enough rows, assume the input is incomplete - if (lines != 1) { - *rowsDecoded = y; - - return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); - } - - if (fSwizzler) { - // use swizzler to sample row - fSwizzler->swizzle(dst, dstRow); - dst = SkTAddOffset(dst, dstRowBytes); - } else { - dstRow = SkTAddOffset(dstRow, dstRowBytes); - } + int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); + if (rows < dstInfo.height()) { + *rowsDecoded = rows; + return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); } return kSuccess; } -void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { - SkSwizzler::SrcConfig srcConfig = SkSwizzler::kUnknown; - if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { - srcConfig = SkSwizzler::kCMYK; - } else { - // If the out_color_space is not CMYK, the only reason we would need a swizzler is - // for sampling and/or subsetting. - switch (dstInfo.colorType()) { - case kGray_8_SkColorType: - srcConfig = SkSwizzler::kNoOp8; - break; - case kN32_SkColorType: - srcConfig = SkSwizzler::kNoOp32; - break; - case kRGB_565_SkColorType: - srcConfig = SkSwizzler::kNoOp16; - break; - default: - // This function should only be called if the colorType is supported by jpeg - SkASSERT(false); - } +void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) { + int dstWidth = dstInfo.width(); + + size_t swizzleBytes = 0; + if (fSwizzler) { + swizzleBytes = get_row_bytes(fDecoderMgr->dinfo()); + dstWidth = fSwizzler->swizzleWidth(); + SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes)); } - if (JCS_RGB == fDecoderMgr->dinfo()->out_color_space) { - srcConfig = SkSwizzler::kRGB; + size_t xformBytes = 0; + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + SkASSERT(fColorXform); + xformBytes = dstWidth * sizeof(uint32_t); + } + + size_t totalBytes = swizzleBytes + xformBytes; + if (totalBytes > 0) { + fStorage.reset(totalBytes); + fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr; + fColorXformSrcRow = (xformBytes > 0) ? + SkTAddOffset(fStorage.get(), swizzleBytes) : nullptr; + } +} + +void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { + // libjpeg-turbo may have already performed color conversion. We must indicate the + // appropriate format to the swizzler. + SkEncodedInfo swizzlerInfo = this->getEncodedInfo(); + bool preSwizzled = true; + if (JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { + preSwizzled = false; + swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color, + swizzlerInfo.alpha(), + swizzlerInfo.bitsPerComponent()); } Options swizzlerOptions = options; @@ -541,19 +626,26 @@ void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& fSwizzlerSubset.width() == options.fSubset->width()); swizzlerOptions.fSubset = &fSwizzlerSubset; } - fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, dstInfo, swizzlerOptions)); + fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions, + nullptr, preSwizzled)); SkASSERT(fSwizzler); - fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); - fSrcRow = fStorage.get(); +} + +void SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo) { + if (needs_color_xform(dstInfo, this->getInfo())) { + fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); + SkASSERT(fColorXform); + } } SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) { if (!createIfNecessary || fSwizzler) { - SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow)); + SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow)); return fSwizzler; } this->initializeSwizzler(this->dstInfo(), this->options()); + this->allocateStorage(this->dstInfo()); return fSwizzler; } @@ -565,27 +657,18 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kInvalidInput; } + this->initializeColorXform(dstInfo); + // Check if we can decode to the requested destination and set the output color space if (!this->setOutputColorSpace(dstInfo)) { - return kInvalidConversion; + return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion); } - // Remove objects used for sampling. - fSwizzler.reset(nullptr); - fSrcRow = nullptr; - fStorage.reset(); - - // Now, given valid output dimensions, we can start the decompress if (!jpeg_start_decompress(fDecoderMgr->dinfo())) { SkCodecPrintf("start decompress failed\n"); return kInvalidInput; } - if (options.fSubset) { - fSwizzlerSubset = *options.fSubset; - } - -#ifdef TURBO_HAS_CROP if (options.fSubset) { uint32_t startX = options.fSubset->x(); uint32_t width = options.fSubset->width(); @@ -627,76 +710,29 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, if (!fSwizzler && JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) { this->initializeSwizzler(dstInfo, options); } -#else - // We will need a swizzler if we are performing a subset decode or - // converting from CMYK. - J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->out_color_space; - if (options.fSubset || JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { - this->initializeSwizzler(dstInfo, options); - } -#endif + + this->allocateStorage(dstInfo); return kSuccess; } int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { - // Set the jump location for libjpeg errors - if (setjmp(fDecoderMgr->getJmpBuf())) { - return fDecoderMgr->returnFailure("setjmp", kInvalidInput); - } - // Read rows one at a time - JSAMPLE* dstRow; - size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo()); - if (fSwizzler) { - // write data to storage row, then sample using swizzler - dstRow = fSrcRow; - } else { - // write data directly to dst - SkASSERT(count == 1 || dstRowBytes >= srcRowBytes); - dstRow = (JSAMPLE*) dst; + int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count); + if (rows < count) { + // This allows us to skip calling jpeg_finish_decompress(). + fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); } - for (int y = 0; y < count; y++) { - // Read row of the image - uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1); - sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550"); - if (rowsDecoded != 1) { - fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height(); - return y; - } - - if (fSwizzler) { - // use swizzler to sample row - fSwizzler->swizzle(dst, dstRow); - dst = SkTAddOffset(dst, dstRowBytes); - } else { - dstRow = SkTAddOffset(dstRow, dstRowBytes); - } - } - return count; + return rows; } bool SkJpegCodec::onSkipScanlines(int count) { // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { - return fDecoderMgr->returnFalse("setjmp"); + return fDecoderMgr->returnFalse("onSkipScanlines"); } -#ifdef TURBO_HAS_SKIP return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count); -#else - if (!fSrcRow) { - fStorage.reset(get_row_bytes(fDecoderMgr->dinfo())); - fSrcRow = fStorage.get(); - } - - for (int y = 0; y < count; y++) { - if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) { - return false; - } - } - return true; -#endif } static bool is_yuv_supported(jpeg_decompress_struct* dinfo) { diff --git a/gfx/skia/skia/src/codec/SkJpegCodec.h b/gfx/skia/skia/src/codec/SkJpegCodec.h index d3ea132da72b..30425eea3f80 100644 --- a/gfx/skia/skia/src/codec/SkJpegCodec.h +++ b/gfx/skia/skia/src/codec/SkJpegCodec.h @@ -10,6 +10,7 @@ #include "SkCodec.h" #include "SkColorSpace.h" +#include "SkColorSpaceXform.h" #include "SkImageInfo.h" #include "SkSwizzler.h" #include "SkStream.h" @@ -58,6 +59,8 @@ protected: bool onDimensionsSupported(const SkISize&) override; + sk_sp getICCData() const override { return fICCData; } + private: /* @@ -86,43 +89,58 @@ private: * Creates an instance of the decoder * Called only by NewFromStream * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the encoded image data * @param decoderMgr holds decompress struct, src manager, and error manager * takes ownership */ - SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, JpegDecoderMgr* decoderMgr, - sk_sp colorSpace, Origin origin); + SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin, + sk_sp iccData); /* * Checks if the conversion between the input image and the requested output - * image has been implemented - * Sets the output color space + * image has been implemented. + * + * Sets the output color space. */ bool setOutputColorSpace(const SkImageInfo& dst); - // scanline decoding void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options); + void initializeColorXform(const SkImageInfo& dstInfo); + void allocateStorage(const SkImageInfo& dstInfo); + int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count); + + /* + * Scanline decoding. + */ SkSampler* getSampler(bool createIfNecessary) override; Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, SkPMColor ctable[], int* ctableCount) override; int onGetScanlines(void* dst, int count, size_t rowBytes) override; bool onSkipScanlines(int count) override; - SkAutoTDelete fDecoderMgr; + SkAutoTDelete fDecoderMgr; + // We will save the state of the decompress struct after reading the header. // This allows us to safely call onGetScaledDimensions() at any time. - const int fReadyState; + const int fReadyState; + + + SkAutoTMalloc fStorage; + uint8_t* fSwizzleSrcRow; + uint32_t* fColorXformSrcRow; - // scanline decoding - SkAutoTMalloc fStorage; // Only used if sampling is needed - uint8_t* fSrcRow; // Only used if sampling is needed // libjpeg-turbo provides some subsetting. In the case that libjpeg-turbo // cannot take the exact the subset that we need, we will use the swizzler // to further subset the output from libjpeg-turbo. - SkIRect fSwizzlerSubset; - SkAutoTDelete fSwizzler; - + SkIRect fSwizzlerSubset; + + SkAutoTDelete fSwizzler; + std::unique_ptr fColorXform; + + sk_sp fICCData; + typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp index 63228bb58501..70401c039117 100644 --- a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp +++ b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.cpp @@ -35,12 +35,25 @@ SkCodec::Result JpegDecoderMgr::returnFailure(const char caller[], SkCodec::Resu return result; } -SkColorType JpegDecoderMgr::getColorType() { +bool JpegDecoderMgr::getEncodedColor(SkEncodedInfo::Color* outColor) { switch (fDInfo.jpeg_color_space) { case JCS_GRAYSCALE: - return kGray_8_SkColorType; + *outColor = SkEncodedInfo::kGray_Color; + return true; + case JCS_YCbCr: + *outColor = SkEncodedInfo::kYUV_Color; + return true; + case JCS_RGB: + *outColor = SkEncodedInfo::kRGB_Color; + return true; + case JCS_YCCK: + *outColor = SkEncodedInfo::kYCCK_Color; + return true; + case JCS_CMYK: + *outColor = SkEncodedInfo::kInvertedCMYK_Color; + return true; default: - return kN32_SkColorType; + return false; } } diff --git a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h index e1127bad3470..7bc422d4ff0b 100644 --- a/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h +++ b/gfx/skia/skia/src/codec/SkJpegDecoderMgr.h @@ -43,9 +43,10 @@ public: void init(); /* - * Recommend a color type based on the encoded format + * Returns true if it successfully sets outColor to the encoded color, + * and false otherwise. */ - SkColorType getColorType(); + bool getEncodedColor(SkEncodedInfo::Color* outColor); /* * Free memory used by the decode manager diff --git a/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp b/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp index 7630a7b59f06..2df10ee24cbc 100644 --- a/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp +++ b/gfx/skia/skia/src/codec/SkMaskSwizzler.cpp @@ -9,7 +9,7 @@ #include "SkColorPriv.h" #include "SkMaskSwizzler.h" -static void swizzle_mask16_to_n32_opaque( +static void swizzle_mask16_to_rgba_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -21,12 +21,29 @@ static void swizzle_mask16_to_n32_opaque( uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); - dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(0xFF, red, green, blue); srcPtr += sampleX; } } -static void swizzle_mask16_to_n32_unpremul( +static void swizzle_mask16_to_bgra_opaque( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint16_t* srcPtr = ((uint16_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint16_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i] = SkPackARGB_as_BGRA(0xFF, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask16_to_rgba_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -39,12 +56,12 @@ static void swizzle_mask16_to_n32_unpremul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(alpha, red, green, blue); srcPtr += sampleX; } } -static void swizzle_mask16_to_n32_premul( +static void swizzle_mask16_to_bgra_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -57,7 +74,43 @@ static void swizzle_mask16_to_n32_premul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_BGRA(alpha, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask16_to_rgba_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint16_t* srcPtr = ((uint16_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint16_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_rgba(alpha, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask16_to_bgra_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint16_t* srcPtr = ((uint16_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint16_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_bgra(alpha, red, green, blue); srcPtr += sampleX; } } @@ -81,7 +134,7 @@ static void swizzle_mask16_to_565( } } -static void swizzle_mask24_to_n32_opaque( +static void swizzle_mask24_to_rgba_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -93,12 +146,29 @@ static void swizzle_mask24_to_n32_opaque( uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); - dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(0xFF, red, green, blue); srcRow += 3 * sampleX; } } -static void swizzle_mask24_to_n32_unpremul( +static void swizzle_mask24_to_bgra_opaque( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + srcRow += 3 * startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i] = SkPackARGB_as_BGRA(0xFF, red, green, blue); + srcRow += 3 * sampleX; + } +} + +static void swizzle_mask24_to_rgba_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -111,12 +181,12 @@ static void swizzle_mask24_to_n32_unpremul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(alpha, red, green, blue); srcRow += 3 * sampleX; } } -static void swizzle_mask24_to_n32_premul( +static void swizzle_mask24_to_bgra_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -129,7 +199,43 @@ static void swizzle_mask24_to_n32_premul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_BGRA(alpha, red, green, blue); + srcRow += 3 * sampleX; + } +} + +static void swizzle_mask24_to_rgba_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + srcRow += 3 * startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_rgba(alpha, red, green, blue); + srcRow += 3 * sampleX; + } +} + +static void swizzle_mask24_to_bgra_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + srcRow += 3 * startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcRow[0] | (srcRow[1] << 8) | srcRow[2] << 16; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_bgra(alpha, red, green, blue); srcRow += 3 * sampleX; } } @@ -151,7 +257,7 @@ static void swizzle_mask24_to_565( } } -static void swizzle_mask32_to_n32_opaque( +static void swizzle_mask32_to_rgba_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -163,12 +269,29 @@ static void swizzle_mask32_to_n32_opaque( uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); - dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(0xFF, red, green, blue); srcPtr += sampleX; } } -static void swizzle_mask32_to_n32_unpremul( +static void swizzle_mask32_to_bgra_opaque( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint32_t* srcPtr = ((uint32_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i] = SkPackARGB_as_BGRA(0xFF, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask32_to_rgba_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -181,12 +304,12 @@ static void swizzle_mask32_to_n32_unpremul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPackARGB32NoCheck(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_RGBA(alpha, red, green, blue); srcPtr += sampleX; } } -static void swizzle_mask32_to_n32_premul( +static void swizzle_mask32_to_bgra_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, uint32_t startX, uint32_t sampleX) { @@ -199,7 +322,43 @@ static void swizzle_mask32_to_n32_premul( uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); - dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); + dstPtr[i] = SkPackARGB_as_BGRA(alpha, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask32_to_rgba_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint32_t* srcPtr = ((uint32_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_rgba(alpha, red, green, blue); + srcPtr += sampleX; + } +} + +static void swizzle_mask32_to_bgra_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks, + uint32_t startX, uint32_t sampleX) { + + // Use the masks to decode to the destination + uint32_t* srcPtr = ((uint32_t*) srcRow) + startX; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcPtr[0]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + dstPtr[i] = premultiply_argb_as_bgra(alpha, red, green, blue); srcPtr += sampleX; } } @@ -234,16 +393,32 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo, switch (bitsPerPixel) { case 16: switch (dstInfo.colorType()) { - case kN32_SkColorType: + case kRGBA_8888_SkColorType: if (kOpaque_SkAlphaType == srcInfo.alphaType()) { - proc = &swizzle_mask16_to_n32_opaque; + proc = &swizzle_mask16_to_rgba_opaque; } else { switch (dstInfo.alphaType()) { case kUnpremul_SkAlphaType: - proc = &swizzle_mask16_to_n32_unpremul; + proc = &swizzle_mask16_to_rgba_unpremul; break; case kPremul_SkAlphaType: - proc = &swizzle_mask16_to_n32_premul; + proc = &swizzle_mask16_to_rgba_premul; + break; + default: + break; + } + } + break; + case kBGRA_8888_SkColorType: + if (kOpaque_SkAlphaType == srcInfo.alphaType()) { + proc = &swizzle_mask16_to_bgra_opaque; + } else { + switch (dstInfo.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask16_to_bgra_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask16_to_bgra_premul; break; default: break; @@ -259,16 +434,32 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo, break; case 24: switch (dstInfo.colorType()) { - case kN32_SkColorType: + case kRGBA_8888_SkColorType: if (kOpaque_SkAlphaType == srcInfo.alphaType()) { - proc = &swizzle_mask24_to_n32_opaque; + proc = &swizzle_mask24_to_rgba_opaque; } else { switch (dstInfo.alphaType()) { case kUnpremul_SkAlphaType: - proc = &swizzle_mask24_to_n32_unpremul; + proc = &swizzle_mask24_to_rgba_unpremul; break; case kPremul_SkAlphaType: - proc = &swizzle_mask24_to_n32_premul; + proc = &swizzle_mask24_to_rgba_premul; + break; + default: + break; + } + } + break; + case kBGRA_8888_SkColorType: + if (kOpaque_SkAlphaType == srcInfo.alphaType()) { + proc = &swizzle_mask24_to_bgra_opaque; + } else { + switch (dstInfo.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask24_to_bgra_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask24_to_bgra_premul; break; default: break; @@ -284,16 +475,32 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(const SkImageInfo& dstInfo, break; case 32: switch (dstInfo.colorType()) { - case kN32_SkColorType: + case kRGBA_8888_SkColorType: if (kOpaque_SkAlphaType == srcInfo.alphaType()) { - proc = &swizzle_mask32_to_n32_opaque; + proc = &swizzle_mask32_to_rgba_opaque; } else { switch (dstInfo.alphaType()) { case kUnpremul_SkAlphaType: - proc = &swizzle_mask32_to_n32_unpremul; + proc = &swizzle_mask32_to_rgba_unpremul; break; case kPremul_SkAlphaType: - proc = &swizzle_mask32_to_n32_premul; + proc = &swizzle_mask32_to_rgba_premul; + break; + default: + break; + } + } + break; + case kBGRA_8888_SkColorType: + if (kOpaque_SkAlphaType == srcInfo.alphaType()) { + proc = &swizzle_mask32_to_bgra_opaque; + } else { + switch (dstInfo.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask32_to_bgra_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask32_to_bgra_premul; break; default: break; diff --git a/gfx/skia/skia/src/codec/SkMaskSwizzler.h b/gfx/skia/skia/src/codec/SkMaskSwizzler.h index 1dc1918f4948..3bf8d1758f34 100644 --- a/gfx/skia/skia/src/codec/SkMaskSwizzler.h +++ b/gfx/skia/skia/src/codec/SkMaskSwizzler.h @@ -39,7 +39,7 @@ public: /** * Implement fill using a custom width. */ - void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint32_t colorOrIndex, + void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) override { const SkImageInfo fillInfo = info.makeWH(fDstWidth, info.height()); SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit); diff --git a/gfx/skia/skia/src/codec/SkPngCodec.cpp b/gfx/skia/skia/src/codec/SkPngCodec.cpp index 8ae2360f2570..30fffe11636b 100644 --- a/gfx/skia/skia/src/codec/SkPngCodec.cpp +++ b/gfx/skia/skia/src/codec/SkPngCodec.cpp @@ -8,42 +8,53 @@ #include "SkBitmap.h" #include "SkCodecPriv.h" #include "SkColorPriv.h" -#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" #include "SkColorTable.h" #include "SkMath.h" #include "SkOpts.h" #include "SkPngCodec.h" +#include "SkPoint3.h" #include "SkSize.h" #include "SkStream.h" #include "SkSwizzler.h" #include "SkTemplates.h" #include "SkUtils.h" +#include "png.h" + +// This warning triggers false postives way too often in here. +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic ignored "-Wclobbered" +#endif + +#if PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5) + // This is not needed with version 1.5 + #undef SK_GOOGLE3_PNG_HACK +#endif + +// FIXME (scroggo): We can use png_jumpbuf directly once Google3 is on 1.6 +#define PNG_JMPBUF(x) png_jmpbuf((png_structp) x) + /////////////////////////////////////////////////////////////////////////////// // Callback functions /////////////////////////////////////////////////////////////////////////////// +// When setjmp is first called, it returns 0, meaning longjmp was not called. +constexpr int kSetJmpOkay = 0; +// An error internal to libpng. +constexpr int kPngError = 1; +// Passed to longjmp when we have decoded as many lines as we need. +constexpr int kStopDecoding = 2; + static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { SkCodecPrintf("------ png error %s\n", msg); - longjmp(png_jmpbuf(png_ptr), 1); + longjmp(PNG_JMPBUF(png_ptr), kPngError); } void sk_warning_fn(png_structp, png_const_charp msg) { SkCodecPrintf("----- png warning %s\n", msg); } -static void sk_read_fn(png_structp png_ptr, png_bytep data, - png_size_t length) { - SkStream* stream = static_cast(png_get_io_ptr(png_ptr)); - const size_t bytes = stream->read(data, length); - if (bytes != length) { - // FIXME: We want to report the fact that the stream was truncated. - // One way to do that might be to pass a enum to longjmp so setjmp can - // specify the failure. - png_error(png_ptr, "Read Error!"); - } -} - #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); @@ -58,9 +69,22 @@ static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { class AutoCleanPng : public SkNoncopyable { public: - AutoCleanPng(png_structp png_ptr) + /* + * This class does not take ownership of stream or reader, but if codecPtr + * is non-NULL, and decodeBounds succeeds, it will have created a new + * SkCodec (pointed to by *codecPtr) which will own/ref them, as well as + * the png_ptr and info_ptr. + */ + AutoCleanPng(png_structp png_ptr, SkStream* stream, SkPngChunkReader* reader, + SkCodec** codecPtr) : fPng_ptr(png_ptr) - , fInfo_ptr(nullptr) {} + , fInfo_ptr(nullptr) + , fDecodedBounds(false) + , fReadHeader(false) + , fStream(stream) + , fChunkReader(reader) + , fOutCodec(codecPtr) + {} ~AutoCleanPng() { // fInfo_ptr will never be non-nullptr unless fPng_ptr is. @@ -75,25 +99,121 @@ public: fInfo_ptr = info_ptr; } - void release() { + /** + * Reads enough of the input stream to decode the bounds. + * @return false if the stream is not a valid PNG (or too short). + * true if it read enough of the stream to determine the bounds. + * In the latter case, the stream may have been read beyond the + * point to determine the bounds, and the png_ptr will have saved + * any extra data. Further, if the codecPtr supplied to the + * constructor was not NULL, it will now point to a new SkCodec, + * which owns (or refs, in the case of the SkPngChunkReader) the + * inputs. If codecPtr was NULL, the png_ptr and info_ptr are + * unowned, and it is up to the caller to destroy them. + */ + bool decodeBounds(); + +private: + png_structp fPng_ptr; + png_infop fInfo_ptr; + bool fDecodedBounds; + bool fReadHeader; + SkStream* fStream; + SkPngChunkReader* fChunkReader; + SkCodec** fOutCodec; + + /** + * Supplied to libpng to call when it has read enough data to determine + * bounds. + */ + static void InfoCallback(png_structp png_ptr, png_infop) { + // png_get_progressive_ptr returns the pointer we set on the png_ptr with + // png_set_progressive_read_fn + static_cast(png_get_progressive_ptr(png_ptr))->infoCallback(); + } + + void infoCallback(); + +#ifdef SK_GOOGLE3_PNG_HACK +// public so it can be called by SkPngCodec::rereadHeaderIfNecessary(). +public: +#endif + void releasePngPtrs() { fPng_ptr = nullptr; fInfo_ptr = nullptr; } - -private: - png_structp fPng_ptr; - png_infop fInfo_ptr; }; #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) -// Method for coverting to either an SkPMColor or a similarly packed -// unpremultiplied color. -typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); +bool AutoCleanPng::decodeBounds() { + if (setjmp(PNG_JMPBUF(fPng_ptr))) { + return false; + } -// Note: SkColorTable claims to store SkPMColors, which is not necessarily -// the case here. -// TODO: If we add support for non-native swizzles, we'll need to handle that here. -bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { + png_set_progressive_read_fn(fPng_ptr, this, InfoCallback, nullptr, nullptr); + + // Arbitrary buffer size, though note that it matches (below) + // SkPngCodec::processData(). FIXME: Can we better suit this to the size of + // the PNG header? + constexpr size_t kBufferSize = 4096; + char buffer[kBufferSize]; + + while (true) { + const size_t bytesRead = fStream->read(buffer, kBufferSize); + if (!bytesRead) { + // We have read to the end of the input without decoding bounds. + break; + } + + png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead); + if (fReadHeader) { + break; + } + } + + // For safety, clear the pointer to this object. + png_set_progressive_read_fn(fPng_ptr, nullptr, nullptr, nullptr, nullptr); + return fDecodedBounds; +} + +void SkPngCodec::processData() { + switch (setjmp(PNG_JMPBUF(fPng_ptr))) { + case kPngError: + // There was an error. Stop processing data. + // FIXME: Do we need to discard png_ptr? + return; + case kStopDecoding: + // We decoded all the lines we want. + return; + case kSetJmpOkay: + // Everything is okay. + break; + default: + // No other values should be passed to longjmp. + SkASSERT(false); + } + + // Arbitrary buffer size + constexpr size_t kBufferSize = 4096; + char buffer[kBufferSize]; + + while (true) { + const size_t bytesRead = this->stream()->read(buffer, kBufferSize); + png_process_data(fPng_ptr, fInfo_ptr, (png_bytep) buffer, bytesRead); + + if (!bytesRead) { + // We have read to the end of the input. Note that we quit *after* + // calling png_process_data, because decodeBounds may have told + // libpng to save the remainder of the buffer, in which case + // png_process_data will process the saved buffer, though the + // stream has no more to read. + break; + } + } +} + +// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here. +bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) { int numColors; png_color* palette; @@ -101,26 +221,27 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { return false; } - // Note: These are not necessarily SkPMColors. - SkPMColor colorPtr[256]; + // Contents depend on tableColorType and our choice of if/when to premultiply: + // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA } + SkPMColor colorTable[256]; + SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType(); png_bytep alphas; int numColorsWithAlpha = 0; if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { + // If we are performing a color xform, it will handle the premultiply. Otherwise, + // we'll do it here. + bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo()); + // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. - PackColorProc proc; - if (premultiply) { - proc = &SkPremultiplyARGBInline; - } else { - proc = &SkPackARGB32NoCheck; - } + PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType); for (int i = 0; i < numColorsWithAlpha; i++) { // We don't have a function in SkOpts that combines a set of alphas with a set // of RGBs. We could write one, but it's hardly worth it, given that this // is such a small fraction of the total decode time. - colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue); + colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue); palette++; } } @@ -134,19 +255,33 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { SkASSERT(&palette->green < &palette->blue); #endif -#ifdef SK_PMCOLOR_IS_RGBA - SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); -#else - SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); -#endif + if (is_rgba(tableColorType)) { + SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette, + numColors - numColorsWithAlpha); + } else { + SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette, + numColors - numColorsWithAlpha); + } + } + + // If we are not decoding to F16, we can color xform now and store the results + // in the color table. + if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) { + SkColorSpaceXform::ColorFormat xformColorFormat = is_rgba(dstInfo.colorType()) ? + SkColorSpaceXform::kRGBA_8888_ColorFormat : + SkColorSpaceXform::kBGRA_8888_ColorFormat; + SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + fColorXform->apply(colorTable, colorTable, numColors, xformColorFormat, + SkColorSpaceXform::kRGBA_8888_ColorFormat, xformAlphaType); } // Pad the color table with the last color in the table (or black) in the case that // invalid pixel indices exceed the number of colors in the table. const int maxColors = 1 << fBitDepth; if (numColors < maxColors) { - SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK; - sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); + SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK; + sk_memset32(colorTable + numColors, lastColor, maxColors - numColors); } // Set the new color count. @@ -154,7 +289,7 @@ bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { *ctableCount = maxColors; } - fColorTable.reset(new SkColorTable(colorPtr, maxColors)); + fColorTable.reset(new SkColorTable(colorTable, maxColors)); return true; } @@ -166,6 +301,8 @@ bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); } +#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) + static float png_fixed_point_to_float(png_fixed_point x) { // We multiply by the same factor that libpng used to convert // fixed point -> double. Since we want floats, we choose to @@ -179,6 +316,71 @@ static float png_inverted_fixed_point_to_float(png_fixed_point x) { return 1.0f / png_fixed_point_to_float(x); } +static constexpr float gSRGB_toXYZD50[] { + 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx + 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz + 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz +}; + +static bool convert_to_D50(SkMatrix44* toXYZD50, float toXYZ[9], float whitePoint[2]) { + float wX = whitePoint[0]; + float wY = whitePoint[1]; + if (wX < 0.0f || wY < 0.0f || (wX + wY > 1.0f)) { + return false; + } + + // Calculate the XYZ illuminant. Call this the src illuminant. + float wZ = 1.0f - wX - wY; + float scale = 1.0f / wY; + // TODO (msarett): + // What are common src illuminants? I'm guessing we will almost always see D65. Should + // we go ahead and save a precomputed D65->D50 Bradford matrix? Should we exit early if + // if the src illuminant is D50? + SkVector3 srcXYZ = SkVector3::Make(wX * scale, 1.0f, wZ * scale); + + // The D50 illuminant. + SkVector3 dstXYZ = SkVector3::Make(0.96422f, 1.0f, 0.82521f); + + // Calculate the chromatic adaptation matrix. We will use the Bradford method, thus + // the matrices below. The Bradford method is used by Adobe and is widely considered + // to be the best. + // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html + SkMatrix mA, mAInv; + mA.setAll(0.8951f, 0.2664f, -0.1614f, -0.7502f, 1.7135f, 0.0367f, 0.0389f, -0.0685f, 1.0296f); + mAInv.setAll(0.9869929f, -0.1470543f, 0.1599627f, 0.4323053f, 0.5183603f, 0.0492912f, + -0.0085287f, 0.0400428f, 0.9684867f); + + // Map illuminant into cone response domain. + SkVector3 srcCone; + srcCone.fX = mA[0] * srcXYZ.fX + mA[1] * srcXYZ.fY + mA[2] * srcXYZ.fZ; + srcCone.fY = mA[3] * srcXYZ.fX + mA[4] * srcXYZ.fY + mA[5] * srcXYZ.fZ; + srcCone.fZ = mA[6] * srcXYZ.fX + mA[7] * srcXYZ.fY + mA[8] * srcXYZ.fZ; + SkVector3 dstCone; + dstCone.fX = mA[0] * dstXYZ.fX + mA[1] * dstXYZ.fY + mA[2] * dstXYZ.fZ; + dstCone.fY = mA[3] * dstXYZ.fX + mA[4] * dstXYZ.fY + mA[5] * dstXYZ.fZ; + dstCone.fZ = mA[6] * dstXYZ.fX + mA[7] * dstXYZ.fY + mA[8] * dstXYZ.fZ; + + SkMatrix DXToD50; + DXToD50.setIdentity(); + DXToD50[0] = dstCone.fX / srcCone.fX; + DXToD50[4] = dstCone.fY / srcCone.fY; + DXToD50[8] = dstCone.fZ / srcCone.fZ; + DXToD50.postConcat(mAInv); + DXToD50.preConcat(mA); + + SkMatrix toXYZ3x3; + toXYZ3x3.setAll(toXYZ[0], toXYZ[3], toXYZ[6], toXYZ[1], toXYZ[4], toXYZ[7], toXYZ[2], toXYZ[5], + toXYZ[8]); + toXYZ3x3.postConcat(DXToD50); + + toXYZD50->set3x3(toXYZ3x3[0], toXYZ3x3[3], toXYZ3x3[6], + toXYZ3x3[1], toXYZ3x3[4], toXYZ3x3[7], + toXYZ3x3[2], toXYZ3x3[5], toXYZ3x3[8]); + return true; +} + +#endif // LIBPNG >= 1.6 + // Returns a colorSpace object that represents any color space information in // the encoded data. If the encoded data contains no color space, this will // return NULL. @@ -214,60 +416,435 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { } // Next, check for chromaticities. - png_fixed_point XYZ[9]; - SkFloat3x3 toXYZD50; + png_fixed_point toXYZFixed[9]; + float toXYZ[9]; + png_fixed_point whitePointFixed[2]; + float whitePoint[2]; png_fixed_point gamma; - SkFloat3 gammas; - if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], &XYZ[2], &XYZ[3], &XYZ[4], - &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) { - - // FIXME (msarett): Here we are treating XYZ values as D50 even though the color - // temperature is unspecified. I suspect that this assumption - // is most often ok, but we could also calculate the color - // temperature (D value) and then convert the XYZ to D50. Maybe - // we should add a new constructor to SkColorSpace that accepts - // XYZ with D-Unkown? + float gammas[3]; + if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1], &toXYZFixed[2], + &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], &toXYZFixed[6], + &toXYZFixed[7], &toXYZFixed[8]) && + png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFixed[1], nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr)) + { for (int i = 0; i < 9; i++) { - toXYZD50.fMat[i] = png_fixed_point_to_float(XYZ[i]); + toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]); + } + whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]); + whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]); + + SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); + if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) { + toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); } if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { - gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = - png_inverted_fixed_point_to_float(gamma); - } else { - // If the image does not specify gamma, let's choose linear. Should we default - // to sRGB? Most images are intended to be sRGB (gamma = 2.2f). - gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = 1.0f; + float value = png_inverted_fixed_point_to_float(gamma); + gammas[0] = value; + gammas[1] = value; + gammas[2] = value; + + return SkColorSpace_Base::NewRGB(gammas, toXYZD50); } - - return SkColorSpace::NewRGB(toXYZD50, gammas); + // Default to sRGB gamma if the image has color space information, + // but does not specify gamma. + return SkColorSpace::NewRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50); } // Last, check for gamma. if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { - // Guess a default value for cHRM? Or should we just give up? - // Here we use the identity matrix as a default. - // FIXME (msarett): Should SkFloat3x3 have a method to set the identity matrix? - memset(toXYZD50.fMat, 0, 9 * sizeof(float)); - toXYZD50.fMat[0] = toXYZD50.fMat[4] = toXYZD50.fMat[8] = 1.0f; - // Set the gammas. - gammas.fVec[0] = gammas.fVec[1] = gammas.fVec[2] = png_inverted_fixed_point_to_float(gamma); + float value = png_inverted_fixed_point_to_float(gamma); + gammas[0] = value; + gammas[1] = value; + gammas[2] = value; - return SkColorSpace::NewRGB(toXYZD50, gammas); + // Since there is no cHRM, we will guess sRGB gamut. + SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); + toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); + + return SkColorSpace_Base::NewRGB(gammas, toXYZD50); } #endif // LIBPNG >= 1.6 - // Finally, what should we do if there is no color space information in the PNG? - // The specification says that this indicates "gamma is unknown" and that the - // "color is device dependent". I'm assuming we can represent this with NULL. - // But should we guess sRGB? Most images are sRGB, even if they don't specify. + // Report that there is no color space information in the PNG. SkPngCodec is currently + // implemented to guess sRGB in this case. return nullptr; } +void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) { + switch (fXformMode) { + case kSwizzleOnly_XformMode: + break; + case kColorOnly_XformMode: + // Intentional fall through. A swizzler hasn't been created yet, but one will + // be created later if we are sampling. We'll go ahead and allocate + // enough memory to swizzle if necessary. + case kSwizzleColor_XformMode: { + const size_t colorXformBytes = dstInfo.width() * sizeof(uint32_t); + fStorage.reset(colorXformBytes); + fColorXformSrcRow = (uint32_t*) fStorage.get(); + break; + } + } +} + +void SkPngCodec::applyXformRow(void* dst, const void* src) { + const SkColorSpaceXform::ColorFormat srcColorFormat = SkColorSpaceXform::kRGBA_8888_ColorFormat; + switch (fXformMode) { + case kSwizzleOnly_XformMode: + fSwizzler->swizzle(dst, (const uint8_t*) src); + break; + case kColorOnly_XformMode: + fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, fXformColorFormat, + srcColorFormat, fXformAlphaType); + break; + case kSwizzleColor_XformMode: + fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src); + fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, fXformColorFormat, + srcColorFormat, fXformAlphaType); + break; + } +} + +class SkPngNormalDecoder : public SkPngCodec { +public: + SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, SkStream* stream, + SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth) + : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth) + , fLinesDecoded(0) + , fDst(nullptr) + , fRowBytes(0) + , fFirstRow(0) + , fLastRow(0) + {} + + static void AllRowsCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { + GetDecoder(png_ptr)->allRowsCallback(row, rowNum); + } + + static void RowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int /*pass*/) { + GetDecoder(png_ptr)->rowCallback(row, rowNum); + } + +#ifdef SK_GOOGLE3_PNG_HACK + static void RereadInfoCallback(png_structp png_ptr, png_infop) { + GetDecoder(png_ptr)->rereadInfoCallback(); + } +#endif + +private: + int fLinesDecoded; // FIXME: Move to baseclass? + void* fDst; + size_t fRowBytes; + + // Variables for partial decode + int fFirstRow; // FIXME: Move to baseclass? + int fLastRow; + + typedef SkPngCodec INHERITED; + + static SkPngNormalDecoder* GetDecoder(png_structp png_ptr) { + return static_cast(png_get_progressive_ptr(png_ptr)); + } + + Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { + const int height = this->getInfo().height(); + png_progressive_info_ptr callback = nullptr; +#ifdef SK_GOOGLE3_PNG_HACK + callback = RereadInfoCallback; +#endif + png_set_progressive_read_fn(this->png_ptr(), this, callback, AllRowsCallback, nullptr); + fDst = dst; + fRowBytes = rowBytes; + + fLinesDecoded = 0; + + this->processData(); + + if (fLinesDecoded == height) { + return SkCodec::kSuccess; + } + + if (rowsDecoded) { + *rowsDecoded = fLinesDecoded; + } + + return SkCodec::kIncompleteInput; + } + + void allRowsCallback(png_bytep row, int rowNum) { + SkASSERT(rowNum - fFirstRow == fLinesDecoded); + fLinesDecoded++; + this->applyXformRow(fDst, row); + fDst = SkTAddOffset(fDst, fRowBytes); + } + + void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override { + png_progressive_info_ptr callback = nullptr; +#ifdef SK_GOOGLE3_PNG_HACK + callback = RereadInfoCallback; +#endif + png_set_progressive_read_fn(this->png_ptr(), this, callback, RowCallback, nullptr); + fFirstRow = firstRow; + fLastRow = lastRow; + fDst = dst; + fRowBytes = rowBytes; + fLinesDecoded = 0; + } + + SkCodec::Result decode(int* rowsDecoded) override { + this->processData(); + + if (fLinesDecoded == fLastRow - fFirstRow + 1) { + return SkCodec::kSuccess; + } + + if (rowsDecoded) { + *rowsDecoded = fLinesDecoded; + } + + return SkCodec::kIncompleteInput; + } + + void rowCallback(png_bytep row, int rowNum) { + if (rowNum < fFirstRow) { + // Ignore this row. + return; + } + + SkASSERT(rowNum <= fLastRow); + + // If there is no swizzler, all rows are needed. + if (!this->swizzler() || this->swizzler()->rowNeeded(fLinesDecoded)) { + this->applyXformRow(fDst, row); + fDst = SkTAddOffset(fDst, fRowBytes); + } + + fLinesDecoded++; + + if (rowNum == fLastRow) { + // Fake error to stop decoding scanlines. + longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); + } + } +}; + +class SkPngInterlacedDecoder : public SkPngCodec { +public: + SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo, + SkStream* stream, SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, + int bitDepth, int numberPasses) + : INHERITED(info, imageInfo, stream, reader, png_ptr, info_ptr, bitDepth) + , fNumberPasses(numberPasses) + , fFirstRow(0) + , fLastRow(0) + , fLinesDecoded(0) + , fInterlacedComplete(false) + , fPng_rowbytes(0) + {} + + static void InterlacedRowCallback(png_structp png_ptr, png_bytep row, png_uint_32 rowNum, int pass) { + auto decoder = static_cast(png_get_progressive_ptr(png_ptr)); + decoder->interlacedRowCallback(row, rowNum, pass); + } + +#ifdef SK_GOOGLE3_PNG_HACK + static void RereadInfoInterlacedCallback(png_structp png_ptr, png_infop) { + static_cast(png_get_progressive_ptr(png_ptr))->rereadInfoInterlaced(); + } +#endif + +private: + const int fNumberPasses; + int fFirstRow; + int fLastRow; + void* fDst; + size_t fRowBytes; + int fLinesDecoded; + bool fInterlacedComplete; + size_t fPng_rowbytes; + SkAutoTMalloc fInterlaceBuffer; + + typedef SkPngCodec INHERITED; + +#ifdef SK_GOOGLE3_PNG_HACK + void rereadInfoInterlaced() { + this->rereadInfoCallback(); + // Note: This allocates more memory than necessary, if we are sampling/subset. + this->setUpInterlaceBuffer(this->getInfo().height()); + } +#endif + + // FIXME: Currently sharing interlaced callback for all rows and subset. It's not + // as expensive as the subset version of non-interlaced, but it still does extra + // work. + void interlacedRowCallback(png_bytep row, int rowNum, int pass) { + if (rowNum < fFirstRow || rowNum > fLastRow) { + // Ignore this row + return; + } + + png_bytep oldRow = fInterlaceBuffer.get() + (rowNum - fFirstRow) * fPng_rowbytes; + png_progressive_combine_row(this->png_ptr(), oldRow, row); + + if (0 == pass) { + // The first pass initializes all rows. + SkASSERT(row); + SkASSERT(fLinesDecoded == rowNum - fFirstRow); + fLinesDecoded++; + } else { + SkASSERT(fLinesDecoded == fLastRow - fFirstRow + 1); + if (fNumberPasses - 1 == pass && rowNum == fLastRow) { + // Last pass, and we have read all of the rows we care about. Note that + // we do not care about reading anything beyond the end of the image (or + // beyond the last scanline requested). + fInterlacedComplete = true; + // Fake error to stop decoding scanlines. + longjmp(PNG_JMPBUF(this->png_ptr()), kStopDecoding); + } + } + } + + SkCodec::Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) override { + const int height = this->getInfo().height(); + this->setUpInterlaceBuffer(height); + png_progressive_info_ptr callback = nullptr; +#ifdef SK_GOOGLE3_PNG_HACK + callback = RereadInfoInterlacedCallback; +#endif + png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback, + nullptr); + + fFirstRow = 0; + fLastRow = height - 1; + fLinesDecoded = 0; + + this->processData(); + + png_bytep srcRow = fInterlaceBuffer.get(); + // FIXME: When resuming, this may rewrite rows that did not change. + for (int rowNum = 0; rowNum < fLinesDecoded; rowNum++) { + this->applyXformRow(dst, srcRow); + dst = SkTAddOffset(dst, rowBytes); + srcRow = SkTAddOffset(srcRow, fPng_rowbytes); + } + if (fInterlacedComplete) { + return SkCodec::kSuccess; + } + + if (rowsDecoded) { + *rowsDecoded = fLinesDecoded; + } + + return SkCodec::kIncompleteInput; + } + + void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) override { + // FIXME: We could skip rows in the interlace buffer that we won't put in the output. + this->setUpInterlaceBuffer(lastRow - firstRow + 1); + png_progressive_info_ptr callback = nullptr; +#ifdef SK_GOOGLE3_PNG_HACK + callback = RereadInfoInterlacedCallback; +#endif + png_set_progressive_read_fn(this->png_ptr(), this, callback, InterlacedRowCallback, nullptr); + fFirstRow = firstRow; + fLastRow = lastRow; + fDst = dst; + fRowBytes = rowBytes; + fLinesDecoded = 0; + } + + SkCodec::Result decode(int* rowsDecoded) override { + this->processData(); + + // Now apply Xforms on all the rows that were decoded. + if (!fLinesDecoded) { + return SkCodec::kIncompleteInput; + } + const int lastRow = fLinesDecoded + fFirstRow - 1; + SkASSERT(lastRow <= fLastRow); + + // FIXME: For resuming interlace, we may swizzle a row that hasn't changed. But it + // may be too tricky/expensive to handle that correctly. + png_bytep srcRow = fInterlaceBuffer.get(); + const int sampleY = this->swizzler() ? this->swizzler()->sampleY() : 1; + void* dst = fDst; + for (int rowNum = fFirstRow; rowNum <= lastRow; rowNum += sampleY) { + this->applyXformRow(dst, srcRow); + dst = SkTAddOffset(dst, fRowBytes); + srcRow = SkTAddOffset(srcRow, fPng_rowbytes * sampleY); + } + + if (fInterlacedComplete) { + return SkCodec::kSuccess; + } + + if (rowsDecoded) { + *rowsDecoded = fLinesDecoded; + } + return SkCodec::kIncompleteInput; + } + + void setUpInterlaceBuffer(int height) { + fPng_rowbytes = png_get_rowbytes(this->png_ptr(), this->info_ptr()); + fInterlaceBuffer.reset(fPng_rowbytes * height); + fInterlacedComplete = false; + } +}; + +#ifdef SK_GOOGLE3_PNG_HACK +bool SkPngCodec::rereadHeaderIfNecessary() { + if (!fNeedsToRereadHeader) { + return true; + } + + // On the first call, we'll need to rewind ourselves. Future calls will + // have already rewound in rewindIfNecessary. + if (this->stream()->getPosition() > 0) { + this->stream()->rewind(); + } + + this->destroyReadStruct(); + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, + sk_error_fn, sk_warning_fn); + if (!png_ptr) { + return false; + } + + // Only use the AutoCleanPng to delete png_ptr as necessary. + // (i.e. not for reading bounds etc.) + AutoCleanPng autoClean(png_ptr, nullptr, nullptr, nullptr); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == nullptr) { + return false; + } + + autoClean.setInfoPtr(info_ptr); + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. + // This needs to be installed before we read the png header. Android may store ninepatch + // chunks in the header. + if (fPngChunkReader.get()) { + png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); + png_set_read_user_chunk_fn(png_ptr, (png_voidp) fPngChunkReader.get(), sk_read_user_chunk); + } +#endif + + fPng_ptr = png_ptr; + fInfo_ptr = info_ptr; + autoClean.releasePngPtrs(); + fNeedsToRereadHeader = false; + return true; +} +#endif // SK_GOOGLE3_PNG_HACK + // Reads the header and initializes the output fields, if not NULL. // // @param stream Input data. Will be read to get enough information to properly @@ -275,22 +852,17 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is // expected to continue to own it for the lifetime of the png_ptr. +// @param outCodec Optional output variable. If non-NULL, will be set to a new +// SkPngCodec on success. // @param png_ptrp Optional output variable. If non-NULL, will be set to a new // png_structp on success. // @param info_ptrp Optional output variable. If non-NULL, will be set to a new // png_infop on success; -// @param imageInfo Optional output variable. If non-NULL, will be set to -// reflect the properties of the encoded image on success. -// @param bitDepthPtr Optional output variable. If non-NULL, will be set to the -// bit depth of the encoded image on success. -// @param numberPassesPtr Optional output variable. If non-NULL, will be set to -// the number_passes of the encoded image on success. // @return true on success, in which case the caller is responsible for calling // png_destroy_read_struct(png_ptrp, info_ptrp). // If it returns false, the passed in fields (except stream) are unchanged. -static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, - png_structp* png_ptrp, png_infop* info_ptrp, - SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) { +static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec, + png_structp* png_ptrp, png_infop* info_ptrp) { // The image is known to be a PNG. Decode enough to know the SkImageInfo. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_fn, sk_warning_fn); @@ -298,7 +870,7 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, return false; } - AutoCleanPng autoClean(png_ptr); + AutoCleanPng autoClean(png_ptr, stream, chunkReader, outCodec); png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == nullptr) { @@ -309,12 +881,10 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, // FIXME: Could we use the return value of setjmp to specify the type of // error? - if (setjmp(png_jmpbuf(png_ptr))) { + if (setjmp(PNG_JMPBUF(png_ptr))) { return false; } - png_set_read_fn(png_ptr, static_cast(stream), sk_read_fn); - #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. // This needs to be installed before we read the png header. Android may store ninepatch @@ -325,18 +895,36 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, } #endif - // The call to png_read_info() gives us all of the information from the - // PNG file before the first IDAT (image data chunk). - png_read_info(png_ptr, info_ptr); + const bool decodedBounds = autoClean.decodeBounds(); + + if (!decodedBounds) { + return false; + } + + // On success, decodeBounds releases ownership of png_ptr and info_ptr. + if (png_ptrp) { + *png_ptrp = png_ptr; + } + if (info_ptrp) { + *info_ptrp = info_ptr; + } + + // decodeBounds takes care of setting outCodec + if (outCodec) { + SkASSERT(*outCodec); + } + return true; +} + +// FIXME (scroggo): Once SK_GOOGLE3_PNG_HACK is no more, this method can be inline in +// AutoCleanPng::infoCallback +static void general_info_callback(png_structp png_ptr, png_infop info_ptr, + SkEncodedInfo::Color* outColor, SkEncodedInfo::Alpha* outAlpha) { png_uint_32 origWidth, origHeight; int bitDepth, encodedColorType; png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, &encodedColorType, nullptr, nullptr, nullptr); - if (bitDepthPtr) { - *bitDepthPtr = bitDepth; - } - // Tell libpng to strip 16 bit/color files down to 8 bits/color. // TODO: Should we handle this in SkSwizzler? Could this also benefit // RAW decodes? @@ -348,8 +936,8 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, // Now determine the default colorType and alphaType and set the required transforms. // Often, we depend on SkSwizzler to perform any transforms that we need. However, we // still depend on libpng for many of the rare and PNG-specific cases. - SkColorType colorType = kUnknown_SkColorType; - SkAlphaType alphaType = kUnknown_SkAlphaType; + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; switch (encodedColorType) { case PNG_COLOR_TYPE_PALETTE: // Extract multiple pixels with bit depths of 1, 2, and 4 from a single @@ -359,20 +947,21 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, png_set_packing(png_ptr); } - colorType = kIndex_8_SkColorType; - // Set the alpha type depending on if a transparency chunk exists. - alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? - kUnpremul_SkAlphaType : kOpaque_SkAlphaType; + color = SkEncodedInfo::kPalette_Color; + // Set the alpha depending on if a transparency chunk exists. + alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? + SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha; break; case PNG_COLOR_TYPE_RGB: if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // Convert to RGBA if transparency chunk exists. png_set_tRNS_to_alpha(png_ptr); - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kBinary_Alpha; } else { - alphaType = kOpaque_SkAlphaType; + color = SkEncodedInfo::kRGB_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; } - colorType = kN32_SkColorType; break; case PNG_COLOR_TYPE_GRAY: // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. @@ -383,65 +972,113 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); - - // We will recommend kN32 here since we do not support kGray - // with alpha. - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kGrayAlpha_Color; + alpha = SkEncodedInfo::kBinary_Alpha; } else { - colorType = kGray_8_SkColorType; - alphaType = kOpaque_SkAlphaType; + color = SkEncodedInfo::kGray_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: - // We will recommend kN32 here since we do not support anything - // similar to GRAY_ALPHA. - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kGrayAlpha_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; break; case PNG_COLOR_TYPE_RGBA: - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; break; default: // All the color types have been covered above. SkASSERT(false); + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; } - - int numberPasses = png_set_interlace_handling(png_ptr); - if (numberPassesPtr) { - *numberPassesPtr = numberPasses; + if (outColor) { + *outColor = color; } - - SkColorProfileType profileType = kLinear_SkColorProfileType; - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { - profileType = kSRGB_SkColorProfileType; + if (outAlpha) { + *outAlpha = alpha; } - - if (imageInfo) { - *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaType, profileType); - } - autoClean.release(); - if (png_ptrp) { - *png_ptrp = png_ptr; - } - if (info_ptrp) { - *info_ptrp = info_ptr; - } - - return true; } -SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader, - png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses, - sk_sp colorSpace) - : INHERITED(info, stream, colorSpace) +#ifdef SK_GOOGLE3_PNG_HACK +void SkPngCodec::rereadInfoCallback() { + general_info_callback(fPng_ptr, fInfo_ptr, nullptr, nullptr); + png_set_interlace_handling(fPng_ptr); + png_read_update_info(fPng_ptr, fInfo_ptr); +} +#endif + +void AutoCleanPng::infoCallback() { + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; + general_info_callback(fPng_ptr, fInfo_ptr, &color, &alpha); + + const int numberPasses = png_set_interlace_handling(fPng_ptr); + + fReadHeader = true; + fDecodedBounds = true; +#ifndef SK_GOOGLE3_PNG_HACK + // 1 tells libpng to save any extra data. We may be able to be more efficient by saving + // it ourselves. + png_process_data_pause(fPng_ptr, 1); +#else + // Hack to make png_process_data stop. + fPng_ptr->buffer_size = 0; +#endif + if (fOutCodec) { + SkASSERT(nullptr == *fOutCodec); + sk_sp colorSpace = read_color_space(fPng_ptr, fInfo_ptr); + if (!colorSpace) { + // Treat unmarked pngs as sRGB. + colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + } + + SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, 8); + // FIXME (scroggo): Once we get rid of SK_GOOGLE3_PNG_HACK, general_info_callback can + // be inlined, so these values will already be set. + png_uint_32 origWidth = png_get_image_width(fPng_ptr, fInfo_ptr); + png_uint_32 origHeight = png_get_image_height(fPng_ptr, fInfo_ptr); + png_byte bitDepth = png_get_bit_depth(fPng_ptr, fInfo_ptr); + SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace); + + if (SkEncodedInfo::kOpaque_Alpha == alpha) { + png_color_8p sigBits; + if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) { + if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) { + // Recommend a decode to 565 if the sBIT indicates 565. + imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType); + } + } + } + + if (1 == numberPasses) { + *fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo, fStream, + fChunkReader, fPng_ptr, fInfo_ptr, bitDepth); + } else { + *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo, fStream, + fChunkReader, fPng_ptr, fInfo_ptr, bitDepth, numberPasses); + } + } + + + // Release the pointers, which are now owned by the codec or the caller is expected to + // take ownership. + this->releasePngPtrs(); +} + +SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo, + SkStream* stream, SkPngChunkReader* chunkReader, void* png_ptr, + void* info_ptr, int bitDepth) + : INHERITED(encodedInfo, imageInfo, stream) , fPngChunkReader(SkSafeRef(chunkReader)) , fPng_ptr(png_ptr) , fInfo_ptr(info_ptr) - , fSrcConfig(SkSwizzler::kUnknown) - , fNumberPasses(numberPasses) + , fColorXformSrcRow(nullptr) , fBitDepth(bitDepth) +#ifdef SK_GOOGLE3_PNG_HACK + , fNeedsToRereadHeader(true) +#endif {} SkPngCodec::~SkPngCodec() { @@ -452,7 +1089,7 @@ void SkPngCodec::destroyReadStruct() { if (fPng_ptr) { // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr SkASSERT(fInfo_ptr); - png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr); + png_destroy_read_struct((png_struct**)&fPng_ptr, (png_info**)&fInfo_ptr, nullptr); fPng_ptr = nullptr; fInfo_ptr = nullptr; } @@ -462,72 +1099,109 @@ void SkPngCodec::destroyReadStruct() { // Getting the pixels /////////////////////////////////////////////////////////////////////////////// -SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, - const Options& options, - SkPMColor ctable[], - int* ctableCount) { - // FIXME: Could we use the return value of setjmp to specify the type of - // error? - if (setjmp(png_jmpbuf(fPng_ptr))) { - SkCodecPrintf("setjmp long jump!\n"); - return kInvalidInput; +bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options, + SkPMColor ctable[], int* ctableCount) { + if (setjmp(PNG_JMPBUF((png_struct*)fPng_ptr))) { + SkCodecPrintf("Failed on png_read_update_info.\n"); + return false; } png_read_update_info(fPng_ptr, fInfo_ptr); - // suggestedColorType was determined in read_header() based on the encodedColorType - const SkColorType suggestedColorType = this->getInfo().colorType(); + // Reset fSwizzler and fColorXform. We can't do this in onRewind() because the + // interlaced scanline decoder may need to rewind. + fSwizzler.reset(nullptr); + fColorXform = nullptr; - switch (suggestedColorType) { - case kIndex_8_SkColorType: - //decode palette to Skia format - fSrcConfig = SkSwizzler::kIndex; - if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(), - ctableCount)) { - return kInvalidInput; - } - break; - case kGray_8_SkColorType: - fSrcConfig = SkSwizzler::kGray; - break; - case kN32_SkColorType: { - const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_ptr); - if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || - PNG_COLOR_TYPE_GRAY == encodedColorType) { - // If encodedColorType is GRAY, there must be a transparent chunk. - // Otherwise, suggestedColorType would be kGray. We have already - // instructed libpng to convert the transparent chunk to alpha, - // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. - SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || - png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); - - fSrcConfig = SkSwizzler::kGrayAlpha; - } else { - if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { - fSrcConfig = SkSwizzler::kRGB; - } else { - fSrcConfig = SkSwizzler::kRGBA; - } - } - break; - } - default: - // We will always recommend one of the above colorTypes. - SkASSERT(false); + if (needs_color_xform(dstInfo, this->getInfo())) { + fColorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); + SkASSERT(fColorXform); } - // Copy the color table to the client if they request kIndex8 mode - copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); + // If the image is RGBA and we have a color xform, we can skip the swizzler. + // FIXME (msarett): + // Support more input types to fColorXform (ex: RGB, Gray) and skip the swizzler more often. + if (fColorXform && SkEncodedInfo::kRGBA_Color == this->getEncodedInfo().color() && + !options.fSubset) + { + fXformMode = kColorOnly_XformMode; + return true; + } - // Create the swizzler. SkPngCodec retains ownership of the color table. - const SkPMColor* colors = get_color_ptr(fColorTable.get()); - fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options)); - SkASSERT(fSwizzler); + if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { + if (!this->createColorTable(dstInfo, ctableCount)) { + return false; + } + } - return kSuccess; + // Copy the color table to the client if they request kIndex8 mode. + copy_color_table(dstInfo, fColorTable, ctable, ctableCount); + + this->initializeSwizzler(dstInfo, options); + return true; } +void SkPngCodec::initializeXformParams() { + switch (fXformMode) { + case kColorOnly_XformMode: + fXformColorFormat = select_xform_format(this->dstInfo().colorType()); + fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(), + this->getInfo().alphaType()); + fXformWidth = this->dstInfo().width(); + break; + case kSwizzleColor_XformMode: + fXformColorFormat = select_xform_format(this->dstInfo().colorType()); + fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(), + this->getInfo().alphaType()); + fXformWidth = this->swizzler()->swizzleWidth(); + break; + default: + break; + } +} + +static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) { + // We will apply the color xform when reading the color table, unless F16 is requested. + return SkEncodedInfo::kPalette_Color != srcColor || kRGBA_F16_SkColorType == dstColorType; +} + +void SkPngCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) { + SkImageInfo swizzlerInfo = dstInfo; + Options swizzlerOptions = options; + fXformMode = kSwizzleOnly_XformMode; + if (fColorXform && apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color())) { + swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType); + if (kPremul_SkAlphaType == dstInfo.alphaType()) { + swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType); + } + + fXformMode = kSwizzleColor_XformMode; + + // Here, we swizzle into temporary memory, which is not zero initialized. + // FIXME (msarett): + // Is this a problem? + swizzlerOptions.fZeroInitialized = kNo_ZeroInitialized; + } + + const SkPMColor* colors = get_color_ptr(fColorTable.get()); + fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo, + swizzlerOptions)); + SkASSERT(fSwizzler); +} + +SkSampler* SkPngCodec::getSampler(bool createIfNecessary) { + if (fSwizzler || !createIfNecessary) { + return fSwizzler; + } + + this->initializeSwizzler(this->dstInfo(), this->options()); + return fSwizzler; +} bool SkPngCodec::onRewind() { +#ifdef SK_GOOGLE3_PNG_HACK + fNeedsToRereadHeader = true; + return true; +#else // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header // succeeds, they will be repopulated, and if it fails, they will // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will @@ -537,322 +1211,99 @@ bool SkPngCodec::onRewind() { png_structp png_ptr; png_infop info_ptr; - if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, - nullptr, nullptr, nullptr)) { + if (!read_header(this->stream(), fPngChunkReader.get(), nullptr, &png_ptr, &info_ptr)) { return false; } fPng_ptr = png_ptr; fInfo_ptr = info_ptr; return true; +#endif } -SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, - size_t dstRowBytes, const Options& options, +SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, + size_t rowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { - if (!conversion_possible(requestedInfo, this->getInfo())) { + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeXforms(dstInfo, options, ctable, ctableCount)) + { return kInvalidConversion; } +#ifdef SK_GOOGLE3_PNG_HACK + // Note that this is done after initializeXforms. Otherwise that method + // would not have png_ptr to use. + if (!this->rereadHeaderIfNecessary()) { + return kCouldNotRewind; + } +#endif + if (options.fSubset) { - // Subsets are not supported. return kUnimplemented; } - // Note that ctable and ctableCount may be modified if there is a color table - const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount); - if (result != kSuccess) { - return result; + this->allocateStorage(dstInfo); + this->initializeXformParams(); + return this->decodeAllRows(dst, rowBytes, rowsDecoded); +} + +SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, + void* dst, size_t rowBytes, const SkCodec::Options& options, + SkPMColor* ctable, int* ctableCount) { + if (!conversion_possible(dstInfo, this->getInfo()) || + !this->initializeXforms(dstInfo, options, ctable, ctableCount)) + { + return kInvalidConversion; } - - const int width = requestedInfo.width(); - const int height = requestedInfo.height(); - const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); - const size_t srcRowBytes = width * bpp; - - // FIXME: Could we use the return value of setjmp to specify the type of - // error? - int row = 0; - // This must be declared above the call to setjmp to avoid memory leaks on incomplete images. - SkAutoTMalloc storage; - if (setjmp(png_jmpbuf(fPng_ptr))) { - // Assume that any error that occurs while reading rows is caused by an incomplete input. - if (fNumberPasses > 1) { - // FIXME (msarett): Handle incomplete interlaced pngs. - return (row == height) ? kSuccess : kInvalidInput; - } - // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, - // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 - // bytes), and if we can't fill the buffer, we immediately fail. - // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains - // half that, which may have been enough to contain a non-zero number of lines, we fail - // when we could have decoded a few more lines and then failed. - // The read function that we provide for libpng has no way of indicating that we have - // made a partial read. - // Making our buffer size smaller improves our incomplete decodes, but what impact does - // it have on regular decode performance? Should we investigate using a different API - // instead of png_read_row? Chromium uses png_process_data. - *rowsDecoded = row; - return (row == height) ? kSuccess : kIncompleteInput; +#ifdef SK_GOOGLE3_PNG_HACK + // See note in onGetPixels. + if (!this->rereadHeaderIfNecessary()) { + return kCouldNotRewind; } +#endif - // FIXME: We could split these out based on subclass. - void* dstRow = dst; - if (fNumberPasses > 1) { - storage.reset(height * srcRowBytes); - uint8_t* const base = storage.get(); + this->allocateStorage(dstInfo); - for (int i = 0; i < fNumberPasses; i++) { - uint8_t* srcRow = base; - for (int y = 0; y < height; y++) { - png_read_row(fPng_ptr, srcRow, nullptr); - srcRow += srcRowBytes; - } - } - - // Now swizzle it. - uint8_t* srcRow = base; - for (; row < height; row++) { - fSwizzler->swizzle(dstRow, srcRow); - dstRow = SkTAddOffset(dstRow, dstRowBytes); - srcRow += srcRowBytes; - } + int firstRow, lastRow; + if (options.fSubset) { + firstRow = options.fSubset->top(); + lastRow = options.fSubset->bottom() - 1; } else { - storage.reset(srcRowBytes); - uint8_t* srcRow = storage.get(); - for (; row < height; row++) { - png_read_row(fPng_ptr, srcRow, nullptr); - fSwizzler->swizzle(dstRow, srcRow); - dstRow = SkTAddOffset(dstRow, dstRowBytes); - } + firstRow = 0; + lastRow = dstInfo.height() - 1; } - - // read rest of file, and get additional comment and time chunks in info_ptr - png_read_end(fPng_ptr, fInfo_ptr); - + this->setRange(firstRow, lastRow, dst, rowBytes); return kSuccess; } -uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { - const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); - if (colorPtr) { - return get_color_table_fill_value(colorType, colorPtr, 0); - } - return INHERITED::onGetFillValue(colorType); +SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) { + // FIXME: Only necessary on the first call. + this->initializeXformParams(); + + return this->decode(rowsDecoded); } -// Subclass of SkPngCodec which supports scanline decoding -class SkPngScanlineDecoder : public SkPngCodec { -public: - SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, - SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth, - sk_sp colorSpace) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1, colorSpace) - , fSrcRow(nullptr) - {} - - Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, - SkPMColor ctable[], int* ctableCount) override { - if (!conversion_possible(dstInfo, this->getInfo())) { - return kInvalidConversion; - } - - const Result result = this->initializeSwizzler(dstInfo, options, ctable, - ctableCount); - if (result != kSuccess) { - return result; - } - - fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig())); - fSrcRow = fStorage.get(); - - return kSuccess; +uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const { + const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); + if (colorPtr) { + SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0, + fColorXform.get()); } - - int onGetScanlines(void* dst, int count, size_t rowBytes) override { - // Assume that an error in libpng indicates an incomplete input. - int row = 0; - if (setjmp(png_jmpbuf(this->png_ptr()))) { - SkCodecPrintf("setjmp long jump!\n"); - return row; - } - - void* dstRow = dst; - for (; row < count; row++) { - png_read_row(this->png_ptr(), fSrcRow, nullptr); - this->swizzler()->swizzle(dstRow, fSrcRow); - dstRow = SkTAddOffset(dstRow, rowBytes); - } - - return row; - } - - bool onSkipScanlines(int count) override { - // Assume that an error in libpng indicates an incomplete input. - if (setjmp(png_jmpbuf(this->png_ptr()))) { - SkCodecPrintf("setjmp long jump!\n"); - return false; - } - - for (int row = 0; row < count; row++) { - png_read_row(this->png_ptr(), fSrcRow, nullptr); - } - return true; - } - -private: - SkAutoTMalloc fStorage; - uint8_t* fSrcRow; - - typedef SkPngCodec INHERITED; -}; - - -class SkPngInterlacedScanlineDecoder : public SkPngCodec { -public: - SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, - SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, - int bitDepth, int numberPasses, sk_sp colorSpace) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, - colorSpace) - , fHeight(-1) - , fCanSkipRewind(false) - { - SkASSERT(numberPasses != 1); - } - - Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, - SkPMColor ctable[], int* ctableCount) override { - if (!conversion_possible(dstInfo, this->getInfo())) { - return kInvalidConversion; - } - - const Result result = this->initializeSwizzler(dstInfo, options, ctable, - ctableCount); - if (result != kSuccess) { - return result; - } - - fHeight = dstInfo.height(); - // FIXME: This need not be called on a second call to onStartScanlineDecode. - fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()); - fGarbageRow.reset(fSrcRowBytes); - fGarbageRowPtr = static_cast(fGarbageRow.get()); - fCanSkipRewind = true; - - return SkCodec::kSuccess; - } - - int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { - // rewind stream if have previously called onGetScanlines, - // since we need entire progressive image to get scanlines - if (fCanSkipRewind) { - // We already rewound in onStartScanlineDecode, so there is no reason to rewind. - // Next time onGetScanlines is called, we will need to rewind. - fCanSkipRewind = false; - } else { - // rewindIfNeeded resets fCurrScanline, since it assumes that start - // needs to be called again before scanline decoding. PNG scanline - // decoding is the exception, since it needs to rewind between - // calls to getScanlines. Keep track of fCurrScanline, to undo the - // reset. - const int currScanline = this->nextScanline(); - // This method would never be called if currScanline is -1 - SkASSERT(currScanline != -1); - - if (!this->rewindIfNeeded()) { - return kCouldNotRewind; - } - this->updateCurrScanline(currScanline); - } - - if (setjmp(png_jmpbuf(this->png_ptr()))) { - SkCodecPrintf("setjmp long jump!\n"); - // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, - // we may be able to report that all of the memory has been initialized. Even if we - // fail on the first pass, we can still report than some scanlines are initialized. - return 0; - } - SkAutoTMalloc storage(count * fSrcRowBytes); - uint8_t* storagePtr = storage.get(); - uint8_t* srcRow; - const int startRow = this->nextScanline(); - for (int i = 0; i < this->numberPasses(); i++) { - // read rows we planned to skip into garbage row - for (int y = 0; y < startRow; y++){ - png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); - } - // read rows we care about into buffer - srcRow = storagePtr; - for (int y = 0; y < count; y++) { - png_read_row(this->png_ptr(), srcRow, nullptr); - srcRow += fSrcRowBytes; - } - // read rows we don't want into garbage buffer - for (int y = 0; y < fHeight - startRow - count; y++) { - png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); - } - } - //swizzle the rows we care about - srcRow = storagePtr; - void* dstRow = dst; - for (int y = 0; y < count; y++) { - this->swizzler()->swizzle(dstRow, srcRow); - dstRow = SkTAddOffset(dstRow, dstRowBytes); - srcRow += fSrcRowBytes; - } - - return count; - } - - bool onSkipScanlines(int count) override { - // The non-virtual version will update fCurrScanline. - return true; - } - - SkScanlineOrder onGetScanlineOrder() const override { - return kNone_SkScanlineOrder; - } - -private: - int fHeight; - size_t fSrcRowBytes; - SkAutoMalloc fGarbageRow; - uint8_t* fGarbageRowPtr; - // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function - // is called whenever some action is taken that reads the stream and - // therefore the next call will require a rewind. So it modifies a boolean - // to note that the *next* time it is called a rewind is needed. - // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling - // onStartScanlineDecode followed by onGetScanlines does *not* require a - // rewind. Since rewindIfNeeded does not have this flexibility, we need to - // add another layer. - bool fCanSkipRewind; - - typedef SkPngCodec INHERITED; -}; + return INHERITED::onGetFillValue(dstInfo); +} SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { SkAutoTDelete streamDeleter(stream); - png_structp png_ptr; - png_infop info_ptr; - SkImageInfo imageInfo; - int bitDepth; - int numberPasses; - if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth, - &numberPasses)) { - return nullptr; + SkCodec* outCodec = nullptr; + if (read_header(streamDeleter.get(), chunkReader, &outCodec, nullptr, nullptr)) { + // Codec has taken ownership of the stream. + SkASSERT(outCodec); + streamDeleter.release(); + return outCodec; } - auto colorSpace = read_color_space(png_ptr, info_ptr); - - if (1 == numberPasses) { - return new SkPngScanlineDecoder(imageInfo, streamDeleter.release(), chunkReader, - png_ptr, info_ptr, bitDepth, colorSpace); - } - - return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release(), chunkReader, - png_ptr, info_ptr, bitDepth, numberPasses, - colorSpace); + return nullptr; } diff --git a/gfx/skia/skia/src/codec/SkPngCodec.h b/gfx/skia/skia/src/codec/SkPngCodec.h index 5673e5b4fac7..1fc451757eef 100644 --- a/gfx/skia/skia/src/codec/SkPngCodec.h +++ b/gfx/skia/skia/src/codec/SkPngCodec.h @@ -6,6 +6,7 @@ */ #include "SkCodec.h" +#include "SkColorSpaceXform.h" #include "SkColorTable.h" #include "SkPngChunkReader.h" #include "SkEncodedFormat.h" @@ -13,7 +14,12 @@ #include "SkRefCnt.h" #include "SkSwizzler.h" -#include "png.h" +// FIXME (scroggo): GOOGLE3 is currently using an outdated version of libpng, +// so we need to work around the lack of the method png_process_data_pause. +// This code will be unnecessary once we update GOOGLE3. It would make more +// sense to condition this on the version of libpng being used, but we do not +// know that here because png.h is only included by the cpp file. +#define SK_GOOGLE3_PNG_HACK class SkStream; @@ -27,43 +33,109 @@ public: virtual ~SkPngCodec(); protected: + // We hold the png_ptr and info_ptr as voidp to avoid having to include png.h + // or forward declare their types here. voidp auto-casts to the real pointer types. + struct voidp { + voidp(void* ptr) : fPtr(ptr) {} + + template + operator T*() const { return (T*)fPtr; } + + explicit operator bool() const { return fPtr != nullptr; } + + void* fPtr; + }; + + SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, SkStream*, SkPngChunkReader*, + void* png_ptr, void* info_ptr, int bitDepth); + Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*, int*) override; SkEncodedFormat onGetEncodedFormat() const override { return kPNG_SkEncodedFormat; } bool onRewind() override; - uint32_t onGetFillValue(SkColorType) const override; + uint64_t onGetFillValue(const SkImageInfo&) const override; - // Helper to set up swizzler and color table. Also calls png_read_update_info. - Result initializeSwizzler(const SkImageInfo& requestedInfo, const Options&, - SkPMColor*, int* ctableCount); - SkSampler* getSampler(bool createIfNecessary) override { - SkASSERT(fSwizzler); - return fSwizzler; - } + SkSampler* getSampler(bool createIfNecessary) override; + void applyXformRow(void* dst, const void* src); - SkPngCodec(const SkImageInfo&, SkStream*, SkPngChunkReader*, png_structp, png_infop, int, int, - sk_sp); + voidp png_ptr() { return fPng_ptr; } + voidp info_ptr() { return fInfo_ptr; } - png_structp png_ptr() { return fPng_ptr; } SkSwizzler* swizzler() { return fSwizzler; } - SkSwizzler::SrcConfig srcConfig() const { return fSrcConfig; } - int numberPasses() const { return fNumberPasses; } -private: - SkAutoTUnref fPngChunkReader; - png_structp fPng_ptr; - png_infop fInfo_ptr; + // Initialize variables used by applyXformRow. + void initializeXformParams(); + + /** + * Pass available input to libpng to process it. + * + * libpng will call any relevant callbacks installed. This will continue decoding + * until it reaches the end of the file, or until a callback tells libpng to stop. + */ + void processData(); + +#ifdef SK_GOOGLE3_PNG_HACK + // In libpng 1.2.56, png_process_data_pause does not exist, so when we wanted to + // read the header, we may have read too far. In that case, we need to delete the + // png_ptr and info_ptr and recreate them. This method does that (and attaches the + // chunk reader. + bool rereadHeaderIfNecessary(); + + // This method sets up the new png_ptr/info_ptr (created in rereadHeaderIfNecessary) + // the way we set up the old one the first time in AutoCleanPng.decodeBounds's callback. + void rereadInfoCallback(); +#endif + + Result onStartIncrementalDecode(const SkImageInfo& dstInfo, void* pixels, size_t rowBytes, + const SkCodec::Options&, + SkPMColor* ctable, int* ctableCount) override; + Result onIncrementalDecode(int*) override; + + SkAutoTUnref fPngChunkReader; + voidp fPng_ptr; + voidp fInfo_ptr; // These are stored here so they can be used both by normal decoding and scanline decoding. - SkAutoTUnref fColorTable; // May be unpremul. - SkAutoTDelete fSwizzler; + SkAutoTUnref fColorTable; // May be unpremul. + SkAutoTDelete fSwizzler; + std::unique_ptr fColorXform; + SkAutoTMalloc fStorage; + uint32_t* fColorXformSrcRow; + const int fBitDepth; - SkSwizzler::SrcConfig fSrcConfig; - const int fNumberPasses; - int fBitDepth; +private: - bool decodePalette(bool premultiply, int* ctableCount); + enum XformMode { + // Requires only a swizzle pass. + kSwizzleOnly_XformMode, + + // Requires only a color xform pass. + kColorOnly_XformMode, + + // Requires a swizzle and a color xform. + kSwizzleColor_XformMode, + }; + + bool createColorTable(const SkImageInfo& dstInfo, int* ctableCount); + // Helper to set up swizzler, color xforms, and color table. Also calls png_read_update_info. + bool initializeXforms(const SkImageInfo& dstInfo, const Options&, SkPMColor* colorPtr, + int* colorCount); + void initializeSwizzler(const SkImageInfo& dstInfo, const Options&); + void allocateStorage(const SkImageInfo& dstInfo); void destroyReadStruct(); + virtual Result decodeAllRows(void* dst, size_t rowBytes, int* rowsDecoded) = 0; + virtual void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) = 0; + virtual Result decode(int* rowsDecoded) = 0; + + XformMode fXformMode; + SkColorSpaceXform::ColorFormat fXformColorFormat; + SkAlphaType fXformAlphaType; + int fXformWidth; + +#ifdef SK_GOOGLE3_PNG_HACK + bool fNeedsToRereadHeader; +#endif + typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/codec/SkRawCodec.cpp b/gfx/skia/skia/src/codec/SkRawCodec.cpp index 762e82364cd3..2a6a48fdbbd9 100644 --- a/gfx/skia/skia/src/codec/SkRawCodec.cpp +++ b/gfx/skia/skia/src/codec/SkRawCodec.cpp @@ -257,7 +257,7 @@ public: } SkMemoryStream* transferBuffer(size_t offset, size_t size) override { - SkAutoTUnref data(SkData::NewUninitialized(size)); + sk_sp data(SkData::MakeUninitialized(size)); if (offset > fStreamBuffer.bytesWritten()) { // If the offset is not buffered, read from fStream directly and skip the buffering. const size_t skipLength = offset - fStreamBuffer.bytesWritten(); @@ -266,7 +266,7 @@ public: } const size_t bytesRead = fStream->read(data->writable_data(), size); if (bytesRead < size) { - data.reset(SkData::NewSubset(data.get(), 0, bytesRead)); + data = SkData::MakeSubset(data.get(), 0, bytesRead); } } else { const size_t alreadyBuffered = SkTMin(fStreamBuffer.bytesWritten() - offset, size); @@ -284,7 +284,7 @@ public: if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize)) { return nullptr; } - data.reset(SkData::NewSubset(data.get(), 0, newSize)); + data = SkData::MakeSubset(data.get(), 0, newSize); } } } @@ -379,18 +379,18 @@ public: } if (fStream->getMemoryBase()) { // directly copy if getMemoryBase() is available. - SkAutoTUnref data(SkData::NewWithCopy( + sk_sp data(SkData::MakeWithCopy( static_cast(fStream->getMemoryBase()) + offset, bytesToRead)); fStream.reset(); return new SkMemoryStream(data); } else { - SkAutoTUnref data(SkData::NewUninitialized(bytesToRead)); + sk_sp data(SkData::MakeUninitialized(bytesToRead)); if (!fStream->seek(offset)) { return nullptr; } const size_t bytesRead = fStream->read(data->writable_data(), bytesToRead); if (bytesRead < bytesToRead) { - data.reset(SkData::NewSubset(data.get(), 0, bytesRead)); + data = SkData::MakeSubset(data.get(), 0, bytesRead); } return new SkMemoryStream(data); } @@ -515,8 +515,16 @@ public: } } - const SkImageInfo& getImageInfo() const { - return fImageInfo; + const SkEncodedInfo& getEncodedInfo() const { + return fEncodedInfo; + } + + int width() const { + return fWidth; + } + + int height() const { + return fHeight; } bool isScalable() const { @@ -545,8 +553,9 @@ private: return 0x2A == get_endian_short(header + 2, littleEndian); } - void init(const int width, const int height, const dng_point& cfaPatternSize) { - fImageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, kOpaque_SkAlphaType); + void init(int width, int height, const dng_point& cfaPatternSize) { + fWidth = width; + fHeight = height; // The DNG SDK scales only during demosaicing, so scaling is only possible when // a mosaic info is available. @@ -607,7 +616,10 @@ private: } SkDngImage(SkRawStream* stream) - : fStream(stream) {} + : fStream(stream) + , fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, + SkEncodedInfo::kOpaque_Alpha, 8)) + {} SkDngMemoryAllocator fAllocator; SkAutoTDelete fStream; @@ -616,7 +628,9 @@ private: SkAutoTDelete fNegative; SkAutoTDelete fDngStream; - SkImageInfo fImageInfo; + int fWidth; + int fHeight; + SkEncodedInfo fEncodedInfo; bool fIsScalable; bool fIsXtransImage; }; @@ -640,7 +654,11 @@ SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { if (::piex::IsRaw(&piexStream)) { ::piex::Error error = ::piex::GetPreviewImageData(&piexStream, &imageData); - if (error == ::piex::Error::kOk && imageData.preview.length > 0) { + // Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only + // handle the JPEG compressed preview image here. + if (error == ::piex::Error::kOk && imageData.preview.length > 0 && + imageData.preview.format == ::piex::Image::kJpegCompressed) + { // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this // function call. // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream. @@ -665,13 +683,13 @@ SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* size_t dstRowBytes, const Options& options, SkPMColor ctable[], int* ctableCount, int* rowsDecoded) { - if (!conversion_possible(requestedInfo, this->getInfo())) { + if (!conversion_possible_ignore_color_space(requestedInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } SkAutoTDelete swizzler(SkSwizzler::CreateSwizzler( - SkSwizzler::kRGB, nullptr, requestedInfo, options)); + this->getEncodedInfo(), nullptr, requestedInfo, options)); SkASSERT(swizzler); const int width = requestedInfo.width(); @@ -760,5 +778,5 @@ bool SkRawCodec::onDimensionsSupported(const SkISize& dim) { SkRawCodec::~SkRawCodec() {} SkRawCodec::SkRawCodec(SkDngImage* dngImage) - : INHERITED(dngImage->getImageInfo(), nullptr) + : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(), nullptr) , fDngImage(dngImage) {} diff --git a/gfx/skia/skia/src/codec/SkSampledCodec.cpp b/gfx/skia/skia/src/codec/SkSampledCodec.cpp index 49c939c1f887..cca26000d684 100644 --- a/gfx/skia/skia/src/codec/SkSampledCodec.cpp +++ b/gfx/skia/skia/src/codec/SkSampledCodec.cpp @@ -101,37 +101,65 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void int scaledSubsetWidth = info.width(); int scaledSubsetHeight = info.height(); + const SkImageInfo scaledInfo = info.makeWH(scaledSize.width(), scaledSize.height()); + + { + // Although startScanlineDecode expects the bottom and top to match the + // SkImageInfo, startIncrementalDecode uses them to determine which rows to + // decode. + SkIRect incrementalSubset = SkIRect::MakeXYWH(scaledSubsetX, scaledSubsetY, + scaledSubsetWidth, scaledSubsetHeight); + codecOptions.fSubset = &incrementalSubset; + const SkCodec::Result startResult = this->codec()->startIncrementalDecode( + scaledInfo, pixels, rowBytes, &codecOptions, + options.fColorPtr, options.fColorCount); + if (SkCodec::kSuccess == startResult) { + int rowsDecoded; + const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); + if (incResult == SkCodec::kSuccess) { + return SkCodec::kSuccess; + } + SkASSERT(SkCodec::kIncompleteInput == incResult); + + // FIXME: Can zero initialized be read from SkCodec::fOptions? + this->codec()->fillIncompleteImage(scaledInfo, pixels, rowBytes, + options.fZeroInitialized, scaledSubsetHeight, rowsDecoded); + return SkCodec::kIncompleteInput; + } else if (startResult != SkCodec::kUnimplemented) { + return startResult; + } + // Otherwise fall down to use the old scanline decoder. + // codecOptions.fSubset will be reset below, so it will not continue to + // point to the object that is no longer on the stack. + } + // Start the scanline decode. SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth, scaledSize.height()); codecOptions.fSubset = &scanlineSubset; - SkCodec::Result result = this->codec()->startScanlineDecode(info.makeWH(scaledSize.width(), - scaledSize.height()), &codecOptions, options.fColorPtr, options.fColorCount); + + SkCodec::Result result = this->codec()->startScanlineDecode(scaledInfo, + &codecOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } // At this point, we are only concerned with subsetting. Either no scale was // requested, or the this->codec() is handling the scale. - switch (this->codec()->getScanlineOrder()) { - case SkCodec::kTopDown_SkScanlineOrder: - case SkCodec::kNone_SkScanlineOrder: { - if (!this->codec()->skipScanlines(scaledSubsetY)) { - this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, - scaledSubsetHeight, 0); - return SkCodec::kIncompleteInput; - } - - int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); - if (decodedLines != scaledSubsetHeight) { - return SkCodec::kIncompleteInput; - } - return SkCodec::kSuccess; - } - default: - SkASSERT(false); - return SkCodec::kUnimplemented; + // Note that subsetting is only supported for kTopDown, so this code will not be + // reached for other orders. + SkASSERT(this->codec()->getScanlineOrder() == SkCodec::kTopDown_SkScanlineOrder); + if (!this->codec()->skipScanlines(scaledSubsetY)) { + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, + scaledSubsetHeight, 0); + return SkCodec::kIncompleteInput; } + + int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes); + if (decodedLines != scaledSubsetHeight) { + return SkCodec::kIncompleteInput; + } + return SkCodec::kSuccess; } @@ -174,10 +202,75 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix sampledOptions.fSubset = ⊂ } + // Since we guarantee that output dimensions are always at least one (even if the sampleSize + // is greater than a given dimension), the input sampleSize is not always the sampleSize that + // we use in practice. + const int sampleX = subsetWidth / info.width(); + const int sampleY = subsetHeight / info.height(); + + const int samplingOffsetY = get_start_coord(sampleY); + const int startY = samplingOffsetY + subsetY; + int dstHeight = info.height(); + + const SkImageInfo nativeInfo = info.makeWH(nativeSize.width(), nativeSize.height()); + + { + // Although startScanlineDecode expects the bottom and top to match the + // SkImageInfo, startIncrementalDecode uses them to determine which rows to + // decode. + // Note: We *could* use "subsetY" and "subsetHeight" (calculated above) for + // incrementalSubset, but this code gives us a tighter bounds on the subset, + // meaning that we can start with the first row actually needed by the output, + // and stop when we've decoded the last row needed by the output. + SkIRect incrementalSubset; + incrementalSubset.fTop = startY; + incrementalSubset.fBottom = startY + (dstHeight - 1) * sampleY + 1; + if (sampledOptions.fSubset) { + incrementalSubset.fLeft = sampledOptions.fSubset->fLeft; + incrementalSubset.fRight = sampledOptions.fSubset->fRight; + } else { + incrementalSubset.fLeft = 0; + incrementalSubset.fRight = nativeSize.width(); + } + SkCodec::Options incrementalOptions = sampledOptions; + incrementalOptions.fSubset = &incrementalSubset; + const SkCodec::Result startResult = this->codec()->startIncrementalDecode(nativeInfo, + pixels, rowBytes, &incrementalOptions, options.fColorPtr, options.fColorCount); + if (SkCodec::kSuccess == startResult) { + SkSampler* sampler = this->codec()->getSampler(true); + if (!sampler) { + return SkCodec::kUnimplemented; + } + + if (sampler->setSampleX(sampleX) != info.width()) { + return SkCodec::kInvalidScale; + } + if (get_scaled_dimension(subsetHeight, sampleY) != info.height()) { + return SkCodec::kInvalidScale; + } + + sampler->setSampleY(sampleY); + + int rowsDecoded; + const SkCodec::Result incResult = this->codec()->incrementalDecode(&rowsDecoded); + if (incResult == SkCodec::kSuccess) { + return SkCodec::kSuccess; + } + SkASSERT(incResult == SkCodec::kIncompleteInput); + + // Count the rows that we decoded, and also did not skip. + const int trueRowsDecoded = (rowsDecoded + sampleY - 1) / sampleY; + this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, + info.height(), trueRowsDecoded); + return SkCodec::kIncompleteInput; + } else if (startResult != SkCodec::kUnimplemented) { + return startResult; + } // kUnimplemented means use the old method. + } + // Start the scanline decode. - SkCodec::Result result = this->codec()->startScanlineDecode( - info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOptions, - options.fColorPtr, options.fColorCount); + SkCodec::Result result = this->codec()->startScanlineDecode(nativeInfo, + &sampledOptions, options.fColorPtr, options.fColorCount); if (SkCodec::kSuccess != result) { return result; } @@ -187,11 +280,6 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix return SkCodec::kUnimplemented; } - // Since we guarantee that output dimensions are always at least one (even if the sampleSize - // is greater than a given dimension), the input sampleSize is not always the sampleSize that - // we use in practice. - const int sampleX = subsetWidth / info.width(); - const int sampleY = subsetHeight / info.height(); if (sampler->setSampleX(sampleX) != info.width()) { return SkCodec::kInvalidScale; } @@ -199,9 +287,6 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix return SkCodec::kInvalidScale; } - const int samplingOffsetY = get_start_coord(sampleY); - const int startY = samplingOffsetY + subsetY; - int dstHeight = info.height(); switch(this->codec()->getScanlineOrder()) { case SkCodec::kTopDown_SkScanlineOrder: { if (!this->codec()->skipScanlines(startY)) { @@ -253,7 +338,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix // We handle filling uninitialized memory here instead of using this->codec(). // this->codec() does not know that we are sampling. - const uint32_t fillValue = this->codec()->getFillValue(info.colorType()); + const uint64_t fillValue = this->codec()->getFillValue(info); const SkImageInfo fillInfo = info.makeWH(info.width(), 1); for (; y < nativeSize.height(); y++) { int srcY = this->codec()->outputScanline(y); @@ -266,30 +351,6 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix } return SkCodec::kIncompleteInput; } - case SkCodec::kNone_SkScanlineOrder: { - const int linesNeeded = subsetHeight - samplingOffsetY; - SkAutoTMalloc storage(linesNeeded * rowBytes); - uint8_t* storagePtr = storage.get(); - - if (!this->codec()->skipScanlines(startY)) { - this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized, - dstHeight, 0); - return SkCodec::kIncompleteInput; - } - int scanlines = this->codec()->getScanlines(storagePtr, linesNeeded, rowBytes); - - for (int y = 0; y < dstHeight; y++) { - memcpy(pixels, storagePtr, info.minRowBytes()); - storagePtr += sampleY * rowBytes; - pixels = SkTAddOffset(pixels, rowBytes); - } - - if (scanlines < dstHeight) { - // this->codec() has already handled filling uninitialized memory. - return SkCodec::kIncompleteInput; - } - return SkCodec::kSuccess; - } default: SkASSERT(false); return SkCodec::kUnimplemented; diff --git a/gfx/skia/skia/src/codec/SkSampler.cpp b/gfx/skia/skia/src/codec/SkSampler.cpp index c69d003c0f58..244aa3b87338 100644 --- a/gfx/skia/skia/src/codec/SkSampler.cpp +++ b/gfx/skia/skia/src/codec/SkSampler.cpp @@ -11,7 +11,7 @@ #include "SkUtils.h" void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes, - uint32_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) { + uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) { SkASSERT(dst != nullptr); // Calculate bytes to fill. We use getSafeSize since the last row may not be padded. @@ -21,28 +21,18 @@ void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes, // Use the proper memset routine to fill the remaining bytes switch (info.colorType()) { - case kN32_SkColorType: { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: { // If memory is zero initialized, we may not need to fill - uint32_t color = colorOrIndex; + uint32_t color = (uint32_t) colorOrIndex; if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == color) { return; } - // We must fill row by row in the case of unaligned row bytes - if (SkIsAlign4((size_t) dst) && SkIsAlign4(rowBytes)) { - sk_memset32((uint32_t*) dst, color, - (uint32_t) bytesToFill / sizeof(SkPMColor)); - } else { - // We must fill row by row in the case of unaligned row bytes. This is an - // unlikely, slow case. - SkCodecPrintf("Warning: Strange number of row bytes, fill will be slow.\n"); - uint32_t* dstRow = (uint32_t*) dst; - for (int row = 0; row < numRows; row++) { - for (int col = 0; col < width; col++) { - dstRow[col] = color; - } - dstRow = SkTAddOffset(dstRow, rowBytes); - } + uint32_t* dstRow = (uint32_t*) dst; + for (int row = 0; row < numRows; row++) { + sk_memset32((uint32_t*) dstRow, color, width); + dstRow = SkTAddOffset(dstRow, rowBytes); } break; } @@ -60,19 +50,10 @@ void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes, return; } - if (SkIsAlign2((size_t) dst) && SkIsAlign2(rowBytes)) { - sk_memset16((uint16_t*) dst, color, (uint32_t) bytesToFill / sizeof(uint16_t)); - } else { - // We must fill row by row in the case of unaligned row bytes. This is an - // unlikely, slow case. - SkCodecPrintf("Warning: Strange number of row bytes, fill will be slow.\n"); - uint16_t* dstRow = (uint16_t*) dst; - for (int row = 0; row < numRows; row++) { - for (int col = 0; col < width; col++) { - dstRow[col] = color; - } - dstRow = SkTAddOffset(dstRow, rowBytes); - } + uint16_t* dstRow = (uint16_t*) dst; + for (int row = 0; row < numRows; row++) { + sk_memset16((uint16_t*) dstRow, color, width); + dstRow = SkTAddOffset(dstRow, rowBytes); } break; } @@ -94,6 +75,19 @@ void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes, memset(dst, (uint8_t) colorOrIndex, bytesToFill); break; + case kRGBA_F16_SkColorType: { + uint64_t color = colorOrIndex; + if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == color) { + return; + } + + uint64_t* dstRow = (uint64_t*) dst; + for (int row = 0; row < numRows; row++) { + sk_memset64((uint64_t*) dstRow, color, width); + dstRow = SkTAddOffset(dstRow, rowBytes); + } + break; + } default: SkCodecPrintf("Error: Unsupported dst color type for fill(). Doing nothing.\n"); SkASSERT(false); diff --git a/gfx/skia/skia/src/codec/SkSampler.h b/gfx/skia/skia/src/codec/SkSampler.h index 73e11c986e29..00015585a11d 100644 --- a/gfx/skia/skia/src/codec/SkSampler.h +++ b/gfx/skia/skia/src/codec/SkSampler.h @@ -20,6 +20,30 @@ public: return this->onSetSampleX(sampleX); } + /** + * Update the sampler to sample every sampleY'th row. + */ + void setSampleY(int sampleY) { + fSampleY = sampleY; + } + + /** + * Retrieve the value set for sampleY. + */ + int sampleY() const { + return fSampleY; + } + + /** + * Based on fSampleY, return whether this row belongs in the output. + * + * @param row Row of the image, starting with the first row used in the + * output. + */ + bool rowNeeded(int row) const { + return row % fSampleY == 0; + } + /** * Fill the remainder of the destination with a single color * @@ -35,6 +59,7 @@ public: * Stride in bytes of the destination. * * @param colorOrIndex + * If colorType is kF16, colorOrIndex is treated as a 64-bit color. * If colorType is kN32, colorOrIndex is treated as a 32-bit color. * If colorType is k565, colorOrIndex is treated as a 16-bit color. * If colorType is kGray, colorOrIndex is treated as an 8-bit color. @@ -46,16 +71,21 @@ public: * */ static void Fill(const SkImageInfo& info, void* dst, size_t rowBytes, - uint32_t colorOrIndex, SkCodec::ZeroInitialized zeroInit); + uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit); /** * Allow subclasses to implement unique versions of fill(). */ virtual void fill(const SkImageInfo& info, void* dst, size_t rowBytes, - uint32_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) {} + uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) {} + + SkSampler() + : fSampleY(1) + {} virtual ~SkSampler() {} private: + int fSampleY; virtual int onSetSampleX(int) = 0; }; diff --git a/gfx/skia/skia/src/codec/SkSwizzler.cpp b/gfx/skia/skia/src/codec/SkSwizzler.cpp index 133736879f20..c9eb92305387 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.cpp +++ b/gfx/skia/skia/src/codec/SkSwizzler.cpp @@ -348,21 +348,9 @@ static void fast_swizzle_grayalpha_to_n32_premul( SkOpts::grayA_to_rgbA((uint32_t*) dst, src + offset, width); } -// kBGRX +// kBGR -static void swizzle_bgrx_to_n32( - void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, - int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { - - src += offset; - SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - for (int x = 0; x < dstWidth; x++) { - dst[x] = SkPackARGB32NoCheck(0xFF, src[2], src[1], src[0]); - src += deltaSrc; - } -} - -static void swizzle_bgrx_to_565( +static void swizzle_bgr_to_565( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -374,79 +362,33 @@ static void swizzle_bgrx_to_565( } } -// kBGRA - -static void swizzle_bgra_to_n32_unpremul( - void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, - int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { - - src += offset; - SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - for (int x = 0; x < dstWidth; x++) { - uint8_t alpha = src[3]; - dst[x] = SkPackARGB32NoCheck(alpha, src[2], src[1], src[0]); - src += deltaSrc; - } -} - -static void fast_swizzle_bgra_to_n32_unpremul( - void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, - const SkPMColor ctable[]) { - - // This function must not be called if we are sampling. If we are not - // sampling, deltaSrc should equal bpp. - SkASSERT(deltaSrc == bpp); - -#ifdef SK_PMCOLOR_IS_RGBA - SkOpts::RGBA_to_BGRA((uint32_t*) dst, src + offset, width); -#else - memcpy(dst, src + offset, width * bpp); -#endif -} - -static void swizzle_bgra_to_n32_premul( - void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, - int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { - - src += offset; - SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; - for (int x = 0; x < dstWidth; x++) { - uint8_t alpha = src[3]; - dst[x] = SkPremultiplyARGBInline(alpha, src[2], src[1], src[0]); - src += deltaSrc; - } -} - -static void fast_swizzle_bgra_to_n32_premul( - void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, - const SkPMColor ctable[]) { - - // This function must not be called if we are sampling. If we are not - // sampling, deltaSrc should equal bpp. - SkASSERT(deltaSrc == bpp); - -#ifdef SK_PMCOLOR_IS_RGBA - SkOpts::RGBA_to_bgrA((uint32_t*) dst, src + offset, width); -#else - SkOpts::RGBA_to_rgbA((uint32_t*) dst, src + offset, width); -#endif -} - // kRGB -static void swizzle_rgb_to_n32( +static void swizzle_rgb_to_rgba( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; for (int x = 0; x < dstWidth; x++) { - dst[x] = SkPackARGB32NoCheck(0xFF, src[0], src[1], src[2]); + dst[x] = SkPackARGB_as_RGBA(0xFF, src[0], src[1], src[2]); src += deltaSrc; } } -static void fast_swizzle_rgb_to_n32( +static void swizzle_rgb_to_bgra( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, + int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { + + src += offset; + SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; + for (int x = 0; x < dstWidth; x++) { + dst[x] = SkPackARGB_as_BGRA(0xFF, src[0], src[1], src[2]); + src += deltaSrc; + } +} + +static void fast_swizzle_rgb_to_rgba( void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -454,11 +396,18 @@ static void fast_swizzle_rgb_to_n32( // sampling, deltaSrc should equal bpp. SkASSERT(deltaSrc == bpp); -#ifdef SK_PMCOLOR_IS_RGBA SkOpts::RGB_to_RGB1((uint32_t*) dst, src + offset, width); -#else +} + +static void fast_swizzle_rgb_to_bgra( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, + int offset, const SkPMColor ctable[]) { + + // This function must not be called if we are sampling. If we are not + // sampling, deltaSrc should equal bpp. + SkASSERT(deltaSrc == bpp); + SkOpts::RGB_to_BGR1((uint32_t*) dst, src + offset, width); -#endif } static void swizzle_rgb_to_565( @@ -475,20 +424,31 @@ static void swizzle_rgb_to_565( // kRGBA -static void swizzle_rgba_to_n32_premul( +static void swizzle_rgba_to_rgba_premul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { src += offset; SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; for (int x = 0; x < dstWidth; x++) { - unsigned alpha = src[3]; - dst[x] = SkPremultiplyARGBInline(alpha, src[0], src[1], src[2]); + dst[x] = premultiply_argb_as_rgba(src[3], src[0], src[1], src[2]); src += deltaSrc; } } -static void fast_swizzle_rgba_to_n32_premul( +static void swizzle_rgba_to_bgra_premul( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, + int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { + + src += offset; + SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; + for (int x = 0; x < dstWidth; x++) { + dst[x] = premultiply_argb_as_bgra(src[3], src[0], src[1], src[2]); + src += deltaSrc; + } +} + +static void fast_swizzle_rgba_to_rgba_premul( void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -496,14 +456,21 @@ static void fast_swizzle_rgba_to_n32_premul( // sampling, deltaSrc should equal bpp. SkASSERT(deltaSrc == bpp); -#ifdef SK_PMCOLOR_IS_RGBA SkOpts::RGBA_to_rgbA((uint32_t*) dst, src + offset, width); -#else - SkOpts::RGBA_to_bgrA((uint32_t*) dst, src + offset, width); -#endif } -static void swizzle_rgba_to_n32_unpremul( +static void fast_swizzle_rgba_to_bgra_premul( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, + int offset, const SkPMColor ctable[]) { + + // This function must not be called if we are sampling. If we are not + // sampling, deltaSrc should equal bpp. + SkASSERT(deltaSrc == bpp); + + SkOpts::RGBA_to_bgrA((uint32_t*) dst, src + offset, width); +} + +static void swizzle_rgba_to_bgra_unpremul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -511,12 +478,12 @@ static void swizzle_rgba_to_n32_unpremul( uint32_t* SK_RESTRICT dst = reinterpret_cast(dstRow); for (int x = 0; x < dstWidth; x++) { unsigned alpha = src[3]; - dst[x] = SkPackARGB32NoCheck(alpha, src[0], src[1], src[2]); + dst[x] = SkPackARGB_as_BGRA(alpha, src[0], src[1], src[2]); src += deltaSrc; } } -static void fast_swizzle_rgba_to_n32_unpremul( +static void fast_swizzle_rgba_to_bgra_unpremul( void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -524,11 +491,7 @@ static void fast_swizzle_rgba_to_n32_unpremul( // sampling, deltaSrc should equal bpp. SkASSERT(deltaSrc == bpp); -#ifdef SK_PMCOLOR_IS_RGBA - memcpy(dst, src + offset, width * bpp); -#else SkOpts::RGBA_to_BGRA((uint32_t*) dst, src + offset, width); -#endif } // kCMYK @@ -576,7 +539,7 @@ static void fast_swizzle_rgba_to_n32_unpremul( // R = C * K / 255 // G = M * K / 255 // B = Y * K / 255 -static void swizzle_cmyk_to_n32( +static void swizzle_cmyk_to_rgba( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -587,12 +550,28 @@ static void swizzle_cmyk_to_n32( const uint8_t g = SkMulDiv255Round(src[1], src[3]); const uint8_t b = SkMulDiv255Round(src[2], src[3]); - dst[x] = SkPackARGB32NoCheck(0xFF, r, g, b); + dst[x] = SkPackARGB_as_RGBA(0xFF, r, g, b); src += deltaSrc; } } -static void fast_swizzle_cmyk_to_n32( +static void swizzle_cmyk_to_bgra( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int dstWidth, + int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { + + src += offset; + SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; + for (int x = 0; x < dstWidth; x++) { + const uint8_t r = SkMulDiv255Round(src[0], src[3]); + const uint8_t g = SkMulDiv255Round(src[1], src[3]); + const uint8_t b = SkMulDiv255Round(src[2], src[3]); + + dst[x] = SkPackARGB_as_BGRA(0xFF, r, g, b); + src += deltaSrc; + } +} + +static void fast_swizzle_cmyk_to_rgba( void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[]) { @@ -600,11 +579,18 @@ static void fast_swizzle_cmyk_to_n32( // sampling, deltaSrc should equal bpp. SkASSERT(deltaSrc == bpp); -#ifdef SK_PMCOLOR_IS_RGBA SkOpts::inverted_CMYK_to_RGB1((uint32_t*) dst, src + offset, width); -#else +} + +static void fast_swizzle_cmyk_to_bgra( + void* dst, const uint8_t* src, int width, int bpp, int deltaSrc, int offset, + const SkPMColor ctable[]) { + + // This function must not be called if we are sampling. If we are not + // sampling, deltaSrc should equal bpp. + SkASSERT(deltaSrc == bpp); + SkOpts::inverted_CMYK_to_BGR1((uint32_t*) dst, src + offset, width); -#endif } static void swizzle_cmyk_to_565( @@ -661,233 +647,336 @@ void SkSwizzler::SkipLeading8888ZerosThen( proc(dst32, (const uint8_t*)src32, dstWidth, bpp, deltaSrc, 0, ctable); } -SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, +SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo, const SkPMColor* ctable, const SkImageInfo& dstInfo, const SkCodec::Options& options, - const SkIRect* frame) { - if (dstInfo.colorType() == kUnknown_SkColorType || kUnknown == sc) { + const SkIRect* frame, + bool preSwizzled) { + if (SkEncodedInfo::kPalette_Color == encodedInfo.color() && nullptr == ctable) { return nullptr; } - if ((kIndex == sc || kIndex4 == sc || kIndex2 == sc || kIndex1 == sc) - && nullptr == ctable) { - return nullptr; - } - RowProc fastProc = nullptr; - RowProc proc = nullptr; - SkCodec::ZeroInitialized zeroInit = options.fZeroInitialized; - switch (sc) { - case kBit: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_bit_to_n32; - break; - case kIndex_8_SkColorType: - proc = &swizzle_bit_to_index; - break; - case kRGB_565_SkColorType: - proc = &swizzle_bit_to_565; - break; - case kGray_8_SkColorType: - proc = &swizzle_bit_to_grayscale; - break; - default: - break; - } - break; - case kIndex1: - case kIndex2: - case kIndex4: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_small_index_to_n32; - break; - case kRGB_565_SkColorType: - proc = &swizzle_small_index_to_565; - break; - case kIndex_8_SkColorType: - proc = &swizzle_small_index_to_index; - break; - default: - break; - } - break; - case kIndex: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - // We assume the color premultiplied ctable (or not) as desired. - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &swizzle_index_to_n32_skipZ; - break; - } else { - proc = &swizzle_index_to_n32; - break; - } - break; - case kRGB_565_SkColorType: - proc = &swizzle_index_to_565; - break; - case kIndex_8_SkColorType: - proc = &sample1; - fastProc = © - break; - default: - break; - } - break; - case kGray: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_gray_to_n32; - fastProc = &fast_swizzle_gray_to_n32; - break; - case kGray_8_SkColorType: - proc = &sample1; - fastProc = © - break; - case kRGB_565_SkColorType: - proc = &swizzle_gray_to_565; - break; - default: - break; - } - break; - case kGrayAlpha: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - if (dstInfo.alphaType() == kUnpremul_SkAlphaType) { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeadingGrayAlphaZerosThen - ; - fastProc = &SkipLeadingGrayAlphaZerosThen - ; - } else { - proc = &swizzle_grayalpha_to_n32_unpremul; - fastProc = &fast_swizzle_grayalpha_to_n32_unpremul; - } - } else { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeadingGrayAlphaZerosThen; - fastProc = &SkipLeadingGrayAlphaZerosThen - ; - } else { - proc = &swizzle_grayalpha_to_n32_premul; - fastProc = &fast_swizzle_grayalpha_to_n32_premul; - } - } - break; - default: - break; - } - break; - case kBGR: - case kBGRX: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_bgrx_to_n32; - break; - case kRGB_565_SkColorType: - proc = &swizzle_bgrx_to_565; - break; - default: - break; - } - break; - case kBGRA: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - if (dstInfo.alphaType() == kUnpremul_SkAlphaType) { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeading8888ZerosThen; - fastProc = &SkipLeading8888ZerosThen; - } else { - proc = &swizzle_bgra_to_n32_unpremul; - fastProc = &fast_swizzle_bgra_to_n32_unpremul; - } - } else { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeading8888ZerosThen; - fastProc = &SkipLeading8888ZerosThen; - } else { - proc = &swizzle_bgra_to_n32_premul; - fastProc = &fast_swizzle_bgra_to_n32_premul; - } - } - break; - default: - break; - } - break; - case kRGB: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_rgb_to_n32; - fastProc = &fast_swizzle_rgb_to_n32; - break; - case kRGB_565_SkColorType: - proc = &swizzle_rgb_to_565; - break; - default: - break; - } - break; - case kRGBA: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - if (dstInfo.alphaType() == kUnpremul_SkAlphaType) { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeading8888ZerosThen; - fastProc = &SkipLeading8888ZerosThen; - } else { - proc = &swizzle_rgba_to_n32_unpremul; - fastProc = &fast_swizzle_rgba_to_n32_unpremul; - } - } else { - if (SkCodec::kYes_ZeroInitialized == zeroInit) { - proc = &SkipLeading8888ZerosThen; - fastProc = &SkipLeading8888ZerosThen; - } else { - proc = &swizzle_rgba_to_n32_premul; - fastProc = &fast_swizzle_rgba_to_n32_premul; - } - } - break; - default: - break; - } - break; - case kCMYK: - switch (dstInfo.colorType()) { - case kN32_SkColorType: - proc = &swizzle_cmyk_to_n32; - fastProc = &fast_swizzle_cmyk_to_n32; - break; - case kRGB_565_SkColorType: - proc = &swizzle_cmyk_to_565; - break; - default: - break; - } - break; - case kNoOp8: - proc = &sample1; - fastProc = © - break; - case kNoOp16: - proc = sample2; - fastProc = © - break; - case kNoOp32: - proc = &sample4; - fastProc = © - break; - default: - break; - } - // Store bpp in bytes if it is an even multiple, otherwise use bits - int srcBPP = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc); - int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType()); + RowProc fastProc = nullptr; + RowProc proc = nullptr; + if (preSwizzled) { + switch (dstInfo.colorType()) { + case kGray_8_SkColorType: + proc = &sample1; + fastProc = © + break; + case kRGB_565_SkColorType: + proc = &sample2; + fastProc = © + break; + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + proc = &sample4; + fastProc = © + break; + default: + return nullptr; + } + } else { + SkCodec::ZeroInitialized zeroInit = options.fZeroInitialized; + const bool premultiply = (SkEncodedInfo::kOpaque_Alpha != encodedInfo.alpha()) && + (kPremul_SkAlphaType == dstInfo.alphaType()); + + switch (encodedInfo.color()) { + case SkEncodedInfo::kGray_Color: + switch (encodedInfo.bitsPerComponent()) { + case 1: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + proc = &swizzle_bit_to_n32; + break; + case kIndex_8_SkColorType: + proc = &swizzle_bit_to_index; + break; + case kRGB_565_SkColorType: + proc = &swizzle_bit_to_565; + break; + case kGray_8_SkColorType: + proc = &swizzle_bit_to_grayscale; + break; + default: + return nullptr; + } + break; + case 8: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + proc = &swizzle_gray_to_n32; + fastProc = &fast_swizzle_gray_to_n32; + break; + case kGray_8_SkColorType: + proc = &sample1; + fastProc = © + break; + case kRGB_565_SkColorType: + proc = &swizzle_gray_to_565; + break; + default: + return nullptr; + } + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kGrayAlpha_Color: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + if (premultiply) { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeadingGrayAlphaZerosThen + ; + fastProc = &SkipLeadingGrayAlphaZerosThen + ; + } else { + proc = &swizzle_grayalpha_to_n32_premul; + fastProc = &fast_swizzle_grayalpha_to_n32_premul; + } + } else { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeadingGrayAlphaZerosThen + ; + fastProc = &SkipLeadingGrayAlphaZerosThen + ; + } else { + proc = &swizzle_grayalpha_to_n32_unpremul; + fastProc = &fast_swizzle_grayalpha_to_n32_unpremul; + } + } + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kPalette_Color: + // We assume that the color table is premultiplied and swizzled + // as desired. + switch (encodedInfo.bitsPerComponent()) { + case 1: + case 2: + case 4: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + proc = &swizzle_small_index_to_n32; + break; + case kRGB_565_SkColorType: + proc = &swizzle_small_index_to_565; + break; + case kIndex_8_SkColorType: + proc = &swizzle_small_index_to_index; + break; + default: + return nullptr; + } + break; + case 8: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &swizzle_index_to_n32_skipZ; + } else { + proc = &swizzle_index_to_n32; + } + break; + case kRGB_565_SkColorType: + proc = &swizzle_index_to_565; + break; + case kIndex_8_SkColorType: + proc = &sample1; + fastProc = © + break; + default: + return nullptr; + } + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kRGB_Color: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + proc = &swizzle_rgb_to_rgba; + fastProc = &fast_swizzle_rgb_to_rgba; + break; + case kBGRA_8888_SkColorType: + proc = &swizzle_rgb_to_bgra; + fastProc = &fast_swizzle_rgb_to_bgra; + break; + case kRGB_565_SkColorType: + proc = &swizzle_rgb_to_565; + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kRGBA_Color: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + if (premultiply) { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_rgba_premul; + fastProc = &fast_swizzle_rgba_to_rgba_premul; + } + } else { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen; + } else { + proc = &sample4; + fastProc = © + } + } + break; + case kBGRA_8888_SkColorType: + if (premultiply) { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_bgra_premul; + fastProc = &fast_swizzle_rgba_to_bgra_premul; + } + } else { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_bgra_unpremul; + fastProc = &fast_swizzle_rgba_to_bgra_unpremul; + } + } + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kBGR_Color: + switch (dstInfo.colorType()) { + case kBGRA_8888_SkColorType: + proc = &swizzle_rgb_to_rgba; + fastProc = &fast_swizzle_rgb_to_rgba; + break; + case kRGBA_8888_SkColorType: + proc = &swizzle_rgb_to_bgra; + fastProc = &fast_swizzle_rgb_to_bgra; + break; + case kRGB_565_SkColorType: + proc = &swizzle_bgr_to_565; + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kBGRX_Color: + switch (dstInfo.colorType()) { + case kBGRA_8888_SkColorType: + proc = &swizzle_rgb_to_rgba; + break; + case kRGBA_8888_SkColorType: + proc = &swizzle_rgb_to_bgra; + break; + case kRGB_565_SkColorType: + proc = &swizzle_bgr_to_565; + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kBGRA_Color: + switch (dstInfo.colorType()) { + case kBGRA_8888_SkColorType: + if (premultiply) { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_rgba_premul; + fastProc = &fast_swizzle_rgba_to_rgba_premul; + } + } else { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen; + } else { + proc = &sample4; + fastProc = © + } + } + break; + case kRGBA_8888_SkColorType: + if (premultiply) { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_bgra_premul; + fastProc = &fast_swizzle_rgba_to_bgra_premul; + } + } else { + if (SkCodec::kYes_ZeroInitialized == zeroInit) { + proc = &SkipLeading8888ZerosThen; + fastProc = &SkipLeading8888ZerosThen + ; + } else { + proc = &swizzle_rgba_to_bgra_unpremul; + fastProc = &fast_swizzle_rgba_to_bgra_unpremul; + } + } + break; + default: + return nullptr; + } + break; + case SkEncodedInfo::kInvertedCMYK_Color: + switch (dstInfo.colorType()) { + case kRGBA_8888_SkColorType: + proc = &swizzle_cmyk_to_rgba; + fastProc = &fast_swizzle_cmyk_to_rgba; + break; + case kBGRA_8888_SkColorType: + proc = &swizzle_cmyk_to_bgra; + fastProc = &fast_swizzle_cmyk_to_bgra; + break; + case kRGB_565_SkColorType: + proc = &swizzle_cmyk_to_565; + break; + default: + return nullptr; + } + break; + default: + return nullptr; + } + } + + int srcBPP; + const int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType()); + if (preSwizzled) { + srcBPP = dstBPP; + } else { + // Store bpp in bytes if it is an even multiple, otherwise use bits + uint8_t bitsPerPixel = encodedInfo.bitsPerPixel(); + srcBPP = SkIsAlign8(bitsPerPixel) ? bitsPerPixel / 8 : bitsPerPixel; + } int srcOffset = 0; int srcWidth = dstInfo.width(); diff --git a/gfx/skia/skia/src/codec/SkSwizzler.h b/gfx/skia/skia/src/codec/SkSwizzler.h index 7eebe7f98156..a535298a0795 100644 --- a/gfx/skia/skia/src/codec/SkSwizzler.h +++ b/gfx/skia/skia/src/codec/SkSwizzler.h @@ -15,79 +15,9 @@ class SkSwizzler : public SkSampler { public: - /** - * Enum describing the config of the source data. - */ - enum SrcConfig { - kUnknown, // Invalid type. - kBit, // A single bit to distinguish between white and black. - kGray, - kGrayAlpha, - kIndex1, - kIndex2, - kIndex4, - kIndex, - kRGB, - kBGR, - kBGRX, // The alpha channel can be anything, but the image is opaque. - kRGBA, - kBGRA, - kCMYK, - kNoOp8, // kNoOp modes are used exclusively for sampling, subsetting, and - kNoOp16, // copying. The pixels themselves do not need to be modified. - kNoOp32, - }; - - /* - * - * Returns bits per pixel for source config - * - */ - static int BitsPerPixel(SrcConfig sc) { - switch (sc) { - case kBit: - case kIndex1: - return 1; - case kIndex2: - return 2; - case kIndex4: - return 4; - case kGray: - case kIndex: - case kNoOp8: - return 8; - case kGrayAlpha: - case kNoOp16: - return 16; - case kRGB: - case kBGR: - return 24; - case kRGBA: - case kBGRX: - case kBGRA: - case kCMYK: - case kNoOp32: - return 32; - default: - SkASSERT(false); - return 0; - } - } - - /* - * - * Returns bytes per pixel for source config - * Raises an error if each pixel is not stored in an even number of bytes - * - */ - static int BytesPerPixel(SrcConfig sc) { - SkASSERT(SkIsAlign8(BitsPerPixel(sc))); - return BitsPerPixel(sc) >> 3; - } - /** * Create a new SkSwizzler. - * @param SrcConfig Description of the format of the source. + * @param encodedInfo Description of the format of the encoded data. * @param ctable Unowned pointer to an array of up to 256 colors for an * index source. * @param dstInfo Describes the destination. @@ -97,6 +27,9 @@ public: * Contains partial scanline information. * @param frame Is non-NULL if the source pixels are part of an image * frame that is a subset of the full image. + * @param preSwizzled Indicates that the codec has already swizzled to the + * destination format. The swizzler only needs to sample + * and/or subset. * * Note that a deeper discussion of partial scanline subsets and image frame * subsets is below. Currently, we do not support both simultaneously. If @@ -104,9 +37,9 @@ public: * * @return A new SkSwizzler or nullptr on failure. */ - static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable, + static SkSwizzler* CreateSwizzler(const SkEncodedInfo& encodedInfo, const SkPMColor* ctable, const SkImageInfo& dstInfo, const SkCodec::Options&, - const SkIRect* frame = nullptr); + const SkIRect* frame = nullptr, bool preSwizzled = false); /** * Swizzle a line. Generally this will be called height times, once @@ -123,7 +56,7 @@ public: /** * Implement fill using a custom width. */ - void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint32_t colorOrIndex, + void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) override { const SkImageInfo fillInfo = info.makeWH(fAllocatedWidth, info.height()); SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit); @@ -139,6 +72,12 @@ public: */ int sampleX() const { return fSampleX; } + /** + * Returns the actual number of pixels written to destination memory, taking + * scaling, subsetting, and partial frames into account. + */ + int swizzleWidth() const { return fSwizzleWidth; } + private: /** diff --git a/gfx/skia/skia/src/codec/SkWbmpCodec.cpp b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp index 90ee322b1f64..099b6e472a9e 100644 --- a/gfx/skia/skia/src/codec/SkWbmpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.cpp @@ -30,14 +30,14 @@ static inline void setup_color_table(SkColorType colorType, } } -static inline bool valid_color_type(SkColorType colorType, SkAlphaType alphaType) { +static inline bool valid_color_type(SkColorType colorType) { switch (colorType) { - case kN32_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: case kIndex_8_SkColorType: - return true; case kGray_8_SkColorType: case kRGB_565_SkColorType: - return kOpaque_SkAlphaType == alphaType; + return true; default: return false; } @@ -97,15 +97,15 @@ bool SkWbmpCodec::onRewind() { SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable, const Options& opts) { - return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts); + return SkSwizzler::CreateSwizzler(this->getEncodedInfo(), ctable, info, opts); } bool SkWbmpCodec::readRow(uint8_t* row) { return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes; } -SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream) - : INHERITED(info, stream) +SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream) + : INHERITED(width, height, info, stream) , fSrcRowBytes(get_src_row_bytes(this->getInfo().width())) , fSwizzler(nullptr) , fColorTable(nullptr) @@ -127,7 +127,7 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, return kUnimplemented; } - if (!valid_color_type(info.colorType(), info.alphaType()) || + if (!valid_color_type(info.colorType()) || !valid_alpha(info.alphaType(), this->getInfo().alphaType())) { return kInvalidConversion; } @@ -155,8 +155,7 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info, } bool SkWbmpCodec::IsWbmp(const void* buffer, size_t bytesRead) { - SkAutoTUnref data(SkData::NewWithoutCopy(buffer, bytesRead)); - SkMemoryStream stream(data); + SkMemoryStream stream(buffer, bytesRead, false); return read_header(&stream, nullptr); } @@ -166,9 +165,9 @@ SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) { if (!read_header(stream, &size)) { return nullptr; } - SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), - kGray_8_SkColorType, kOpaque_SkAlphaType); - return new SkWbmpCodec(info, streamDeleter.release()); + SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color, + SkEncodedInfo::kOpaque_Alpha, 1); + return new SkWbmpCodec(size.width(), size.height(), info, streamDeleter.release()); } int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { @@ -195,7 +194,7 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo, return kUnimplemented; } - if (!valid_color_type(dstInfo.colorType(), dstInfo.alphaType()) || + if (!valid_color_type(dstInfo.colorType()) || !valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) { return kInvalidConversion; } diff --git a/gfx/skia/skia/src/codec/SkWbmpCodec.h b/gfx/skia/skia/src/codec/SkWbmpCodec.h index f43f615ed252..9f29237e2394 100644 --- a/gfx/skia/skia/src/codec/SkWbmpCodec.h +++ b/gfx/skia/skia/src/codec/SkWbmpCodec.h @@ -44,7 +44,7 @@ private: */ bool readRow(uint8_t* row); - SkWbmpCodec(const SkImageInfo&, SkStream*); + SkWbmpCodec(int width, int height, const SkEncodedInfo&, SkStream*); const size_t fSrcRowBytes; diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.cpp b/gfx/skia/skia/src/codec/SkWebpCodec.cpp index 77af8e5e8f6f..3e5ef2aecf3d 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.cpp +++ b/gfx/skia/skia/src/codec/SkWebpCodec.cpp @@ -6,7 +6,9 @@ */ #include "SkCodecPriv.h" +#include "SkColorSpaceXform.h" #include "SkWebpCodec.h" +#include "SkStreamPriv.h" #include "SkTemplates.h" // A WebP decoder on top of (subset of) libwebp @@ -18,6 +20,7 @@ // If moving libwebp out of skia source tree, path for webp headers must be // updated accordingly. Here, we enforce using local copy in webp sub-directory. #include "webp/decode.h" +#include "webp/demux.h" #include "webp/encode.h" bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) { @@ -31,79 +34,114 @@ bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) { // Parse headers of RIFF container, and check for valid Webp (VP8) content. // NOTE: This calls peek instead of read, since onGetPixels will need these // bytes again. -static bool webp_parse_header(SkStream* stream, SkImageInfo* info) { - unsigned char buffer[WEBP_VP8_HEADER_SIZE]; - SkASSERT(WEBP_VP8_HEADER_SIZE <= SkCodec::MinBufferedBytesNeeded()); +// Returns an SkWebpCodec on success; +SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { + SkAutoTDelete streamDeleter(stream); - const size_t bytesPeeked = stream->peek(buffer, WEBP_VP8_HEADER_SIZE); - if (bytesPeeked != WEBP_VP8_HEADER_SIZE) { - // Use read + rewind as a backup - if (stream->read(buffer, WEBP_VP8_HEADER_SIZE) != WEBP_VP8_HEADER_SIZE - || !stream->rewind()) - return false; + // Webp demux needs a contiguous data buffer. + sk_sp data = nullptr; + if (stream->getMemoryBase()) { + // It is safe to make without copy because we'll hold onto the stream. + data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength()); + } else { + data = SkCopyStreamToData(stream); + + // If we are forced to copy the stream to a data, we can go ahead and delete the stream. + streamDeleter.reset(nullptr); } - WebPBitstreamFeatures features; - VP8StatusCode status = WebPGetFeatures(buffer, WEBP_VP8_HEADER_SIZE, &features); - if (VP8_STATUS_OK != status) { - return false; // Invalid WebP file. + // It's a little strange that the |demux| will outlive |webpData|, though it needs the + // pointer in |webpData| to remain valid. This works because the pointer remains valid + // until the SkData is freed. + WebPData webpData = { data->bytes(), data->size() }; + SkAutoTCallVProc demux(WebPDemuxPartial(&webpData, nullptr)); + if (nullptr == demux) { + return nullptr; } - // sanity check for image size that's about to be decoded. + WebPChunkIterator chunkIterator; + SkAutoTCallVProc autoCI(&chunkIterator); + sk_sp colorSpace = nullptr; + if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) { + colorSpace = SkColorSpace::NewICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size); + } + + if (!colorSpace) { + colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + } + + // Since we do not yet support animation, we get the |width|, |height|, |color|, and |alpha| + // from the first frame. It's the only frame we will decode. + // + // TODO: + // When we support animation, we'll want to report the canvas width and canvas height instead. + // We can get these from the |demux| directly. + // What |color| and |alpha| will we want to report though? WebP allows different frames + // to be encoded in different ways, making the encoded format difficult to describe. + WebPIterator frame; + SkAutoTCallVProc autoFrame(&frame); + if (!WebPDemuxGetFrame(demux, 1, &frame)) { + return nullptr; + } + + // Sanity check for image size that's about to be decoded. { - const int64_t size = sk_64_mul(features.width, features.height); + const int64_t size = sk_64_mul(frame.width, frame.height); if (!sk_64_isS32(size)) { - return false; + return nullptr; } // now check that if we are 4-bytes per pixel, we also don't overflow if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) { - return false; + return nullptr; } } - if (info) { - // FIXME: Is N32 the right type? - // Is unpremul the right type? Clients of SkCodec may assume it's the - // best type, when Skia currently cannot draw unpremul (and raster is faster - // with premul). - *info = SkImageInfo::Make(features.width, features.height, kN32_SkColorType, - SkToBool(features.has_alpha) ? kUnpremul_SkAlphaType - : kOpaque_SkAlphaType); - } - return true; -} - -SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { - SkAutoTDelete streamDeleter(stream); - SkImageInfo info; - if (webp_parse_header(stream, &info)) { - return new SkWebpCodec(info, streamDeleter.release()); - } - return nullptr; -} - -// This version is slightly different from SkCodecPriv's version of conversion_possible. It -// supports both byte orders for 8888. -static bool webp_conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { - // FIXME: skbug.com/4895 - // Currently, we ignore the SkColorProfileType on the SkImageInfo. We - // will treat the encoded data as linear regardless of what the client - // requests. - - if (!valid_alpha(dst.alphaType(), src.alphaType())) { - return false; + // TODO: + // The only reason we actually need to call WebPGetFeatures() is to get the |features.format|. + // This call actually re-reads the frame header. Should we suggest that libwebp expose + // the format on the |frame|? + WebPBitstreamFeatures features; + VP8StatusCode status = WebPGetFeatures(frame.fragment.bytes, frame.fragment.size, &features); + if (VP8_STATUS_OK != status) { + return nullptr; } - switch (dst.colorType()) { - // Both byte orders are supported. - case kBGRA_8888_SkColorType: - case kRGBA_8888_SkColorType: - return true; - case kRGB_565_SkColorType: - return src.alphaType() == kOpaque_SkAlphaType; + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; + switch (features.format) { + case 0: + // This indicates a "mixed" format. We would see this for + // animated webps or for webps encoded in multiple fragments. + // I believe that this is a rare case. + // We could also guess kYUV here, but I think it makes more + // sense to guess kBGRA which is likely closer to the final + // output. Otherwise, we might end up converting + // BGRA->YUVA->BGRA. + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + break; + case 1: + // This is the lossy format (YUV). + if (SkToBool(features.has_alpha)) { + color = SkEncodedInfo::kYUVA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + } else { + color = SkEncodedInfo::kYUV_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; + } + break; + case 2: + // This is the lossless format (BGRA). + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + break; default: - return false; + return nullptr; } + + SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); + return new SkWebpCodec(features.width, features.height, info, std::move(colorSpace), + streamDeleter.release(), demux.release(), std::move(data)); } SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const { @@ -121,7 +159,6 @@ bool SkWebpCodec::onDimensionsSupported(const SkISize& dim) { && dim.height() >= 1 && dim.height() <= info.height(); } - static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) { switch (ct) { case kBGRA_8888_SkColorType: @@ -135,11 +172,6 @@ static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) { } } -// The WebP decoding API allows us to incrementally pass chunks of bytes as we receive them to the -// decoder with WebPIAppend. In order to do so, we need to read chunks from the SkStream. This size -// is arbitrary. -static const size_t BUFFER_SIZE = 4096; - bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { if (!desiredSubset) { return false; @@ -160,11 +192,17 @@ bool SkWebpCodec::onGetValidSubset(SkIRect* desiredSubset) const { SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, const Options& options, SkPMColor*, int*, - int* rowsDecoded) { - if (!webp_conversion_possible(dstInfo, this->getInfo())) { + int* rowsDecodedPtr) { + if (!conversion_possible(dstInfo, this->getInfo())) { return kInvalidConversion; } + std::unique_ptr colorXform = nullptr; + if (needs_color_xform(dstInfo, this->getInfo())) { + colorXform = SkColorSpaceXform::New(this->getInfo().colorSpace(), dstInfo.colorSpace()); + SkASSERT(colorXform); + } + WebPDecoderConfig config; if (0 == WebPInitDecoderConfig(&config)) { // ABI mismatch. @@ -219,40 +257,78 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, config.options.scaled_height = dstDimensions.height(); } - config.output.colorspace = webp_decode_mode(dstInfo.colorType(), - dstInfo.alphaType() == kPremul_SkAlphaType); - config.output.u.RGBA.rgba = (uint8_t*) dst; - config.output.u.RGBA.stride = (int) rowBytes; - config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes); + // Swizzling between RGBA and BGRA is zero cost in a color transform. So when we have a + // color transform, we should decode to whatever is easiest for libwebp, and then let the + // color transform swizzle if necessary. + // Lossy webp is encoded as YUV (so RGBA and BGRA are the same cost). Lossless webp is + // encoded as BGRA. This means decoding to BGRA is either faster or the same cost as RGBA. + config.output.colorspace = colorXform ? MODE_BGRA : + webp_decode_mode(dstInfo.colorType(), dstInfo.alphaType() == kPremul_SkAlphaType); config.output.is_external_memory = 1; + // We will decode the entire image and then perform the color transform. libwebp + // does not provide a row-by-row API. This is a shame particularly in the F16 case, + // where we need to allocate an extra image-sized buffer. + SkAutoTMalloc pixels; + if (kRGBA_F16_SkColorType == dstInfo.colorType()) { + pixels.reset(dstDimensions.width() * dstDimensions.height()); + config.output.u.RGBA.rgba = (uint8_t*) pixels.get(); + config.output.u.RGBA.stride = (int) dstDimensions.width() * sizeof(uint32_t); + config.output.u.RGBA.size = config.output.u.RGBA.stride * dstDimensions.height(); + } else { + config.output.u.RGBA.rgba = (uint8_t*) dst; + config.output.u.RGBA.stride = (int) rowBytes; + config.output.u.RGBA.size = dstInfo.getSafeSize(rowBytes); + } + + WebPIterator frame; + SkAutoTCallVProc autoFrame(&frame); + // If this succeeded in NewFromStream(), it should succeed again here. + SkAssertResult(WebPDemuxGetFrame(fDemux, 1, &frame)); + SkAutoTCallVProc idec(WebPIDecode(nullptr, 0, &config)); if (!idec) { return kInvalidInput; } - SkAutoTMalloc storage(BUFFER_SIZE); - uint8_t* buffer = storage.get(); - while (true) { - const size_t bytesRead = stream()->read(buffer, BUFFER_SIZE); - if (0 == bytesRead) { - WebPIDecGetRGB(idec, rowsDecoded, NULL, NULL, NULL); - return kIncompleteInput; - } + int rowsDecoded; + SkCodec::Result result; + switch (WebPIUpdate(idec, frame.fragment.bytes, frame.fragment.size)) { + case VP8_STATUS_OK: + rowsDecoded = dstInfo.height(); + result = kSuccess; + break; + case VP8_STATUS_SUSPENDED: + WebPIDecGetRGB(idec, rowsDecodedPtr, nullptr, nullptr, nullptr); + rowsDecoded = *rowsDecodedPtr; + result = kIncompleteInput; + break; + default: + return kInvalidInput; + } - switch (WebPIAppend(idec, buffer, bytesRead)) { - case VP8_STATUS_OK: - return kSuccess; - case VP8_STATUS_SUSPENDED: - // Break out of the switch statement. Continue the loop. - break; - default: - return kInvalidInput; + if (colorXform) { + SkColorSpaceXform::ColorFormat dstColorFormat = select_xform_format(dstInfo.colorType()); + SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), + this->getInfo().alphaType()); + + uint32_t* src = (uint32_t*) config.output.u.RGBA.rgba; + size_t srcRowBytes = config.output.u.RGBA.stride; + for (int y = 0; y < rowsDecoded; y++) { + colorXform->apply(dst, src, dstInfo.width(), dstColorFormat, + SkColorSpaceXform::kBGRA_8888_ColorFormat, xformAlphaType); + dst = SkTAddOffset(dst, rowBytes); + src = SkTAddOffset(src, srcRowBytes); } } + + return result; } -SkWebpCodec::SkWebpCodec(const SkImageInfo& info, SkStream* stream) - // The spec says an unmarked image is sRGB, so we return that space here. - // TODO: Add support for parsing ICC profiles from webps. - : INHERITED(info, stream, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)) {} +SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info, + sk_sp colorSpace, SkStream* stream, WebPDemuxer* demux, + sk_sp data) + : INHERITED(width, height, info, stream, std::move(colorSpace)) + , fDemux(demux) + , fData(std::move(data)) +{} diff --git a/gfx/skia/skia/src/codec/SkWebpCodec.h b/gfx/skia/skia/src/codec/SkWebpCodec.h index 2d81cf3d9cfa..b9c493f20468 100644 --- a/gfx/skia/skia/src/codec/SkWebpCodec.h +++ b/gfx/skia/skia/src/codec/SkWebpCodec.h @@ -15,6 +15,10 @@ #include "SkTypes.h" class SkStream; +extern "C" { + struct WebPDemuxer; + void WebPDemuxDelete(WebPDemuxer* dmux); +} static const size_t WEBP_VP8_HEADER_SIZE = 30; @@ -34,7 +38,14 @@ protected: bool onGetValidSubset(SkIRect* /* desiredSubset */) const override; private: - SkWebpCodec(const SkImageInfo&, SkStream*); + SkWebpCodec(int width, int height, const SkEncodedInfo&, sk_sp, SkStream*, + WebPDemuxer*, sk_sp); + + SkAutoTCallVProc fDemux; + + // fDemux has a pointer into this data. + // This should not be freed until the decode is completed. + sk_sp fData; typedef SkCodec INHERITED; }; diff --git a/gfx/skia/skia/src/core/SkAAClip.cpp b/gfx/skia/skia/src/core/SkAAClip.cpp index f71d7b61d237..088ee5584447 100644 --- a/gfx/skia/skia/src/core/SkAAClip.cpp +++ b/gfx/skia/skia/src/core/SkAAClip.cpp @@ -191,6 +191,7 @@ void SkAAClip::validate() const { SkASSERT(fBounds.isEmpty()); return; } + SkASSERT(!fBounds.isEmpty()); const RunHead* head = fRunHead; SkASSERT(head->fRefCnt > 0); diff --git a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.cpp b/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.cpp deleted file mode 100644 index ce2c15b3458a..000000000000 --- a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#include "SkAdvancedTypefaceMetrics.h" -#include "SkTypes.h" - -#if defined(SK_BUILD_FOR_WIN) -#include -#endif - -// forward declare structs needed for getAdvanceData() template for freetype -struct FT_FaceRec_; -typedef struct FT_FaceRec_* FT_Face; - -#ifdef SK_BUILD_FOR_MAC -#import -#endif - -#ifdef SK_BUILD_FOR_IOS -#include -#include -#include -#endif - -namespace skia_advanced_typeface_metrics_utils { - -const int16_t kInvalidAdvance = SK_MinS16; -const int16_t kDontCareAdvance = SK_MinS16 + 1; - -template -void stripUninterestingTrailingAdvancesFromRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range) { - SkASSERT(false); -} - -template <> -void stripUninterestingTrailingAdvancesFromRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range) { - SkASSERT(range); - - int expectedAdvanceCount = range->fEndId - range->fStartId + 1; - if (range->fAdvance.count() < expectedAdvanceCount) { - return; - } - - for (int i = expectedAdvanceCount - 1; i >= 0; --i) { - if (range->fAdvance[i] != kDontCareAdvance && - range->fAdvance[i] != kInvalidAdvance && - range->fAdvance[i] != 0) { - range->fEndId = range->fStartId + i; - break; - } - } -} - -template -void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric* range, - int startId) { - range->fStartId = startId; - range->fAdvance.setCount(0); -} - -template class AutoTDelete> -SkAdvancedTypefaceMetrics::AdvanceMetric* appendRange( - AutoTDelete >* nextSlot, - int startId) { - nextSlot->reset(new SkAdvancedTypefaceMetrics::AdvanceMetric); - resetRange(nextSlot->get(), startId); - return nextSlot->get(); -} - -template -void zeroWildcardsInRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range) { - SkASSERT(false); -} - -template <> -void zeroWildcardsInRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range) { - SkASSERT(range); - if (range->fType != SkAdvancedTypefaceMetrics::WidthRange::kRange) { - return; - } - SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1); - - // Zero out wildcards. - for (int i = 0; i < range->fAdvance.count(); ++i) { - if (range->fAdvance[i] == kDontCareAdvance) { - range->fAdvance[i] = 0; - } - } -} - -template -void finishRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range, - int endId, - typename SkAdvancedTypefaceMetrics::AdvanceMetric::MetricType - type) { - range->fEndId = endId; - range->fType = type; - stripUninterestingTrailingAdvancesFromRange(range); - int newLength; - if (type == SkAdvancedTypefaceMetrics::AdvanceMetric::kRange) { - newLength = range->fEndId - range->fStartId + 1; - } else { - if (range->fEndId == range->fStartId) { - range->fType = - SkAdvancedTypefaceMetrics::AdvanceMetric::kRange; - } - newLength = 1; - } - SkASSERT(range->fAdvance.count() >= newLength); - range->fAdvance.setCount(newLength); - zeroWildcardsInRange(range); -} - -template -SkAdvancedTypefaceMetrics::AdvanceMetric* getAdvanceData( - FontHandle fontHandle, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)) { - // Assuming that on average, the ASCII representation of an advance plus - // a space is 8 characters and the ASCII representation of a glyph id is 3 - // characters, then the following cut offs for using different range types - // apply: - // The cost of stopping and starting the range is 7 characers - // a. Removing 4 0's or don't care's is a win - // The cost of stopping and starting the range plus a run is 22 - // characters - // b. Removing 3 repeating advances is a win - // c. Removing 2 repeating advances and 3 don't cares is a win - // When not currently in a range the cost of a run over a range is 16 - // characaters, so: - // d. Removing a leading 0/don't cares is a win because it is omitted - // e. Removing 2 repeating advances is a win - - SkAutoTDelete > result; - SkAdvancedTypefaceMetrics::AdvanceMetric* curRange; - SkAdvancedTypefaceMetrics::AdvanceMetric* prevRange = nullptr; - Data lastAdvance = kInvalidAdvance; - int repeatedAdvances = 0; - int wildCardsInRun = 0; - int trailingWildCards = 0; - uint32_t subsetIndex = 0; - - // Limit the loop count to glyph id ranges provided. - int firstIndex = 0; - int lastIndex = num_glyphs; - if (subsetGlyphIDs) { - firstIndex = static_cast(subsetGlyphIDs[0]); - lastIndex = - static_cast(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1; - } - curRange = appendRange(&result, firstIndex); - - for (int gId = firstIndex; gId <= lastIndex; gId++) { - Data advance = kInvalidAdvance; - if (gId < lastIndex) { - // Get glyph id only when subset is nullptr, or the id is in subset. - SkASSERT(!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength && - static_cast(gId) <= subsetGlyphIDs[subsetIndex])); - if (!subsetGlyphIDs || - (subsetIndex < subsetGlyphIDsLength && - static_cast(gId) == subsetGlyphIDs[subsetIndex])) { - SkAssertResult(getAdvance(fontHandle, gId, &advance)); - ++subsetIndex; - } else { - advance = kDontCareAdvance; - } - } - if (advance == lastAdvance) { - repeatedAdvances++; - trailingWildCards = 0; - } else if (advance == kDontCareAdvance) { - wildCardsInRun++; - trailingWildCards++; - } else if (curRange->fAdvance.count() == - repeatedAdvances + 1 + wildCardsInRun) { // All in run. - if (lastAdvance == 0) { - resetRange(curRange, gId); - trailingWildCards = 0; - } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { - finishRange(curRange, gId - 1, - SkAdvancedTypefaceMetrics::WidthRange::kRun); - prevRange = curRange; - curRange = appendRange(&curRange->fNext, gId); - trailingWildCards = 0; - } - repeatedAdvances = 0; - wildCardsInRun = trailingWildCards; - trailingWildCards = 0; - } else { - if (lastAdvance == 0 && - repeatedAdvances + 1 + wildCardsInRun >= 4) { - finishRange(curRange, - gId - repeatedAdvances - wildCardsInRun - 2, - SkAdvancedTypefaceMetrics::WidthRange::kRange); - prevRange = curRange; - curRange = appendRange(&curRange->fNext, gId); - trailingWildCards = 0; - } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { - finishRange(curRange, - gId - trailingWildCards - 1, - SkAdvancedTypefaceMetrics::WidthRange::kRange); - prevRange = curRange; - curRange = appendRange(&curRange->fNext, gId); - trailingWildCards = 0; - } else if (lastAdvance != 0 && - (repeatedAdvances + 1 >= 3 || - (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { - finishRange(curRange, - gId - repeatedAdvances - wildCardsInRun - 2, - SkAdvancedTypefaceMetrics::WidthRange::kRange); - curRange = - appendRange(&curRange->fNext, - gId - repeatedAdvances - wildCardsInRun - 1); - curRange->fAdvance.append(1, &lastAdvance); - finishRange(curRange, gId - 1, - SkAdvancedTypefaceMetrics::WidthRange::kRun); - prevRange = curRange; - curRange = appendRange(&curRange->fNext, gId); - trailingWildCards = 0; - } - repeatedAdvances = 0; - wildCardsInRun = trailingWildCards; - trailingWildCards = 0; - } - curRange->fAdvance.append(1, &advance); - if (advance != kDontCareAdvance) { - lastAdvance = advance; - } - } - if (curRange->fStartId == lastIndex) { - SkASSERT(prevRange); - SkASSERT(prevRange->fNext->fStartId == lastIndex); - prevRange->fNext.reset(); - } else { - finishRange(curRange, lastIndex - 1, - SkAdvancedTypefaceMetrics::WidthRange::kRange); - } - return result.release(); -} - -// Make AdvanceMetric template functions available for linking with typename -// WidthRange and VerticalAdvanceRange. -template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( - FT_Face face, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(FT_Face face, int gId, int16_t* data)); - -#if defined(SK_BUILD_FOR_WIN) -template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( - HDC hdc, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(HDC hdc, int gId, int16_t* data)); -template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( - IDWriteFontFace* fontFace, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data)); -#elif defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) -template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( - CTFontRef ctFont, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(CTFontRef ctFont, int gId, int16_t* data)); -#endif -template void resetRange( - SkAdvancedTypefaceMetrics::WidthRange* range, - int startId); -template SkAdvancedTypefaceMetrics::WidthRange* appendRange( - SkAutoTDelete* nextSlot, - int startId); -template void finishRange( - SkAdvancedTypefaceMetrics::WidthRange* range, - int endId, - SkAdvancedTypefaceMetrics::WidthRange::MetricType type); - -template void resetRange( - SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range, - int startId); -template SkAdvancedTypefaceMetrics::VerticalAdvanceRange* appendRange( - SkAutoTDelete* - nextSlot, - int startId); -template void finishRange( - SkAdvancedTypefaceMetrics::VerticalAdvanceRange* range, - int endId, - SkAdvancedTypefaceMetrics::VerticalAdvanceRange::MetricType type); - -// additional declaration needed for testing with a face of an unknown type -template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData( - void* fontData, - int num_glyphs, - const uint32_t* subsetGlyphIDs, - uint32_t subsetGlyphIDsLength, - bool (*getAdvance)(void* fontData, int gId, int16_t* data)); - -} // namespace skia_advanced_typeface_metrics_utils diff --git a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h b/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h index 329b7d13c107..17255ab217ab 100644 --- a/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h +++ b/gfx/skia/skia/src/core/SkAdvancedTypefaceMetrics.h @@ -5,43 +5,14 @@ * found in the LICENSE file. */ - #ifndef SkAdvancedTypefaceMetrics_DEFINED #define SkAdvancedTypefaceMetrics_DEFINED +#include "SkBitmaskEnum.h" #include "SkRect.h" #include "SkRefCnt.h" #include "SkString.h" #include "SkTDArray.h" -#include "SkTemplates.h" - -// Whatever std::unique_ptr Clank's using doesn't seem to work with AdvanceMetric's -// style of forward-declaration. Probably just a bug in an old libc++ / libstdc++. -// For now, hack around it with our own smart pointer. It'd be nice to clean up. -template -class SkHackyAutoTDelete : SkNoncopyable { -public: - explicit SkHackyAutoTDelete(T* ptr = nullptr) : fPtr(ptr) {} - ~SkHackyAutoTDelete() { delete fPtr; } - - T* get() const { return fPtr; } - T* operator->() const { return fPtr; } - - void reset(T* ptr = nullptr) { - if (ptr != fPtr) { - delete fPtr; - fPtr = ptr; - } - } - T* release() { - T* ptr = fPtr; - fPtr = nullptr; - return ptr; - } - -private: - T* fPtr; -}; /** \class SkAdvancedTypefaceMetrics @@ -49,16 +20,15 @@ private: embed typefaces. This class is created and filled in with information by SkTypeface::getAdvancedTypefaceMetrics. */ - class SkAdvancedTypefaceMetrics : public SkRefCnt { public: SkAdvancedTypefaceMetrics() : fType(SkAdvancedTypefaceMetrics::kOther_Font) - , fFlags(SkAdvancedTypefaceMetrics::kEmpty_FontFlag) + , fFlags((FontFlags)0) , fLastGlyphID(0) , fEmSize(0) - , fStyle(0) + , fStyle((StyleFlags)0) , fItalicAngle(0) , fAscent(0) , fDescent(0) @@ -66,9 +36,11 @@ public: , fCapHeight(0) , fBBox(SkIRect::MakeEmpty()) {} + ~SkAdvancedTypefaceMetrics() {} + SkString fFontName; - enum FontType { + enum FontType : uint8_t { kType1_Font, kType1CID_Font, kCFF_Font, @@ -80,29 +52,28 @@ public: // information will never be populated. FontType fType; - enum FontFlags { - kEmpty_FontFlag = 0x0, //! - struct AdvanceMetric { - enum MetricType { - kDefault, // Default advance: fAdvance.count = 1 - kRange, // Advances for a range: fAdvance.count = fEndID-fStartID - kRun // fStartID-fEndID have same advance: fAdvance.count = 1 - }; - MetricType fType; - uint16_t fStartId; - uint16_t fEndId; - SkTDArray fAdvance; - SkHackyAutoTDelete > fNext; - }; - - struct VerticalMetric { - int16_t fVerticalAdvance; - int16_t fOriginXDisp; // Horiz. displacement of the secondary origin. - int16_t fOriginYDisp; // Vert. displacement of the secondary origin. - }; - typedef AdvanceMetric WidthRange; - typedef AdvanceMetric VerticalAdvanceRange; - - // This is indexed by glyph id. - SkAutoTDelete fGlyphWidths; - // Only used for Vertical CID fonts. - SkAutoTDelete fVerticalMetrics; - // The names of each glyph, only populated for postscript fonts. - SkAutoTDelete > fGlyphNames; + SkTArray fGlyphNames; // The mapping from glyph to Unicode, only populated if // kToUnicode_PerGlyphInfo is passed to GetAdvancedTypefaceMetrics. @@ -151,41 +95,9 @@ private: typedef SkRefCnt INHERITED; }; -namespace skia_advanced_typeface_metrics_utils { - -template -void resetRange(SkAdvancedTypefaceMetrics::AdvanceMetric* range, - int startId); - -template class AutoTDelete> -SkAdvancedTypefaceMetrics::AdvanceMetric* appendRange( - AutoTDelete >* nextSlot, - int startId); - -template -void finishRange( - SkAdvancedTypefaceMetrics::AdvanceMetric* range, - int endId, - typename SkAdvancedTypefaceMetrics::AdvanceMetric::MetricType - type); - -/** Retrieve advance data for glyphs. Used by the PDF backend. It calls - underlying platform dependent API getAdvance to acquire the data. - @param num_glyphs Total number of glyphs in the given font. - @param glyphIDs For per-glyph info, specify subset of the font by - giving glyph ids. Each integer represents a glyph - id. Passing nullptr means all glyphs in the font. - @param glyphIDsCount Number of elements in subsetGlyphIds. Ignored if - glyphIDs is nullptr. -*/ -template -SkAdvancedTypefaceMetrics::AdvanceMetric* getAdvanceData( - FontHandle fontHandle, - int num_glyphs, - const uint32_t* glyphIDs, - uint32_t glyphIDsCount, - bool (*getAdvance)(FontHandle fontHandle, int gId, Data* data)); - -} // namespace skia_advanced_typeface_metrics_utils +namespace skstd { +template <> struct is_bitmask_enum : std::true_type {}; +template <> struct is_bitmask_enum : std::true_type {}; +} #endif diff --git a/gfx/skia/skia/src/core/SkBigPicture.cpp b/gfx/skia/skia/src/core/SkBigPicture.cpp index 70f68db337d0..2a2e438fd6a3 100644 --- a/gfx/skia/skia/src/core/SkBigPicture.cpp +++ b/gfx/skia/skia/src/core/SkBigPicture.cpp @@ -16,14 +16,12 @@ SkBigPicture::SkBigPicture(const SkRect& cull, SkRecord* record, SnapshotArray* drawablePicts, SkBBoxHierarchy* bbh, - AccelData* accelData, size_t approxBytesUsedBySubPictures) : fCullRect(cull) , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures) , fRecord(record) // Take ownership of caller's ref. , fDrawablePicts(drawablePicts) // Take ownership. , fBBH(bbh) // Take ownership of caller's ref. - , fAccelData(accelData) // Take ownership of caller's ref. {} void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const { @@ -58,11 +56,11 @@ void SkBigPicture::partialPlayback(SkCanvas* canvas, } const SkBigPicture::Analysis& SkBigPicture::analysis() const { - return *fAnalysis.get([&]{ return new Analysis(*fRecord); }); + fAnalysisOnce([this] { fAnalysis.init(*fRecord); }); + return fAnalysis; } SkRect SkBigPicture::cullRect() const { return fCullRect; } -bool SkBigPicture::hasText() const { return this->analysis().fHasText; } bool SkBigPicture::willPlayBackBitmaps() const { return this->analysis().fWillPlaybackBitmaps; } int SkBigPicture::numSlowPaths() const { return this->analysis().fNumSlowPathsAndDashEffects; } int SkBigPicture::approximateOpCount() const { return fRecord->count(); } @@ -80,20 +78,17 @@ SkPicture const* const* SkBigPicture::drawablePicts() const { return fDrawablePicts ? fDrawablePicts->begin() : nullptr; } -SkBigPicture::Analysis::Analysis(const SkRecord& record) { - TRACE_EVENT0("disabled-by-default-skia", "SkBigPicture::Analysis::Analysis()"); - SkTextHunter text; +void SkBigPicture::Analysis::init(const SkRecord& record) { + TRACE_EVENT0("disabled-by-default-skia", "SkBigPicture::Analysis::init()"); SkBitmapHunter bitmap; SkPathCounter path; - bool hasText = false, hasBitmap = false; + bool hasBitmap = false; for (int i = 0; i < record.count(); i++) { - hasText = hasText || record.visit(i, text); hasBitmap = hasBitmap || record.visit(i, bitmap); record.visit(i, path); } - fHasText = hasText; fWillPlaybackBitmaps = hasBitmap; fNumSlowPathsAndDashEffects = SkTMin(path.fNumSlowPathsAndDashEffects, 255); } diff --git a/gfx/skia/skia/src/core/SkBigPicture.h b/gfx/skia/skia/src/core/SkBigPicture.h index 0834709f8a62..c5dfda95eb56 100644 --- a/gfx/skia/skia/src/core/SkBigPicture.h +++ b/gfx/skia/skia/src/core/SkBigPicture.h @@ -8,7 +8,7 @@ #ifndef SkBigPicture_DEFINED #define SkBigPicture_DEFINED -#include "SkOncePtr.h" +#include "SkOnce.h" #include "SkPicture.h" #include "SkRect.h" #include "SkTemplates.h" @@ -20,9 +20,6 @@ class SkRecord; // An implementation of SkPicture supporting an arbitrary number of drawing commands. class SkBigPicture final : public SkPicture { public: - // AccelData provides a base class for device-specific acceleration data. - class AccelData : public SkRefCnt { }; - // An array of refcounted const SkPicture pointers. class SnapshotArray : ::SkNoncopyable { public: @@ -40,14 +37,12 @@ public: SkRecord*, // We take ownership of the caller's ref. SnapshotArray*, // We take exclusive ownership. SkBBoxHierarchy*, // We take ownership of the caller's ref. - AccelData*, // We take ownership of the caller's ref. size_t approxBytesUsedBySubPictures); // SkPicture overrides void playback(SkCanvas*, AbortCallback*) const override; SkRect cullRect() const override; - bool hasText() const override; bool willPlayBackBitmaps() const override; int approximateOpCount() const override; size_t approximateBytesUsed() const override; @@ -61,17 +56,15 @@ public: // Used by GrRecordReplaceDraw const SkBBoxHierarchy* bbh() const { return fBBH; } const SkRecord* record() const { return fRecord; } - const AccelData* accelData() const { return fAccelData; } private: struct Analysis { - explicit Analysis(const SkRecord&); + void init(const SkRecord&); bool suitableForGpuRasterization(const char** reason) const; uint8_t fNumSlowPathsAndDashEffects; bool fWillPlaybackBitmaps : 1; - bool fHasText : 1; }; int numSlowPaths() const override; @@ -81,11 +74,11 @@ private: const SkRect fCullRect; const size_t fApproxBytesUsedBySubPictures; - SkOncePtr fAnalysis; + mutable SkOnce fAnalysisOnce; + mutable Analysis fAnalysis; SkAutoTUnref fRecord; SkAutoTDelete fDrawablePicts; SkAutoTUnref fBBH; - SkAutoTUnref fAccelData; }; #endif//SkBigPicture_DEFINED diff --git a/gfx/skia/skia/src/core/SkBitmap.cpp b/gfx/skia/skia/src/core/SkBitmap.cpp index 7e8e62e88b2c..c62f5f391b47 100644 --- a/gfx/skia/skia/src/core/SkBitmap.cpp +++ b/gfx/skia/skia/src/core/SkBitmap.cpp @@ -8,6 +8,7 @@ #include "SkAtomics.h" #include "SkBitmap.h" #include "SkColorPriv.h" +#include "SkConfig8888.h" #include "SkData.h" #include "SkFilterQuality.h" #include "SkMallocPixelRef.h" @@ -49,25 +50,22 @@ SkBitmap::~SkBitmap() { SkBitmap& SkBitmap::operator=(const SkBitmap& src) { if (this != &src) { this->freePixels(); - memcpy(this, &src, sizeof(src)); - - // inc src reference counts - SkSafeRef(src.fPixelRef); - - // we reset our locks if we get blown away - fPixelLockCount = 0; - - if (fPixelRef) { - // ignore the values from the memcpy - fPixels = nullptr; - fColorTable = nullptr; - // Note that what to for genID is somewhat arbitrary. We have no - // way to track changes to raw pixels across multiple SkBitmaps. - // Would benefit from an SkRawPixelRef type created by - // setPixels. - // Just leave the memcpy'ed one but they'll get out of sync - // as soon either is modified. + this->fPixelRef = SkSafeRef(src.fPixelRef); + if (this->fPixelRef) { + // ignore the values if we have a pixelRef + this->fPixels = nullptr; + this->fColorTable = nullptr; + } else { + this->fPixels = src.fPixels; + this->fColorTable = src.fColorTable; } + // we reset our locks if we get blown away + this->fPixelLockCount = 0; + + this->fPixelRefOrigin = src.fPixelRefOrigin; + this->fInfo = src.fInfo; + this->fRowBytes = src.fRowBytes; + this->fFlags = src.fFlags; } SkDEBUGCODE(this->validate();) @@ -97,6 +95,7 @@ void SkBitmap::swap(SkBitmap& other) { void SkBitmap::reset() { this->freePixels(); + this->fInfo.reset(); sk_bzero(this, sizeof(*this)); } @@ -426,10 +425,6 @@ void SkBitmap::notifyPixelsChanged() const { } } -GrTexture* SkBitmap::getTexture() const { - return fPixelRef ? fPixelRef->getTexture() : nullptr; -} - /////////////////////////////////////////////////////////////////////////////// /** We explicitly use the same allocator for our pixels that SkMask does, @@ -541,6 +536,9 @@ void* SkBitmap::getAddr(int x, int y) const { if (base) { base += y * this->rowBytes(); switch (this->colorType()) { + case kRGBA_F16_SkColorType: + base += x << 3; + break; case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: base += x << 2; @@ -603,7 +601,7 @@ SkColor SkBitmap::getColor(int x, int y) const { } case kRGBA_F16_SkColorType: { const uint64_t* addr = (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; - Sk4f p4 = SkHalfToFloat_01(addr[0]); + Sk4f p4 = SkHalfToFloat_finite_ftz(addr[0]); if (p4[3]) { float inva = 1 / p4[3]; p4 = p4 * Sk4f(inva, inva, inva, 1); @@ -742,29 +740,13 @@ bool SkBitmap::extractSubset(SkBitmap* result, const SkIRect& subset) const { return false; // r is empty (i.e. no intersection) } - if (fPixelRef->getTexture() != nullptr) { - // Do a deep copy - SkPixelRef* pixelRef = fPixelRef->deepCopy(this->colorType(), this->profileType(), &subset); - if (pixelRef != nullptr) { - SkBitmap dst; - dst.setInfo(SkImageInfo::Make(subset.width(), subset.height(), - this->colorType(), this->alphaType())); - dst.setIsVolatile(this->isVolatile()); - dst.setPixelRef(pixelRef)->unref(); - SkDEBUGCODE(dst.validate()); - result->swap(dst); - return true; - } - } - // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have // exited above. SkASSERT(static_cast(r.fLeft) < static_cast(this->width())); SkASSERT(static_cast(r.fTop) < static_cast(this->height())); SkBitmap dst; - dst.setInfo(SkImageInfo::Make(r.width(), r.height(), this->colorType(), this->alphaType()), - this->rowBytes()); + dst.setInfo(this->info().makeWH(r.width(), r.height()), this->rowBytes()); dst.setIsVolatile(this->isVolatile()); if (fPixelRef) { @@ -913,116 +895,33 @@ bool SkBitmap::copyTo(SkBitmap* dst, SkColorType dstColorType, Allocator* alloc) return true; } +// TODO: can we merge this with copyTo? bool SkBitmap::deepCopyTo(SkBitmap* dst) const { const SkColorType dstCT = this->colorType(); - const SkColorProfileType dstPT = this->profileType(); if (!this->canCopyTo(dstCT)) { return false; } - - // If we have a PixelRef, and it supports deep copy, use it. - // Currently supported only by texture-backed bitmaps. - if (fPixelRef) { - SkPixelRef* pixelRef = fPixelRef->deepCopy(dstCT, dstPT, nullptr); - if (pixelRef) { - uint32_t rowBytes; - if (this->colorType() == dstCT && this->profileType() == dstPT) { - // Since there is no subset to pass to deepCopy, and deepCopy - // succeeded, the new pixel ref must be identical. - SkASSERT(fPixelRef->info() == pixelRef->info()); - pixelRef->cloneGenID(*fPixelRef); - // Use the same rowBytes as the original. - rowBytes = fRowBytes; - } else { - // With the new config, an appropriate fRowBytes will be computed by setInfo. - rowBytes = 0; - } - - const SkImageInfo info = fInfo.makeColorType(dstCT); - if (!dst->setInfo(info, rowBytes)) { - return false; - } - dst->setPixelRef(pixelRef, fPixelRefOrigin)->unref(); - return true; - } - } - - if (this->getTexture()) { - return false; - } else { - return this->copyTo(dst, dstCT, nullptr); - } + return this->copyTo(dst, dstCT, nullptr); } /////////////////////////////////////////////////////////////////////////////// -static void rect_memset(uint8_t* array, U8CPU value, SkISize size, size_t rowBytes) { - for (int y = 0; y < size.height(); ++y) { - memset(array, value, size.width()); - array += rowBytes; - } -} - -static void get_bitmap_alpha(const SkPixmap& pmap, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { - SkColorType colorType = pmap.colorType(); - int w = pmap.width(); - int h = pmap.height(); - size_t rb = pmap.rowBytes(); - - if (kAlpha_8_SkColorType == colorType && !pmap.isOpaque()) { - const uint8_t* s = pmap.addr8(0, 0); - while (--h >= 0) { - memcpy(alpha, s, w); - s += rb; - alpha += alphaRowBytes; - } - } else if (kN32_SkColorType == colorType && !pmap.isOpaque()) { - const SkPMColor* SK_RESTRICT s = pmap.addr32(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkGetPackedA32(s[x]); - } - s = (const SkPMColor*)((const char*)s + rb); - alpha += alphaRowBytes; - } - } else if (kARGB_4444_SkColorType == colorType && !pmap.isOpaque()) { - const SkPMColor16* SK_RESTRICT s = pmap.addr16(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkPacked4444ToA32(s[x]); - } - s = (const SkPMColor16*)((const char*)s + rb); - alpha += alphaRowBytes; - } - } else if (kIndex_8_SkColorType == colorType && !pmap.isOpaque()) { - const SkColorTable* ct = pmap.ctable(); - if (ct) { - const SkPMColor* SK_RESTRICT table = ct->readColors(); - const uint8_t* SK_RESTRICT s = pmap.addr8(0, 0); - while (--h >= 0) { - for (int x = 0; x < w; x++) { - alpha[x] = SkGetPackedA32(table[s[x]]); - } - s += rb; - alpha += alphaRowBytes; - } - } - } else { // src is opaque, so just fill alpha[] with 0xFF - rect_memset(alpha, 0xFF, pmap.info().dimensions(), alphaRowBytes); - } -} - static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int alphaRowBytes) { SkASSERT(alpha != nullptr); SkASSERT(alphaRowBytes >= src.width()); SkAutoPixmapUnlock apl; if (!src.requestLock(&apl)) { - rect_memset(alpha, 0, src.info().dimensions(), alphaRowBytes); + for (int y = 0; y < src.height(); ++y) { + memset(alpha, 0, src.width()); + alpha += alphaRowBytes; + } return false; } - get_bitmap_alpha(apl.pixmap(), alpha, alphaRowBytes); + const SkPixmap& pmap = apl.pixmap(); + SkPixelInfo::CopyPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes, + pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable()); return true; } @@ -1149,8 +1048,10 @@ bool SkBitmap::ReadRawPixels(SkReadBuffer* buffer, SkBitmap* bitmap) { SkImageInfo info; info.unflatten(*buffer); - // If there was an error reading "info", don't use it to compute minRowBytes() - if (!buffer->validate(true)) { + // If there was an error reading "info" or if it is bogus, + // don't use it to compute minRowBytes() + if (!buffer->validate(SkColorTypeValidateAlphaType(info.colorType(), + info.alphaType()))) { return false; } diff --git a/gfx/skia/skia/src/core/SkBitmapCache.cpp b/gfx/skia/skia/src/core/SkBitmapCache.cpp index 83eec1b666b7..153a24748b81 100644 --- a/gfx/skia/skia/src/core/SkBitmapCache.cpp +++ b/gfx/skia/skia/src/core/SkBitmapCache.cpp @@ -230,18 +230,21 @@ static unsigned gMipMapKeyNamespaceLabel; struct MipMapKey : public SkResourceCache::Key { public: - MipMapKey(uint32_t genID, const SkIRect& bounds) : fGenID(genID), fBounds(bounds) { + MipMapKey(uint32_t genID, SkSourceGammaTreatment treatment, const SkIRect& bounds) + : fGenID(genID), fSrcGammaTreatment(static_cast(treatment)), fBounds(bounds) + { this->init(&gMipMapKeyNamespaceLabel, SkMakeResourceCacheSharedIDForBitmap(genID), - sizeof(fGenID) + sizeof(fBounds)); + sizeof(fGenID) + sizeof(fSrcGammaTreatment) + sizeof(fBounds)); } uint32_t fGenID; + uint32_t fSrcGammaTreatment; SkIRect fBounds; }; struct MipMapRec : public SkResourceCache::Rec { - MipMapRec(const SkBitmap& src, const SkMipMap* result) - : fKey(src.getGenerationID(), get_bounds_from_bitmap(src)) + MipMapRec(const SkBitmap& src, SkSourceGammaTreatment treatment, const SkMipMap* result) + : fKey(src.getGenerationID(), treatment, get_bounds_from_bitmap(src)) , fMipMap(result) { fMipMap->attachToCacheAndRef(); @@ -279,9 +282,10 @@ private: } const SkMipMap* SkMipMapCache::FindAndRef(const SkBitmapCacheDesc& desc, + SkSourceGammaTreatment treatment, SkResourceCache* localCache) { // Note: we ignore width/height from desc, just need id and bounds - MipMapKey key(desc.fImageID, desc.fBounds); + MipMapKey key(desc.fImageID, treatment, desc.fBounds); const SkMipMap* result; if (!CHECK_LOCAL(localCache, find, Find, key, MipMapRec::Finder, &result)) { @@ -295,10 +299,11 @@ static SkResourceCache::DiscardableFactory get_fact(SkResourceCache* localCache) : SkResourceCache::GetDiscardableFactory(); } -const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkResourceCache* localCache) { - SkMipMap* mipmap = SkMipMap::Build(src, get_fact(localCache)); +const SkMipMap* SkMipMapCache::AddAndRef(const SkBitmap& src, SkSourceGammaTreatment treatment, + SkResourceCache* localCache) { + SkMipMap* mipmap = SkMipMap::Build(src, treatment, get_fact(localCache)); if (mipmap) { - MipMapRec* rec = new MipMapRec(src, mipmap); + MipMapRec* rec = new MipMapRec(src, treatment, mipmap); CHECK_LOCAL(localCache, add, Add, rec); src.pixelRef()->notifyAddedToCache(); } diff --git a/gfx/skia/skia/src/core/SkBitmapCache.h b/gfx/skia/skia/src/core/SkBitmapCache.h index 9371e77ca99f..76bcef06cf13 100644 --- a/gfx/skia/skia/src/core/SkBitmapCache.h +++ b/gfx/skia/skia/src/core/SkBitmapCache.h @@ -8,12 +8,11 @@ #ifndef SkBitmapCache_DEFINED #define SkBitmapCache_DEFINED -#include "SkScalar.h" #include "SkBitmap.h" +#include "SkMipMap.h" class SkImage; class SkResourceCache; -class SkMipMap; uint64_t SkMakeResourceCacheSharedIDForBitmap(uint32_t bitmapGenID); @@ -73,9 +72,10 @@ public: class SkMipMapCache { public: - static const SkMipMap* FindAndRef(const SkBitmapCacheDesc&, + static const SkMipMap* FindAndRef(const SkBitmapCacheDesc&, SkSourceGammaTreatment, SkResourceCache* localCache = nullptr); - static const SkMipMap* AddAndRef(const SkBitmap& src, SkResourceCache* localCache = nullptr); + static const SkMipMap* AddAndRef(const SkBitmap& src, SkSourceGammaTreatment, + SkResourceCache* localCache = nullptr); }; #endif diff --git a/gfx/skia/skia/src/core/SkBitmapController.cpp b/gfx/skia/skia/src/core/SkBitmapController.cpp index ac1029db8131..f4ee0fb6c1b8 100644 --- a/gfx/skia/skia/src/core/SkBitmapController.cpp +++ b/gfx/skia/skia/src/core/SkBitmapController.cpp @@ -44,10 +44,12 @@ SkBitmapController::State* SkBitmapController::requestBitmap(const SkBitmapProvi class SkDefaultBitmapControllerState : public SkBitmapController::State { public: - SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality); + SkDefaultBitmapControllerState(const SkBitmapProvider&, const SkMatrix& inv, SkFilterQuality, + SkSourceGammaTreatment); private: SkBitmap fResultBitmap; + SkSourceGammaTreatment fSrcGammaTreatment; SkAutoTUnref fCurrMip; bool processHQRequest(const SkBitmapProvider&); @@ -164,13 +166,13 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider } if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) { - fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc())); + fCurrMip.reset(SkMipMapCache::FindAndRef(provider.makeCacheDesc(), fSrcGammaTreatment)); if (nullptr == fCurrMip.get()) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; } - fCurrMip.reset(SkMipMapCache::AddAndRef(orig)); + fCurrMip.reset(SkMipMapCache::AddAndRef(orig, fSrcGammaTreatment)); if (nullptr == fCurrMip.get()) { return false; } @@ -200,9 +202,11 @@ bool SkDefaultBitmapControllerState::processMediumRequest(const SkBitmapProvider SkDefaultBitmapControllerState::SkDefaultBitmapControllerState(const SkBitmapProvider& provider, const SkMatrix& inv, - SkFilterQuality qual) { + SkFilterQuality qual, + SkSourceGammaTreatment treatment) { fInvMatrix = inv; fQuality = qual; + fSrcGammaTreatment = treatment; if (this->processHQRequest(provider) || this->processMediumRequest(provider)) { SkASSERT(fResultBitmap.getPixels()); @@ -223,5 +227,6 @@ SkBitmapController::State* SkDefaultBitmapController::onRequestBitmap(const SkBi const SkMatrix& inverse, SkFilterQuality quality, void* storage, size_t size) { - return SkInPlaceNewCheck(storage, size, bm, inverse, quality); + return SkInPlaceNewCheck(storage, size, bm, inverse, quality, + fSrcGammaTreatment); } diff --git a/gfx/skia/skia/src/core/SkBitmapController.h b/gfx/skia/skia/src/core/SkBitmapController.h index 86b8755ec185..f31c8eef5561 100644 --- a/gfx/skia/skia/src/core/SkBitmapController.h +++ b/gfx/skia/skia/src/core/SkBitmapController.h @@ -53,13 +53,18 @@ protected: /////////////////////////////////////////////////////////////////////////////////////////////////// +#include "SkMipMap.h" + class SkDefaultBitmapController : public SkBitmapController { public: - SkDefaultBitmapController() {} + SkDefaultBitmapController(SkSourceGammaTreatment treatment) : fSrcGammaTreatment(treatment) {} protected: State* onRequestBitmap(const SkBitmapProvider&, const SkMatrix& inverse, SkFilterQuality, void* storage, size_t storageSize) override; + +private: + const SkSourceGammaTreatment fSrcGammaTreatment; }; #endif diff --git a/gfx/skia/skia/src/core/SkBitmapDevice.cpp b/gfx/skia/skia/src/core/SkBitmapDevice.cpp index c8ac8d2d44f2..26d253cf38da 100644 --- a/gfx/skia/skia/src/core/SkBitmapDevice.cpp +++ b/gfx/skia/skia/src/core/SkBitmapDevice.cpp @@ -8,13 +8,17 @@ #include "SkBitmapDevice.h" #include "SkConfig8888.h" #include "SkDraw.h" +#include "SkImageFilter.h" +#include "SkImageFilterCache.h" #include "SkMallocPixelRef.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkPath.h" #include "SkPixelRef.h" #include "SkPixmap.h" +#include "SkRasterClip.h" #include "SkShader.h" +#include "SkSpecialImage.h" #include "SkSurface.h" #include "SkXfermode.h" @@ -65,9 +69,11 @@ static bool valid_for_bitmap_device(const SkImageInfo& info, } SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) - : INHERITED(SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)) - , fBitmap(bitmap) { + : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)) + , fBitmap(bitmap) +{ SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); + fBitmap.lockPixels(); } SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) { @@ -75,9 +81,11 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) { } SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps) - : INHERITED(surfaceProps) - , fBitmap(bitmap) { + : INHERITED(bitmap.info(), surfaceProps) + , fBitmap(bitmap) +{ SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); + fBitmap.lockPixels(); } SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, @@ -112,13 +120,10 @@ SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, return new SkBitmapDevice(bitmap, surfaceProps); } -SkImageInfo SkBitmapDevice::imageInfo() const { - return fBitmap.info(); -} - void SkBitmapDevice::setNewSize(const SkISize& size) { SkASSERT(!fBitmap.pixelRef()); fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight)); + this->privateResize(fBitmap.info().width(), fBitmap.info().height()); } void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { @@ -126,6 +131,7 @@ void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { SkASSERT(bm.height() == fBitmap.height()); fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) fBitmap.lockPixels(); + this->privateResize(fBitmap.info().width(), fBitmap.info().height()); } SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { @@ -138,7 +144,7 @@ const SkBitmap& SkBitmapDevice::onAccessBitmap() { } bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) { - if (fBitmap.lockPixelsAreWritable() && this->onPeekPixels(pmap)) { + if (this->onPeekPixels(pmap)) { fBitmap.notifyPixelsChanged(); return true; } @@ -179,20 +185,6 @@ bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, s return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y); } -void SkBitmapDevice::onAttachToCanvas(SkCanvas* canvas) { - INHERITED::onAttachToCanvas(canvas); - if (fBitmap.lockPixelsAreWritable()) { - fBitmap.lockPixels(); - } -} - -void SkBitmapDevice::onDetachFromCanvas() { - INHERITED::onDetachFromCanvas(); - if (fBitmap.lockPixelsAreWritable()) { - fBitmap.unlockPixels(); - } -} - /////////////////////////////////////////////////////////////////////////////// void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { @@ -237,9 +229,19 @@ void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) { + LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); draw.drawBitmap(bitmap, matrix, nullptr, paint); } +static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { + if (!paint.getMaskFilter()) { + return true; + } + + // Some mask filters parameters (sigma) depend on the CTM/scale. + return m.getType() <= SkMatrix::kTranslate_Mask; +} + void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { @@ -257,6 +259,8 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, } matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); + LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); + const SkRect* dstPtr = &dst; const SkBitmap* bitmapPtr = &bitmap; @@ -271,18 +275,23 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, matrix.mapRect(&tmpDst, tmpSrc); dstPtr = &tmpDst; } + } + if (src && !src->contains(bitmapBounds) && + SkCanvas::kFast_SrcRectConstraint == constraint && + paint.getFilterQuality() != kNone_SkFilterQuality) { + // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know + // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, + // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). + goto USE_SHADER; + } + + if (src) { // since we may need to clamp to the borders of the src rect within // the bitmap, we extract a subset. const SkIRect srcIR = tmpSrc.roundOut(); - if(bitmap.pixelRef()->getTexture()) { - // Accelerated source canvas, don't use extractSubset but readPixels to get the subset. - // This way, the pixels are copied in CPU memory instead of GPU memory. - bitmap.pixelRef()->readPixels(&tmpBitmap, kN32_SkColorType, &srcIR); - } else { - if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { - return; - } + if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { + return; } bitmapPtr = &tmpBitmap; @@ -309,20 +318,30 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // We can go faster by just calling drawBitmap, which will concat the // matrix with the CTM, and try to call drawSprite if it can. If not, // it will make a shader and call drawRect, as we do below. - draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); - return; + if (CanApplyDstMatrixAsCTM(matrix, paint)) { + draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); + return; + } } + USE_SHADER: + + // Since the shader need only live for our stack-frame, pass in a custom allocator. This + // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap + // if its mutable, since that precaution is not needed (give the short lifetime of the shader). + SkTBlitterAllocator allocator; // construct a shader, so we can call drawRect with the dst - auto s = SkShader::MakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, &matrix); + auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, + &matrix, kNever_SkCopyPixelsMode, &allocator); if (!s) { return; } + // we deliberately add a ref, since the allocator wants to be the last owner + s.get()->ref(); SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); - paintWithShader.setShader(std::move(s)); + paintWithShader.setShader(s); // Call ourself, in case the subclass wanted to share this setup code // but handle the drawRect code themselves. @@ -357,15 +376,64 @@ void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, int x, int y, const SkPaint& paint) { + SkASSERT(!paint.getImageFilter()); draw.drawSprite(static_cast(device)->fBitmap, x, y, paint); } +/////////////////////////////////////////////////////////////////////////////// + +void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, + const SkPaint& paint) { + SkASSERT(!srcImg->isTextureBacked()); + + SkBitmap resultBM; + + SkImageFilter* filter = paint.getImageFilter(); + if (filter) { + SkIPoint offset = SkIPoint::Make(0, 0); + SkMatrix matrix = *draw.fMatrix; + matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); + const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); + SkAutoTUnref cache(this->getImageFilterCache()); + SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); + SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); + + sk_sp resultImg(filter->filterImage(srcImg, ctx, &offset)); + if (resultImg) { + SkPaint tmpUnfiltered(paint); + tmpUnfiltered.setImageFilter(nullptr); + if (resultImg->getROPixels(&resultBM)) { + this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); + } + } + } else { + if (srcImg->getROPixels(&resultBM)) { + this->drawSprite(draw, resultBM, x, y, paint); + } + } +} + +sk_sp SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { + return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); +} + +sk_sp SkBitmapDevice::makeSpecial(const SkImage* image) { + return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), + image->makeNonTextureImage()); +} + +sk_sp SkBitmapDevice::snapSpecial() { + return this->makeSpecial(fBitmap); +} + +/////////////////////////////////////////////////////////////////////////////// + sk_sp SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { return SkSurface::MakeRaster(info, &props); } -SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() { - SkImageFilter::Cache* cache = SkImageFilter::Cache::Get(); +SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { + SkImageFilterCache* cache = SkImageFilterCache::Get(); cache->ref(); return cache; } @@ -378,7 +446,7 @@ bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style || - !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) + !paint.isSrcOver()) { return true; } diff --git a/gfx/skia/skia/src/core/SkBitmapHeap.cpp b/gfx/skia/skia/src/core/SkBitmapHeap.cpp deleted file mode 100644 index 071647e13e18..000000000000 --- a/gfx/skia/skia/src/core/SkBitmapHeap.cpp +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkBitmapHeap.h" -#include "SkBitmap.h" -#include "SkTSearch.h" - -SkBitmapHeapEntry::SkBitmapHeapEntry() - : fSlot(-1) - , fRefCount(0) - , fBytesAllocated(0) { -} - -SkBitmapHeapEntry::~SkBitmapHeapEntry() { - SkASSERT(0 == fRefCount); -} - -void SkBitmapHeapEntry::addReferences(int count) { - if (0 == fRefCount) { - // If there are no current owners then the heap manager - // will be the only one able to modify it, so it does not - // need to be an atomic operation. - fRefCount = count; - } else { - sk_atomic_add(&fRefCount, count); - } -} - -/////////////////////////////////////////////////////////////////////////////// - -static bool operator<(const SkIPoint& a, const SkIPoint& b) { - return *(const int64_t*)&a < *(const int64_t*)&b; -} - -static bool operator>(const SkIPoint& a, const SkIPoint& b) { - return *(const int64_t*)&a > *(const int64_t*)&b; -} - -bool SkBitmapHeap::LookupEntry::Less(const SkBitmapHeap::LookupEntry& a, - const SkBitmapHeap::LookupEntry& b) { - if (a.fGenerationId < b.fGenerationId) { - return true; - } else if (a.fGenerationId > b.fGenerationId) { - return false; - } else if (a.fPixelOrigin < b.fPixelOrigin) { - return true; - } else if (a.fPixelOrigin > b.fPixelOrigin) { - return false; - } else if (a.fWidth < b.fWidth) { - return true; - } else if (a.fWidth > b.fWidth) { - return false; - } else if (a.fHeight < b.fHeight) { - return true; - } - return false; -} - -/////////////////////////////////////////////////////////////////////////////// - -SkBitmapHeap::SkBitmapHeap(int32_t preferredSize, int32_t ownerCount) - : INHERITED() - , fExternalStorage(nullptr) - , fMostRecentlyUsed(nullptr) - , fLeastRecentlyUsed(nullptr) - , fPreferredCount(preferredSize) - , fOwnerCount(ownerCount) - , fBytesAllocated(0) - , fDeferAddingOwners(false) { -} - -SkBitmapHeap::SkBitmapHeap(ExternalStorage* storage, int32_t preferredSize) - : INHERITED() - , fExternalStorage(storage) - , fMostRecentlyUsed(nullptr) - , fLeastRecentlyUsed(nullptr) - , fPreferredCount(preferredSize) - , fOwnerCount(IGNORE_OWNERS) - , fBytesAllocated(0) - , fDeferAddingOwners(false) { - SkSafeRef(storage); -} - -SkBitmapHeap::~SkBitmapHeap() { - SkDEBUGCODE( - for (int i = 0; i < fStorage.count(); i++) { - bool unused = false; - for (int j = 0; j < fUnusedSlots.count(); j++) { - if (fUnusedSlots[j] == fStorage[i]->fSlot) { - unused = true; - break; - } - } - if (!unused) { - fBytesAllocated -= fStorage[i]->fBytesAllocated; - } - } - fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry)); - ) - SkASSERT(0 == fBytesAllocated); - fStorage.deleteAll(); - SkSafeUnref(fExternalStorage); - fLookupTable.deleteAll(); -} - -void SkBitmapHeap::removeFromLRU(SkBitmapHeap::LookupEntry* entry) { - if (fMostRecentlyUsed == entry) { - fMostRecentlyUsed = entry->fLessRecentlyUsed; - if (nullptr == fMostRecentlyUsed) { - SkASSERT(fLeastRecentlyUsed == entry); - fLeastRecentlyUsed = nullptr; - } else { - fMostRecentlyUsed->fMoreRecentlyUsed = nullptr; - } - } else { - // Remove entry from its prior place, and make sure to cover the hole. - if (fLeastRecentlyUsed == entry) { - SkASSERT(entry->fMoreRecentlyUsed != nullptr); - fLeastRecentlyUsed = entry->fMoreRecentlyUsed; - } - // Since we have already considered the case where entry is the most recently used, it must - // have a more recently used at this point. - SkASSERT(entry->fMoreRecentlyUsed != nullptr); - entry->fMoreRecentlyUsed->fLessRecentlyUsed = entry->fLessRecentlyUsed; - - if (entry->fLessRecentlyUsed != nullptr) { - SkASSERT(fLeastRecentlyUsed != entry); - entry->fLessRecentlyUsed->fMoreRecentlyUsed = entry->fMoreRecentlyUsed; - } - } - entry->fMoreRecentlyUsed = nullptr; -} - -void SkBitmapHeap::appendToLRU(SkBitmapHeap::LookupEntry* entry) { - if (fMostRecentlyUsed != nullptr) { - SkASSERT(nullptr == fMostRecentlyUsed->fMoreRecentlyUsed); - fMostRecentlyUsed->fMoreRecentlyUsed = entry; - entry->fLessRecentlyUsed = fMostRecentlyUsed; - } - fMostRecentlyUsed = entry; - if (nullptr == fLeastRecentlyUsed) { - fLeastRecentlyUsed = entry; - } -} - -// iterate through our LRU cache and try to find an entry to evict -SkBitmapHeap::LookupEntry* SkBitmapHeap::findEntryToReplace(const SkBitmap& replacement) { - SkASSERT(fPreferredCount != UNLIMITED_SIZE); - SkASSERT(fStorage.count() >= fPreferredCount); - - SkBitmapHeap::LookupEntry* iter = fLeastRecentlyUsed; - while (iter != nullptr) { - SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot]; - if (heapEntry->fRefCount > 0) { - // If the least recently used bitmap has not been unreferenced - // by its owner, then according to our LRU specifications a more - // recently used one can not have used all its references yet either. - return nullptr; - } - if (replacement.getGenerationID() == iter->fGenerationId) { - // Do not replace a bitmap with a new one using the same - // pixel ref. Instead look for a different one that will - // potentially free up more space. - iter = iter->fMoreRecentlyUsed; - } else { - return iter; - } - } - return nullptr; -} - -size_t SkBitmapHeap::freeMemoryIfPossible(size_t bytesToFree) { - if (UNLIMITED_SIZE == fPreferredCount) { - return 0; - } - LookupEntry* iter = fLeastRecentlyUsed; - size_t origBytesAllocated = fBytesAllocated; - // Purge starting from LRU until a non-evictable bitmap is found or until - // everything is evicted. - while (iter != nullptr) { - SkBitmapHeapEntry* heapEntry = fStorage[iter->fStorageSlot]; - if (heapEntry->fRefCount > 0) { - break; - } - LookupEntry* next = iter->fMoreRecentlyUsed; - this->removeEntryFromLookupTable(iter); - // Free the pixel memory. removeEntryFromLookupTable already reduced - // fBytesAllocated properly. - heapEntry->fBitmap.reset(); - // Add to list of unused slots which can be reused in the future. - fUnusedSlots.push(heapEntry->fSlot); - iter = next; - if (origBytesAllocated - fBytesAllocated >= bytesToFree) { - break; - } - } - - if (fLeastRecentlyUsed != iter) { - // There was at least one eviction. - fLeastRecentlyUsed = iter; - if (nullptr == fLeastRecentlyUsed) { - // Everything was evicted - fMostRecentlyUsed = nullptr; - fBytesAllocated -= (fStorage.count() * sizeof(SkBitmapHeapEntry)); - fStorage.deleteAll(); - fUnusedSlots.reset(); - SkASSERT(0 == fBytesAllocated); - } else { - fLeastRecentlyUsed->fLessRecentlyUsed = nullptr; - } - } - - return origBytesAllocated - fBytesAllocated; -} - -int SkBitmapHeap::findInLookupTable(const LookupEntry& indexEntry, SkBitmapHeapEntry** entry) { - int index = SkTSearch( - (const LookupEntry**)fLookupTable.begin(), - fLookupTable.count(), - &indexEntry, sizeof(void*)); - - if (index < 0) { - // insert ourselves into the bitmapIndex - index = ~index; - *fLookupTable.insert(index) = new LookupEntry(indexEntry); - } else if (entry != nullptr) { - // populate the entry if needed - *entry = fStorage[fLookupTable[index]->fStorageSlot]; - } - - return index; -} - -bool SkBitmapHeap::copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap) { - SkASSERT(!fExternalStorage); - - // If the bitmap is mutable, we need to do a deep copy, since the - // caller may modify it afterwards. - if (originalBitmap.isImmutable()) { - copiedBitmap = originalBitmap; -// TODO if we have the pixel ref in the heap we could pass it here to avoid a potential deep copy -// else if (sharedPixelRef != nullptr) { -// copiedBitmap = orig; -// copiedBitmap.setPixelRef(sharedPixelRef, originalBitmap.pixelRefOffset()); - } else if (originalBitmap.empty()) { - copiedBitmap.reset(); - } else if (!originalBitmap.deepCopyTo(&copiedBitmap)) { - return false; - } - copiedBitmap.setImmutable(); - return true; -} - -int SkBitmapHeap::removeEntryFromLookupTable(LookupEntry* entry) { - // remove the bitmap index for the deleted entry - SkDEBUGCODE(int count = fLookupTable.count();) - int index = this->findInLookupTable(*entry, nullptr); - // Verify that findInLookupTable found an existing entry rather than adding - // a new entry to the lookup table. - SkASSERT(count == fLookupTable.count()); - fBytesAllocated -= fStorage[entry->fStorageSlot]->fBytesAllocated; - delete fLookupTable[index]; - fLookupTable.remove(index); - return index; -} - -int32_t SkBitmapHeap::insert(const SkBitmap& originalBitmap) { - SkBitmapHeapEntry* entry = nullptr; - int searchIndex = this->findInLookupTable(LookupEntry(originalBitmap), &entry); - - if (entry) { - // Already had a copy of the bitmap in the heap. - if (fOwnerCount != IGNORE_OWNERS) { - if (fDeferAddingOwners) { - *fDeferredEntries.append() = entry->fSlot; - } else { - entry->addReferences(fOwnerCount); - } - } - if (fPreferredCount != UNLIMITED_SIZE) { - LookupEntry* lookupEntry = fLookupTable[searchIndex]; - if (lookupEntry != fMostRecentlyUsed) { - this->removeFromLRU(lookupEntry); - this->appendToLRU(lookupEntry); - } - } - return entry->fSlot; - } - - // decide if we need to evict an existing heap entry or create a new one - if (fPreferredCount != UNLIMITED_SIZE && fStorage.count() >= fPreferredCount) { - // iterate through our LRU cache and try to find an entry to evict - LookupEntry* lookupEntry = this->findEntryToReplace(originalBitmap); - if (lookupEntry != nullptr) { - // we found an entry to evict - entry = fStorage[lookupEntry->fStorageSlot]; - // Remove it from the LRU. The new entry will be added to the LRU later. - this->removeFromLRU(lookupEntry); - int index = this->removeEntryFromLookupTable(lookupEntry); - - // update the current search index now that we have removed one - if (index < searchIndex) { - searchIndex--; - } - } - } - - // if we didn't have an entry yet we need to create one - if (!entry) { - if (fPreferredCount != UNLIMITED_SIZE && fUnusedSlots.count() > 0) { - int slot; - fUnusedSlots.pop(&slot); - entry = fStorage[slot]; - } else { - entry = new SkBitmapHeapEntry; - fStorage.append(1, &entry); - entry->fSlot = fStorage.count() - 1; - fBytesAllocated += sizeof(SkBitmapHeapEntry); - } - } - - // create a copy of the bitmap - bool copySucceeded; - if (fExternalStorage) { - copySucceeded = fExternalStorage->insert(originalBitmap, entry->fSlot); - } else { - copySucceeded = copyBitmap(originalBitmap, entry->fBitmap); - } - - // if the copy failed then we must abort - if (!copySucceeded) { - // delete the index - delete fLookupTable[searchIndex]; - fLookupTable.remove(searchIndex); - // If entry is the last slot in storage, it is safe to delete it. - if (fStorage.count() - 1 == entry->fSlot) { - // free the slot - fStorage.remove(entry->fSlot); - fBytesAllocated -= sizeof(SkBitmapHeapEntry); - delete entry; - } else { - fUnusedSlots.push(entry->fSlot); - } - return INVALID_SLOT; - } - - // update the index with the appropriate slot in the heap - fLookupTable[searchIndex]->fStorageSlot = entry->fSlot; - - // compute the space taken by this entry - // TODO if there is a shared pixel ref don't count it - // If the SkBitmap does not share an SkPixelRef with an SkBitmap already - // in the SharedHeap, also include the size of its pixels. - entry->fBytesAllocated = originalBitmap.getSize(); - - // add the bytes from this entry to the total count - fBytesAllocated += entry->fBytesAllocated; - - if (fOwnerCount != IGNORE_OWNERS) { - if (fDeferAddingOwners) { - *fDeferredEntries.append() = entry->fSlot; - } else { - entry->addReferences(fOwnerCount); - } - } - if (fPreferredCount != UNLIMITED_SIZE) { - this->appendToLRU(fLookupTable[searchIndex]); - } - return entry->fSlot; -} - -void SkBitmapHeap::deferAddingOwners() { - fDeferAddingOwners = true; -} - -void SkBitmapHeap::endAddingOwnersDeferral(bool add) { - if (add) { - for (int i = 0; i < fDeferredEntries.count(); i++) { - SkASSERT(fOwnerCount != IGNORE_OWNERS); - SkBitmapHeapEntry* heapEntry = this->getEntry(fDeferredEntries[i]); - SkASSERT(heapEntry != nullptr); - heapEntry->addReferences(fOwnerCount); - } - } - fDeferAddingOwners = false; - fDeferredEntries.reset(); -} diff --git a/gfx/skia/skia/src/core/SkBitmapHeap.h b/gfx/skia/skia/src/core/SkBitmapHeap.h deleted file mode 100644 index 22c31a0b0b18..000000000000 --- a/gfx/skia/skia/src/core/SkBitmapHeap.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 SkBitmapHeap_DEFINED -#define SkBitmapHeap_DEFINED - -#include "SkAtomics.h" -#include "SkBitmap.h" -#include "SkPoint.h" -#include "SkRefCnt.h" -#include "SkTDArray.h" -#include "SkTypes.h" - -/** - * SkBitmapHeapEntry provides users of SkBitmapHeap (using internal storage) with a means to... - * (1) get access a bitmap in the heap - * (2) indicate they are done with bitmap by releasing their reference (if they were an owner). - */ -class SkBitmapHeapEntry : SkNoncopyable { -public: - ~SkBitmapHeapEntry(); - - int32_t getSlot() { return fSlot; } - - SkBitmap* getBitmap() { return &fBitmap; } - - void releaseRef() { - sk_atomic_dec(&fRefCount); - } - -private: - SkBitmapHeapEntry(); - - void addReferences(int count); - - int32_t fSlot; - int32_t fRefCount; - - SkBitmap fBitmap; - // Keep track of the bytes allocated for this bitmap. When replacing the - // bitmap or removing this HeapEntry we know how much memory has been - // reclaimed. - size_t fBytesAllocated; - - friend class SkBitmapHeap; - friend class SkBitmapHeapTester; -}; - - -class SkBitmapHeapReader : public SkRefCnt { -public: - - - SkBitmapHeapReader() : INHERITED() {} - virtual SkBitmap* getBitmap(int32_t slot) const = 0; - virtual void releaseRef(int32_t slot) = 0; -private: - typedef SkRefCnt INHERITED; -}; - - -/** - * TODO: stores immutable bitmaps into a heap - */ -class SkBitmapHeap : public SkBitmapHeapReader { -public: - class ExternalStorage : public SkRefCnt { - public: - - - virtual bool insert(const SkBitmap& bitmap, int32_t slot) = 0; - - private: - typedef SkRefCnt INHERITED; - }; - - static const int32_t UNLIMITED_SIZE = -1; - static const int32_t IGNORE_OWNERS = -1; - static const int32_t INVALID_SLOT = -1; - - /** - * Constructs a heap that is responsible for allocating and managing its own storage. In the - * case where we choose to allow the heap to grow indefinitely (i.e. UNLIMITED_SIZE) we - * guarantee that once allocated in the heap a bitmap's index in the heap is immutable. - * Otherwise we guarantee the bitmaps placement in the heap until its owner count goes to zero. - * - * @param preferredSize Specifies the preferred maximum number of bitmaps to store. This is - * not a hard limit as it can grow larger if the number of bitmaps in the heap with active - * owners exceeds this limit. - * @param ownerCount The number of owners to assign to each inserted bitmap. NOTE: while a - * bitmap in the heap has a least one owner it can't be removed. - */ - SkBitmapHeap(int32_t preferredSize = UNLIMITED_SIZE, int32_t ownerCount = IGNORE_OWNERS); - - /** - * Constructs a heap that defers the responsibility of storing the bitmaps to an external - * function. This is especially useful if the bitmaps will be used in a separate process as the - * external storage can ensure the data is properly shuttled to the appropriate processes. - * - * Our LRU implementation assumes that inserts into the external storage are consumed in the - * order that they are inserted (i.e. SkPipe). This ensures that we don't need to query the - * external storage to see if a slot in the heap is eligible to be overwritten. - * - * @param externalStorage The class responsible for storing the bitmaps inserted into the heap - * @param heapSize The maximum size of the heap. Because of the sequential limitation imposed - * by our LRU implementation we can guarantee that the heap will never grow beyond this size. - */ - SkBitmapHeap(ExternalStorage* externalStorage, int32_t heapSize = UNLIMITED_SIZE); - - virtual ~SkBitmapHeap(); - - /** - * Retrieves the bitmap from the specified slot in the heap - * - * @return The bitmap located at that slot or nullptr if external storage is being used. - */ - SkBitmap* getBitmap(int32_t slot) const override { - SkASSERT(fExternalStorage == nullptr); - SkBitmapHeapEntry* entry = getEntry(slot); - if (entry) { - return &entry->fBitmap; - } - return nullptr; - } - - /** - * Retrieves the bitmap from the specified slot in the heap - * - * @return The bitmap located at that slot or nullptr if external storage is being used. - */ - void releaseRef(int32_t slot) override { - SkASSERT(fExternalStorage == nullptr); - if (fOwnerCount != IGNORE_OWNERS) { - SkBitmapHeapEntry* entry = getEntry(slot); - if (entry) { - entry->releaseRef(); - } - } - } - - /** - * Inserts a bitmap into the heap. The stored version of bitmap is guaranteed to be immutable - * and is not dependent on the lifecycle of the provided bitmap. - * - * @param bitmap the bitmap to be inserted into the heap - * @return the slot in the heap where the bitmap is stored or INVALID_SLOT if the bitmap could - * not be added to the heap. If it was added the slot will remain valid... - * (1) indefinitely if no owner count has been specified. - * (2) until all owners have called releaseRef on the appropriate SkBitmapHeapEntry* - */ - int32_t insert(const SkBitmap& bitmap); - - /** - * Retrieves an entry from the heap at a given slot. - * - * @param slot the slot in the heap where a bitmap was stored. - * @return a SkBitmapHeapEntry that wraps the bitmap or nullptr if external storage is used. - */ - SkBitmapHeapEntry* getEntry(int32_t slot) const { - SkASSERT(slot <= fStorage.count()); - if (fExternalStorage != nullptr) { - return nullptr; - } - return fStorage[slot]; - } - - /** - * Returns a count of the number of items currently in the heap - */ - int count() const { - SkASSERT(fExternalStorage != nullptr || - fStorage.count() - fUnusedSlots.count() == fLookupTable.count()); - return fLookupTable.count(); - } - - /** - * Returns the total number of bytes allocated by the bitmaps in the heap - */ - size_t bytesAllocated() const { - return fBytesAllocated; - } - - /** - * Attempt to reduce the storage allocated. - * @param bytesToFree minimum number of bytes that should be attempted to - * be freed. - * @return number of bytes actually freed. - */ - size_t freeMemoryIfPossible(size_t bytesToFree); - - /** - * Defer any increments of owner counts until endAddingOwnersDeferral is called. So if an - * existing SkBitmap is inserted into the SkBitmapHeap, its corresponding SkBitmapHeapEntry will - * not have addReferences called on it, and the client does not need to make a corresponding - * call to releaseRef. Only meaningful if this SkBitmapHeap was created with an owner count not - * equal to IGNORE_OWNERS. - */ - void deferAddingOwners(); - - /** - * Resume adding references when duplicate SkBitmaps are inserted. - * @param add If true, add references to the SkBitmapHeapEntrys whose SkBitmaps were re-inserted - * while deferring. - */ - void endAddingOwnersDeferral(bool add); - -private: - struct LookupEntry { - LookupEntry(const SkBitmap& bm) - : fGenerationId(bm.getGenerationID()) - , fPixelOrigin(bm.pixelRefOrigin()) - , fWidth(bm.width()) - , fHeight(bm.height()) - , fMoreRecentlyUsed(nullptr) - , fLessRecentlyUsed(nullptr){} - - const uint32_t fGenerationId; // SkPixelRef GenerationID. - const SkIPoint fPixelOrigin; - const uint32_t fWidth; - const uint32_t fHeight; - - // TODO: Generalize the LRU caching mechanism - LookupEntry* fMoreRecentlyUsed; - LookupEntry* fLessRecentlyUsed; - - uint32_t fStorageSlot; // slot of corresponding bitmap in fStorage. - - /** - * Compare two LookupEntry pointers for sorting and searching. - */ - static bool Less(const LookupEntry& a, const LookupEntry& b); - }; - - /** - * Remove the entry from the lookup table. Also deletes the entry pointed - * to by the table. Therefore, if a pointer to that one was passed in, the - * pointer should no longer be used, since the object to which it points has - * been deleted. - * @return The index in the lookup table of the entry before removal. - */ - int removeEntryFromLookupTable(LookupEntry*); - - /** - * Searches for the bitmap in the lookup table and returns the bitmaps index within the table. - * If the bitmap was not already in the table it is added. - * - * @param key The key to search the lookup table, created from a bitmap. - * @param entry A pointer to a SkBitmapHeapEntry* that if non-null AND the bitmap is found - * in the lookup table is populated with the entry from the heap storage. - */ - int findInLookupTable(const LookupEntry& key, SkBitmapHeapEntry** entry); - - LookupEntry* findEntryToReplace(const SkBitmap& replacement); - bool copyBitmap(const SkBitmap& originalBitmap, SkBitmap& copiedBitmap); - - /** - * Remove a LookupEntry from the LRU, in preparation for either deleting or appending as most - * recent. Points the LookupEntry's old neighbors at each other, and sets fLeastRecentlyUsed - * (if there is still an entry left). Sets LookupEntry's fMoreRecentlyUsed to nullptr and leaves - * its fLessRecentlyUsed unmodified. - */ - void removeFromLRU(LookupEntry* entry); - - /** - * Append a LookupEntry to the end of the LRU cache, marking it as the most - * recently used. Assumes that the LookupEntry is already in fLookupTable, - * but is not in the LRU cache. If it is in the cache, removeFromLRU should - * be called first. - */ - void appendToLRU(LookupEntry*); - - // searchable index that maps to entries in the heap - SkTDArray fLookupTable; - - // heap storage - SkTDArray fStorage; - // Used to mark slots in fStorage as deleted without actually deleting - // the slot so as not to mess up the numbering. - SkTDArray fUnusedSlots; - ExternalStorage* fExternalStorage; - - LookupEntry* fMostRecentlyUsed; - LookupEntry* fLeastRecentlyUsed; - - const int32_t fPreferredCount; - const int32_t fOwnerCount; - size_t fBytesAllocated; - - bool fDeferAddingOwners; - SkTDArray fDeferredEntries; - - typedef SkBitmapHeapReader INHERITED; -}; - -#endif // SkBitmapHeap_DEFINED diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp index c9df4ce248c7..e0d281b026fa 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.cpp @@ -8,17 +8,6 @@ #include "SkBitmapProcShader.h" #include "SkBitmapProcState.h" #include "SkBitmapProvider.h" -#include "SkColorPriv.h" -#include "SkErrorInternals.h" -#include "SkPixelRef.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" - -#if SK_SUPPORT_GPU -#include "SkGrPriv.h" -#include "effects/GrBicubicEffect.h" -#include "effects/GrSimpleTextureEffect.h" -#endif static bool only_scale_and_translate(const SkMatrix& matrix) { unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; @@ -121,13 +110,19 @@ public: SkBitmapProcInfo* info) : INHERITED(shader, rec, info) { - // Need to ensure that our pipeline is created at a 16byte aligned address - fPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fStorage); - float alpha = SkColorGetA(info->fPaintColor) / 255.0f; - new (fPipeline) SkLinearBitmapPipeline(info->fRealInvMatrix, info->fFilterQuality, - info->fTileModeX, info->fTileModeY, - alpha, - info->fPixmap); + // Save things off in case we need to build a blitter pipeline. + fSrcPixmap = info->fPixmap; + fAlpha = SkColorGetA(info->fPaintColor) / 255.0f; + fXMode = info->fTileModeX; + fYMode = info->fTileModeY; + fFilterQuality = info->fFilterQuality; + fMatrixTypeMask = info->fRealInvMatrix.getType(); + + fShaderPipeline.init( + info->fRealInvMatrix, info->fFilterQuality, + info->fTileModeX, info->fTileModeY, + info->fPaintColor, + info->fPixmap); // To implement the old shadeSpan entry-point, we need to efficiently convert our native // floats into SkPMColor. The SkXfermode::D32Procs do exactly that. @@ -136,13 +131,8 @@ public: fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0); } - ~LinearPipelineContext() override { - // since we did a manual new, we need to manually destroy as well. - fPipeline->~SkLinearBitmapPipeline(); - } - void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override { - fPipeline->shadeSpan4f(x, y, dstC, count); + fShaderPipeline->shadeSpan4f(x, y, dstC, count); } void shadeSpan(int x, int y, SkPMColor dstC[], int count) override { @@ -151,7 +141,7 @@ public: while (count > 0) { const int n = SkTMin(count, N); - fPipeline->shadeSpan4f(x, y, tmp, n); + fShaderPipeline->shadeSpan4f(x, y, tmp, n); fXferProc(nullptr, dstC, tmp, n, nullptr); dstC += n; x += n; @@ -159,14 +149,42 @@ public: } } + bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override { + SkXfermode::Mode mode; + if (!SkXfermode::AsMode(state->fXfer, &mode)) { return false; } + + if (SkLinearBitmapPipeline::ClonePipelineForBlitting( + &fBlitterPipeline, *fShaderPipeline, + fMatrixTypeMask, + fXMode, fYMode, + fFilterQuality, fSrcPixmap, + fAlpha, mode, dstInfo)) + { + state->fStorage[0] = fBlitterPipeline.get(); + state->fBlitBW = &LinearPipelineContext::ForwardToPipeline; + + return true; + } + + return false; + } + + static void ForwardToPipeline(BlitState* state, int x, int y, const SkPixmap& dst, int count) { + SkLinearBitmapPipeline* pipeline = static_cast(state->fStorage[0]); + void* addr = dst.writable_addr32(x, y); + pipeline->blitSpan(x, y, addr, count); + } + private: - enum { - kActualSize = sizeof(SkLinearBitmapPipeline), - kPaddedSize = SkAlignPtr(kActualSize + 12), - }; - void* fStorage[kPaddedSize / sizeof(void*)]; - SkLinearBitmapPipeline* fPipeline; - SkXfermode::D32Proc fXferProc; + SkEmbeddableLinearPipeline fShaderPipeline; + SkEmbeddableLinearPipeline fBlitterPipeline; + SkXfermode::D32Proc fXferProc; + SkPixmap fSrcPixmap; + float fAlpha; + SkShader::TileMode fXMode; + SkShader::TileMode fYMode; + SkMatrix::TypeMask fMatrixTypeMask; + SkFilterQuality fFilterQuality; typedef BitmapProcInfoContext INHERITED; }; @@ -174,37 +192,23 @@ private: /////////////////////////////////////////////////////////////////////////////////////////////////// static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) { - // These src attributes are not supported in the new 4f context (yet) - // - if (srcInfo.colorType() != kRGBA_8888_SkColorType - && srcInfo.colorType() != kBGRA_8888_SkColorType - && srcInfo.colorType() != kIndex_8_SkColorType) { - return false; - } - -#if 0 // later we may opt-in to the new code even if the client hasn't requested it... - // These src attributes are only supported in the new 4f context - // - if (srcInfo.isSRGB() || - kUnpremul_SkAlphaType == srcInfo.alphaType() || - (4 == srcInfo.bytesPerPixel() && kN32_SkColorType != srcInfo.colorType())) - { - return true; - } -#endif - // If we get here, we can reasonably use either context, respect the caller's preference // - return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType; + bool needsPremul = srcInfo.alphaType() == kUnpremul_SkAlphaType; + bool needsSwizzle = srcInfo.bytesPerPixel() == 4 && srcInfo.colorType() != kN32_SkColorType; + return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType + || needsPremul || needsSwizzle; } -size_t SkBitmapProcShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) { +size_t SkBitmapProcLegacyShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) { size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState); size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo); + size_t s = SkTMax(size0, size1); + return s; return SkTMax(size0, size1); } -SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, +SkShader::Context* SkBitmapProcLegacyShader::MakeContext(const SkShader& shader, TileMode tmx, TileMode tmy, const SkBitmapProvider& provider, const ContextRec& rec, void* storage) { @@ -216,28 +220,21 @@ SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, // Decide if we can/want to use the new linear pipeline bool useLinearPipeline = choose_linear_pipeline(rec, provider.info()); - - // - // For now, only enable locally since we are hitting some crashers on the test bots - // - //useLinearPipeline = false; + SkSourceGammaTreatment treatment = SkMipMap::DeduceTreatment(rec); if (useLinearPipeline) { void* infoStorage = (char*)storage + sizeof(LinearPipelineContext); - SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy); + SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy, treatment); if (!info->init(totalInverse, *rec.fPaint)) { info->~SkBitmapProcInfo(); return nullptr; } - if (info->fPixmap.colorType() != kRGBA_8888_SkColorType - && info->fPixmap.colorType() != kBGRA_8888_SkColorType - && info->fPixmap.colorType() != kIndex_8_SkColorType) { - return nullptr; - } + return new (storage) LinearPipelineContext(shader, rec, info); } else { void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext); - SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy); + SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy, + treatment); if (!state->setup(totalInverse, *rec.fPaint)) { state->~SkBitmapProcState(); return nullptr; @@ -245,219 +242,3 @@ SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader, return new (storage) BitmapProcShaderContext(shader, rec, state); } } - -SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const { - return MakeContext(*this, (TileMode)fTileModeX, (TileMode)fTileModeY, - SkBitmapProvider(fRawBitmap), rec, storage); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy, - const SkMatrix* localMatrix) - : INHERITED(localMatrix) { - fRawBitmap = src; - fTileModeX = (uint8_t)tmx; - fTileModeY = (uint8_t)tmy; -} - -bool SkBitmapProcShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const { - if (texture) { - *texture = fRawBitmap; - } - if (texM) { - texM->reset(); - } - if (xy) { - xy[0] = (TileMode)fTileModeX; - xy[1] = (TileMode)fTileModeY; - } - return true; -} - -sk_sp SkBitmapProcShader::CreateProc(SkReadBuffer& buffer) { - SkMatrix lm; - buffer.readMatrix(&lm); - SkBitmap bm; - if (!buffer.readBitmap(&bm)) { - return nullptr; - } - bm.setImmutable(); - TileMode mx = (TileMode)buffer.readUInt(); - TileMode my = (TileMode)buffer.readUInt(); - return SkShader::MakeBitmapShader(bm, mx, my, &lm); -} - -void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const { - buffer.writeMatrix(this->getLocalMatrix()); - buffer.writeBitmap(fRawBitmap); - buffer.writeUInt(fTileModeX); - buffer.writeUInt(fTileModeY); -} - -bool SkBitmapProcShader::isOpaque() const { - return fRawBitmap.isOpaque(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkUnPreMultiply.h" -#include "SkColorShader.h" -#include "SkEmptyShader.h" - -// returns true and set color if the bitmap can be drawn as a single color -// (for efficiency) -static bool can_use_color_shader(const SkBitmap& bm, SkColor* color) { -#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - // HWUI does not support color shaders (see b/22390304) - return false; -#endif - - if (1 != bm.width() || 1 != bm.height()) { - return false; - } - - SkAutoLockPixels alp(bm); - if (!bm.readyToDraw()) { - return false; - } - - switch (bm.colorType()) { - case kN32_SkColorType: - *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0)); - return true; - case kRGB_565_SkColorType: - *color = SkPixel16ToColor(*bm.getAddr16(0, 0)); - return true; - case kIndex_8_SkColorType: - *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0)); - return true; - default: // just skip the other configs for now - break; - } - return false; -} - -static bool bitmap_is_too_big(const SkBitmap& bm) { - // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it - // communicates between its matrix-proc and its sampler-proc. Until we can - // widen that, we have to reject bitmaps that are larger. - // - static const int kMaxSize = 65535; - - return bm.width() > kMaxSize || bm.height() > kMaxSize; -} - -sk_sp SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, - SkShader::TileMode tmy, const SkMatrix* localMatrix, - SkTBlitterAllocator* allocator) { - SkShader* shader; - SkColor color; - if (src.isNull() || bitmap_is_too_big(src)) { - if (nullptr == allocator) { - shader = new SkEmptyShader; - } else { - shader = allocator->createT(); - } - } else if (can_use_color_shader(src, &color)) { - if (nullptr == allocator) { - shader = new SkColorShader(color); - } else { - shader = allocator->createT(color); - } - } else { - if (nullptr == allocator) { - shader = new SkBitmapProcShader(src, tmx, tmy, localMatrix); - } else { - shader = allocator->createT(src, tmx, tmy, localMatrix); - } - } - return sk_sp(shader); -} - -/////////////////////////////////////////////////////////////////////////////// - -#ifndef SK_IGNORE_TO_STRING -void SkBitmapProcShader::toString(SkString* str) const { - static const char* gTileModeName[SkShader::kTileModeCount] = { - "clamp", "repeat", "mirror" - }; - - str->append("BitmapShader: ("); - - str->appendf("(%s, %s)", - gTileModeName[fTileModeX], - gTileModeName[fTileModeY]); - - str->append(" "); - fRawBitmap.toString(str); - - this->INHERITED::toString(str); - - str->append(")"); -} -#endif - -/////////////////////////////////////////////////////////////////////////////// - -#if SK_SUPPORT_GPU - -#include "GrTextureAccess.h" -#include "SkGr.h" -#include "effects/GrSimpleTextureEffect.h" - -const GrFragmentProcessor* SkBitmapProcShader::asFragmentProcessor(GrContext* context, - const SkMatrix& viewM, const SkMatrix* localMatrix, - SkFilterQuality filterQuality) const { - SkMatrix matrix; - matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height()); - - SkMatrix lmInverse; - if (!this->getLocalMatrix().invert(&lmInverse)) { - return nullptr; - } - if (localMatrix) { - SkMatrix inv; - if (!localMatrix->invert(&inv)) { - return nullptr; - } - lmInverse.postConcat(inv); - } - matrix.preConcat(lmInverse); - - SkShader::TileMode tm[] = { - (TileMode)fTileModeX, - (TileMode)fTileModeY, - }; - - // Must set wrap and filter on the sampler before requesting a texture. In two places below - // we check the matrix scale factors to determine how to interpret the filter quality setting. - // This completely ignores the complexity of the drawVertices case where explicit local coords - // are provided by the caller. - bool doBicubic; - GrTextureParams::FilterMode textureFilterMode = - GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), - &doBicubic); - GrTextureParams params(tm, textureFilterMode); - SkAutoTUnref texture(GrRefCachedBitmapTexture(context, fRawBitmap, params)); - - if (!texture) { - SkErrorInternals::SetError( kInternalError_SkError, - "Couldn't convert bitmap to texture."); - return nullptr; - } - - SkAutoTUnref inner; - if (doBicubic) { - inner.reset(GrBicubicEffect::Create(texture, matrix, tm)); - } else { - inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params)); - } - - if (kAlpha_8_SkColorType == fRawBitmap.colorType()) { - return GrFragmentProcessor::MulOutputByInputUnpremulColor(inner); - } - return GrFragmentProcessor::MulOutputByInputAlpha(inner); -} - -#endif diff --git a/gfx/skia/skia/src/core/SkBitmapProcShader.h b/gfx/skia/skia/src/core/SkBitmapProcShader.h index 185a95de6683..4b7447e52e5d 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcShader.h +++ b/gfx/skia/skia/src/core/SkBitmapProcShader.h @@ -4,42 +4,15 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - #ifndef SkBitmapProcShader_DEFINED #define SkBitmapProcShader_DEFINED +#include "SkImagePriv.h" #include "SkShader.h" -#include "SkSmallAllocator.h" -struct SkBitmapProcState; class SkBitmapProvider; -class SkBitmapProcShader : public SkShader { -public: - SkBitmapProcShader(const SkBitmap& src, TileMode tx, TileMode ty, - const SkMatrix* localMatrix = nullptr); - - bool isOpaque() const override; - - SK_TO_STRING_OVERRIDE() - SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapProcShader) - -#if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*, const SkMatrix& viewM, - const SkMatrix*, SkFilterQuality) const override; -#endif - -protected: - void flatten(SkWriteBuffer&) const override; - size_t onContextSize(const ContextRec& rec) const override { - return ContextSize(rec, fRawBitmap.info()); - } - Context* onCreateContext(const ContextRec&, void* storage) const override; - bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override; - - SkBitmap fRawBitmap; - uint8_t fTileModeX, fTileModeY; - +class SkBitmapProcLegacyShader : public SkShader { private: friend class SkImageShader; @@ -50,16 +23,4 @@ private: typedef SkShader INHERITED; }; -// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total -// bytes requested is calculated using one of our large shaders, its context size plus the size of -// an Sk3DBlitter in SkDraw.cpp -// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not -// yet found a situation where the size below isn't big enough. -typedef SkSmallAllocator<3, 2100> SkTBlitterAllocator; - -// If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive -// the SkShader. -sk_sp SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode, - const SkMatrix* localMatrix, SkTBlitterAllocator* alloc); - #endif diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.cpp b/gfx/skia/skia/src/core/SkBitmapProcState.cpp index 28046b5a9d16..5bc1b47f6e49 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState.cpp @@ -19,7 +19,7 @@ #include "SkImageEncoder.h" #include "SkResourceCache.h" -#if !SK_ARM_NEON_IS_NONE +#if defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) // These are defined in src/opts/SkBitmapProcState_arm_neon.cpp extern const SkBitmapProcState::SampleProc32 gSkBitmapProcStateSample32_neon[]; extern void S16_D16_filter_DX_neon(const SkBitmapProcState&, const uint32_t*, int, uint16_t*); @@ -37,18 +37,22 @@ extern void Clamp_S32_opaque_D32_nofilter_DX_shaderproc(const void*, int, int, u #include "SkBitmapProcState_procs.h" SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmapProvider& provider, - SkShader::TileMode tmx, SkShader::TileMode tmy) + SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment treatment) : fProvider(provider) , fTileModeX(tmx) , fTileModeY(tmy) + , fSrcGammaTreatment(treatment) , fBMState(nullptr) {} SkBitmapProcInfo::SkBitmapProcInfo(const SkBitmap& bm, - SkShader::TileMode tmx, SkShader::TileMode tmy) + SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment treatment) : fProvider(SkBitmapProvider(bm)) , fTileModeX(tmx) , fTileModeY(tmy) + , fSrcGammaTreatment(treatment) , fBMState(nullptr) {} @@ -129,7 +133,7 @@ bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) { allow_ignore_fractional_translate = false; } - SkDefaultBitmapController controller; + SkDefaultBitmapController controller(fSrcGammaTreatment); fBMState = controller.requestBitmap(fProvider, inv, paint.getFilterQuality(), fBMStateStorage.get(), fBMStateStorage.size()); // Note : we allow the controller to return an empty (zero-dimension) result. Should we? @@ -296,7 +300,7 @@ bool SkBitmapProcState::chooseScanlineProcs(bool trivialMatrix, bool clampClamp) return false; } -#if !SK_ARM_NEON_IS_ALWAYS +#if !defined(SK_ARM_HAS_NEON) static const SampleProc32 gSkBitmapProcStateSample32[] = { S32_opaque_D32_nofilter_DXDY, S32_alpha_D32_nofilter_DXDY, diff --git a/gfx/skia/skia/src/core/SkBitmapProcState.h b/gfx/skia/skia/src/core/SkBitmapProcState.h index 40dc31a5e0c4..e2e4f96951e8 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState.h +++ b/gfx/skia/skia/src/core/SkBitmapProcState.h @@ -28,8 +28,10 @@ typedef SkFixed3232 SkFractionalInt; class SkPaint; struct SkBitmapProcInfo { - SkBitmapProcInfo(const SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy); - SkBitmapProcInfo(const SkBitmap&, SkShader::TileMode tmx, SkShader::TileMode tmy); + SkBitmapProcInfo(const SkBitmapProvider&, SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment); + SkBitmapProcInfo(const SkBitmap&, SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment); ~SkBitmapProcInfo(); const SkBitmapProvider fProvider; @@ -43,6 +45,7 @@ struct SkBitmapProcInfo { SkShader::TileMode fTileModeY; SkFilterQuality fFilterQuality; SkMatrix::TypeMask fInvType; + SkSourceGammaTreatment fSrcGammaTreatment; bool init(const SkMatrix& inverse, const SkPaint&); @@ -55,10 +58,12 @@ private: }; struct SkBitmapProcState : public SkBitmapProcInfo { - SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy) - : SkBitmapProcInfo(prov, tmx, tmy) {} - SkBitmapProcState(const SkBitmap& bitmap, SkShader::TileMode tmx, SkShader::TileMode tmy) - : SkBitmapProcInfo(bitmap, tmx, tmy) {} + SkBitmapProcState(const SkBitmapProvider& prov, SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment treatment) + : SkBitmapProcInfo(prov, tmx, tmy, treatment) {} + SkBitmapProcState(const SkBitmap& bitmap, SkShader::TileMode tmx, SkShader::TileMode tmy, + SkSourceGammaTreatment treatment) + : SkBitmapProcInfo(bitmap, tmx, tmy, treatment) {} bool setup(const SkMatrix& inv, const SkPaint& paint) { return this->init(inv, paint) && this->chooseProcs(); diff --git a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp index 16f1bc6f283a..970ea47a3c44 100644 --- a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp @@ -47,16 +47,16 @@ void decal_filter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int count); /////////////////////////////////////////////////////////////////////////////// // Compile neon code paths if needed -#if !SK_ARM_NEON_IS_NONE +#if defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON) // These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp extern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[]; extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[]; -#endif // !SK_ARM_NEON_IS_NONE +#endif // defined(SK_ARM_HAS_NEON) // Compile non-neon code path if needed -#if !SK_ARM_NEON_IS_ALWAYS +#if !defined(SK_ARM_HAS_NEON) #define MAKENAME(suffix) ClampX_ClampY ## suffix #define TILEX_PROCF(fx, max) SkClampMax((fx) >> 16, max) #define TILEY_PROCF(fy, max) SkClampMax((fy) >> 16, max) diff --git a/gfx/skia/skia/src/core/SkBitmapProvider.cpp b/gfx/skia/skia/src/core/SkBitmapProvider.cpp index 9f6eb94310a5..37f8dc9d52e9 100644 --- a/gfx/skia/skia/src/core/SkBitmapProvider.cpp +++ b/gfx/skia/skia/src/core/SkBitmapProvider.cpp @@ -29,10 +29,6 @@ bool SkBitmapProvider::validForDrawing() const { if (nullptr == fBitmap.pixelRef()) { return false; // no pixels to read } - if (fBitmap.getTexture()) { - // we can handle texture (ugh) since lockPixels will perform a read-back - return true; - } if (kIndex_8_SkColorType == fBitmap.colorType()) { SkAutoLockPixels alp(fBitmap); // but we need to call it before getColorTable() is safe. if (!fBitmap.getColorTable()) { @@ -45,8 +41,7 @@ bool SkBitmapProvider::validForDrawing() const { SkImageInfo SkBitmapProvider::info() const { if (fImage) { - SkAlphaType at = fImage->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType; - return SkImageInfo::MakeN32(fImage->width(), fImage->height(), at); + return as_IB(fImage)->onImageInfo(); } else { return fBitmap.info(); } @@ -54,7 +49,9 @@ SkImageInfo SkBitmapProvider::info() const { bool SkBitmapProvider::isVolatile() const { if (fImage) { - return false; // add flag to images? + // add flag to images? + const SkBitmap* bm = as_IB(fImage)->onPeekBitmap(); + return bm ? bm->isVolatile() : false; } else { return fBitmap.isVolatile(); } diff --git a/gfx/skia/skia/src/core/SkBitmapScaler.cpp b/gfx/skia/skia/src/core/SkBitmapScaler.cpp index 398e20c24622..5edb1b23e16d 100644 --- a/gfx/skia/skia/src/core/SkBitmapScaler.cpp +++ b/gfx/skia/skia/src/core/SkBitmapScaler.cpp @@ -250,7 +250,10 @@ bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeM } SkBitmap result; - result.setInfo(SkImageInfo::MakeN32(destWidth, destHeight, source.alphaType())); + // Note: pass along the profile information even thought this is no the right answer because + // this could be scaling in sRGB. + result.setInfo(SkImageInfo::MakeN32(destWidth, destHeight, source.alphaType(), + sk_ref_sp(source.info().colorSpace()))); result.allocPixels(allocator, nullptr); SkPixmap resultPM; diff --git a/gfx/skia/skia/src/core/SkBlendModePriv.h b/gfx/skia/skia/src/core/SkBlendModePriv.h new file mode 100644 index 000000000000..b5d9e751e62d --- /dev/null +++ b/gfx/skia/skia/src/core/SkBlendModePriv.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 SkBlendModePriv_DEFINED +#define SkBlendModePriv_DEFINED + +#include "SkBlendMode.h" + +bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode); + +#if SK_SUPPORT_GPU +sk_sp SkBlendMode_AsXPFactory(SkBlendMode); +#endif + +#endif diff --git a/gfx/skia/skia/src/core/SkBlitter.cpp b/gfx/skia/skia/src/core/SkBlitter.cpp index 8f0031cd46d4..ce689d7e8421 100644 --- a/gfx/skia/skia/src/core/SkBlitter.cpp +++ b/gfx/skia/skia/src/core/SkBlitter.cpp @@ -38,14 +38,17 @@ const SkPixmap* SkBlitter::justAnOpaqueColor(uint32_t* value) { return nullptr; } +/* void SkBlitter::blitH(int x, int y, int width) { SkDEBUGFAIL("unimplemented"); } + void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { SkDEBUGFAIL("unimplemented"); } + */ void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) { if (alpha == 255) { @@ -155,7 +158,7 @@ void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { cy += 1; } } else { - // Bits is calculated as the offset into the mask at the point {cx, cy} therfore, all + // Bits is calculated as the offset into the mask at the point {cx, cy} therefore, all // addressing into the bit mask is relative to that point. Since this is an address // calculated from a arbitrary bit in that byte, calculate the left most bit. int bitsLeft = cx - ((cx - maskLeft) & 7); @@ -785,7 +788,7 @@ SkShader::ContextRec::DstType SkBlitter::PreferredShaderDest(const SkImageInfo& #ifdef SK_FORCE_PM4f_FOR_L32_BLITS return SkShader::ContextRec::kPM4f_DstType; #else - return (dstInfo.isSRGB() || dstInfo.colorType() == kRGBA_F16_SkColorType) + return (dstInfo.gammaCloseToSRGB() || dstInfo.colorType() == kRGBA_F16_SkColorType) ? SkShader::ContextRec::kPM4f_DstType : SkShader::ContextRec::kPMColor_DstType; #endif @@ -807,7 +810,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, SkShader* shader = origPaint.getShader(); SkColorFilter* cf = origPaint.getColorFilter(); - SkXfermode* mode = origPaint.getXfermode(); + SkBlendMode mode = origPaint.getBlendMode(); sk_sp shader3D; SkTCopyOnFirstWrite paint(origPaint); @@ -820,12 +823,12 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, shader = shader3D.get(); } - if (mode) { + if (mode != SkBlendMode::kSrcOver) { bool deviceIsOpaque = kRGB_565_SkColorType == device.colorType(); switch (SkInterpretXfermode(*paint, deviceIsOpaque)) { case kSrcOver_SkXfermodeInterpretation: - mode = nullptr; - paint.writable()->setXfermode(nullptr); + mode = SkBlendMode::kSrcOver; + paint.writable()->setBlendMode(mode); break; case kSkipDrawing_SkXfermodeInterpretation:{ return allocator->createT(); @@ -840,18 +843,22 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, * color/shader/colorfilter, and just pretend we're SRC + color==0. This * will fall into our optimizations for SRC mode. */ - if (SkXfermode::IsMode(mode, SkXfermode::kClear_Mode)) { + if (mode == SkBlendMode::kClear) { SkPaint* p = paint.writable(); p->setShader(nullptr); shader = nullptr; p->setColorFilter(nullptr); cf = nullptr; - mode = p->setXfermodeMode(SkXfermode::kSrc_Mode); + p->setBlendMode(mode = SkBlendMode::kSrc); p->setColor(0); } + if (SkBlitter* blitter = SkCreateRasterPipelineBlitter(device, *paint, allocator)) { + return blitter; + } + if (nullptr == shader) { - if (mode) { + if (mode != SkBlendMode::kSrcOver) { // xfermodes (and filters) require shaders for our current blitters paint.writable()->setShader(SkShader::MakeColorShader(paint->getColor())); paint.writable()->setAlpha(0xFF); @@ -902,7 +909,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, case kAlpha_8_SkColorType: if (drawCoverage) { SkASSERT(nullptr == shader); - SkASSERT(nullptr == paint->getXfermode()); + SkASSERT(paint->isSrcOver()); blitter = allocator->createT(device, *paint); } else if (shader) { blitter = allocator->createT(device, *paint, shaderContext); @@ -919,7 +926,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, #ifdef SK_FORCE_PM4f_FOR_L32_BLITS if (true) #else - if (device.info().isSRGB()) + if (device.info().gammaCloseToSRGB()) #endif { blitter = SkBlitter_ARGB32_Create(device, *paint, shaderContext, allocator); @@ -938,8 +945,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, break; case kRGBA_F16_SkColorType: - // kU16_SkColorType: - blitter = SkBlitter_ARGB64_Create(device, *paint, shaderContext, allocator); + blitter = SkBlitter_F16_Create(device, *paint, shaderContext, allocator); break; default: diff --git a/gfx/skia/skia/src/core/SkBlitter.h b/gfx/skia/skia/src/core/SkBlitter.h index 009582624882..0e5fedd7ebb6 100644 --- a/gfx/skia/skia/src/core/SkBlitter.h +++ b/gfx/skia/skia/src/core/SkBlitter.h @@ -22,22 +22,37 @@ struct SkMask; /** SkBlitter and its subclasses are responsible for actually writing pixels into memory. Besides efficiency, they handle clipping and antialiasing. + A SkBlitter subclass contains all the context needed to generate pixels + for the destination and how src/generated pixels map to the destination. + The coordinates passed to the blitX calls are in destination pixel space. */ class SkBlitter { public: virtual ~SkBlitter(); /// Blit a horizontal run of one or more pixels. - virtual void blitH(int x, int y, int width); + virtual void blitH(int x, int y, int width) = 0; + /// Blit a horizontal run of antialiased pixels; runs[] is a *sparse* /// zero-terminated run-length encoding of spans of constant alpha values. - virtual void blitAntiH(int x, int y, const SkAlpha antialias[], - const int16_t runs[]); + /// The runs[] and antialias[] work together to represent long runs of pixels with the same + /// alphas. The runs[] contains the number of pixels with the same alpha, and antialias[] + /// contain the coverage value for that number of pixels. The runs[] (and antialias[]) are + /// encoded in a clever way. The runs array is zero terminated, and has enough entries for + /// each pixel plus one, in most cases some of the entries will not contain valid data. An entry + /// in the runs array contains the number of pixels (np) that have the same alpha value. The + /// next np value is found np entries away. For example, if runs[0] = 7, then the next valid + /// entry will by at runs[7]. The runs array and antialias[] are coupled by index. So, if the + /// np entry is at runs[45] = 12 then the alpha value can be found at antialias[45] = 0x88. + /// This would mean to use an alpha value of 0x88 for the next 12 pixels starting at pixel 45. + virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) = 0; /// Blit a vertical run of pixels with a constant alpha value. virtual void blitV(int x, int y, int height, SkAlpha alpha); + /// Blit a solid rectangle one or more pixels wide. virtual void blitRect(int x, int y, int width, int height); + /** Blit a rectangle with one alpha-blended column on the left, width (zero or more) opaque pixels, and one alpha-blended column on the right. @@ -45,6 +60,7 @@ public: */ virtual void blitAntiRect(int x, int y, int width, int height, SkAlpha leftAlpha, SkAlpha rightAlpha); + /// Blit a pattern of pixels defined by a rectangle-clipped mask; /// typically used for text. virtual void blitMask(const SkMask&, const SkIRect& clip); diff --git a/gfx/skia/skia/src/core/SkBlitter_A8.cpp b/gfx/skia/skia/src/core/SkBlitter_A8.cpp index 66976143c8f3..cb7d718f5400 100644 --- a/gfx/skia/skia/src/core/SkBlitter_A8.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_A8.cpp @@ -230,10 +230,8 @@ SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkPixmap& device, const SkPaint& SkShader::Context* shaderContext) : INHERITED(device, paint, shaderContext) { - if ((fXfermode = paint.getXfermode()) != nullptr) { - fXfermode->ref(); - SkASSERT(fShaderContext); - } + fXfermode = SkXfermode::Peek(paint.getBlendMode()); + SkASSERT(!fXfermode || fShaderContext); int width = device.width(); fBuffer = (SkPMColor*)sk_malloc_throw(sizeof(SkPMColor) * (width + (SkAlign4(width) >> 2))); @@ -241,7 +239,6 @@ SkA8_Shader_Blitter::SkA8_Shader_Blitter(const SkPixmap& device, const SkPaint& } SkA8_Shader_Blitter::~SkA8_Shader_Blitter() { - if (fXfermode) SkSafeUnref(fXfermode); sk_free(fBuffer); } @@ -355,7 +352,7 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { SkA8_Coverage_Blitter::SkA8_Coverage_Blitter(const SkPixmap& device, const SkPaint& paint) : SkRasterBlitter(device) { SkASSERT(nullptr == paint.getShader()); - SkASSERT(nullptr == paint.getXfermode()); + SkASSERT(paint.isSrcOver()); SkASSERT(nullptr == paint.getColorFilter()); } diff --git a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp index abe67e2c0712..ea0554d66eaa 100644 --- a/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_ARGB32.cpp @@ -174,10 +174,15 @@ void SkARGB32_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { return; } - if (mask.fFormat == SkMask::kBW_Format) { - SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA)); - } else if (SkMask::kARGB32_Format == mask.fFormat) { - SkARGB32_Blit32(fDevice, mask, clip, fPMColor); + switch (mask.fFormat) { + case SkMask::kBW_Format: + SkARGB32_BlendBW(fDevice, mask, clip, fPMColor, SkAlpha255To256(255 - fSrcA)); + break; + case SkMask::kARGB32_Format: + SkARGB32_Blit32(fDevice, mask, clip, fPMColor); + break; + default: + SkFAIL("Mask format not handled."); } } @@ -189,10 +194,15 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask, return; } - if (mask.fFormat == SkMask::kBW_Format) { - SkARGB32_BlitBW(fDevice, mask, clip, fPMColor); - } else if (SkMask::kARGB32_Format == mask.fFormat) { - SkARGB32_Blit32(fDevice, mask, clip, fPMColor); + switch (mask.fFormat) { + case SkMask::kBW_Format: + SkARGB32_BlitBW(fDevice, mask, clip, fPMColor); + break; + case SkMask::kARGB32_Format: + SkARGB32_Blit32(fDevice, mask, clip, fPMColor); + break; + default: + SkFAIL("Mask format not handled."); } } @@ -329,8 +339,7 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device, { fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); - fXfermode = paint.getXfermode(); - SkSafeRef(fXfermode); + fXfermode = SkXfermode::Peek(paint.getBlendMode()); int flags = 0; if (!(shaderContext->getFlags() & SkShader::kOpaqueAlpha_Flag)) { @@ -360,7 +369,6 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkPixmap& device, } SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() { - SkSafeUnref(fXfermode); sk_free(fBuffer); } diff --git a/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp b/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp index 820d72cc2e6d..d63e924e2c31 100644 --- a/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_PM4f.cpp @@ -325,7 +325,7 @@ static bool is_opaque(const SkPaint& paint, const SkShader::Context* shaderConte struct State4f { State4f(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) { - fXfer = paint.getXfermode(); + fXfer = SkXfermode::Peek(paint.getBlendMode()); if (shaderContext) { fBuffer.reset(info.width()); } else { @@ -354,7 +354,7 @@ struct State32 : State4f { if (is_opaque(paint, shaderContext)) { fFlags |= SkXfermode::kSrcIsOpaque_D32Flag; } - if (info.isSRGB()) { + if (info.gammaCloseToSRGB()) { fFlags |= SkXfermode::kDstIsSRGB_D32Flag; } fProc1 = SkXfermode::GetD32Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_D32Flag); @@ -363,8 +363,8 @@ struct State32 : State4f { SkXfermode::LCD32Proc getLCDProc(uint32_t oneOrManyFlag) const { uint32_t flags = fFlags & 1; - if (!(fFlags & SkXfermode::kDstIsSRGB_D32Flag)) { - flags |= SkXfermode::kDstIsLinearInt_LCDFlag; + if (fFlags & SkXfermode::kDstIsSRGB_D32Flag) { + flags |= SkXfermode::kDstIsSRGB_LCDFlag; } return SkXfermode::GetLCD32Proc(flags | oneOrManyFlag); } @@ -374,31 +374,26 @@ struct State32 : State4f { } }; -struct State64 : State4f { +struct StateF16 : State4f { typedef uint64_t DstType; - SkXfermode::D64Proc fProc1; - SkXfermode::D64Proc fProcN; + SkXfermode::F16Proc fProc1; + SkXfermode::F16Proc fProcN; - State64(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) + StateF16(const SkImageInfo& info, const SkPaint& paint, const SkShader::Context* shaderContext) : State4f(info, paint, shaderContext) { if (is_opaque(paint, shaderContext)) { - fFlags |= SkXfermode::kSrcIsOpaque_D64Flag; + fFlags |= SkXfermode::kSrcIsOpaque_F16Flag; } - if (kRGBA_F16_SkColorType == info.colorType()) { - fFlags |= SkXfermode::kDstIsFloat16_D64Flag; - } - fProc1 = SkXfermode::GetD64Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_D64Flag); - fProcN = SkXfermode::GetD64Proc(fXfer, fFlags); + SkASSERT(kRGBA_F16_SkColorType == info.colorType()); + fProc1 = SkXfermode::GetF16Proc(fXfer, fFlags | SkXfermode::kSrcIsSingle_F16Flag); + fProcN = SkXfermode::GetF16Proc(fXfer, fFlags); } - SkXfermode::LCD64Proc getLCDProc(uint32_t oneOrManyFlag) const { + SkXfermode::LCDF16Proc getLCDProc(uint32_t oneOrManyFlag) const { uint32_t flags = fFlags & 1; - if (!(fFlags & SkXfermode::kDstIsFloat16_D64Flag)) { - flags |= SkXfermode::kDstIsLinearInt_LCDFlag; - } - return SkXfermode::GetLCD64Proc(flags | oneOrManyFlag); + return SkXfermode::GetLCDF16Proc(flags | oneOrManyFlag); } static DstType* WritableAddr(const SkPixmap& device, int x, int y) { @@ -415,7 +410,7 @@ template SkBlitter* create(const SkPixmap& device, const SkPain SkShader::Context::BlitState bstate; sk_bzero(&bstate, sizeof(bstate)); bstate.fCtx = shaderContext; - bstate.fXfer = paint.getXfermode(); + bstate.fXfer = SkXfermode::Peek(paint.getBlendMode()); (void)shaderContext->chooseBlitProcs(device.info(), &bstate); return allocator->createT>(device, paint, bstate); @@ -434,8 +429,8 @@ SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint, return create(device, paint, shaderContext, allocator); } -SkBlitter* SkBlitter_ARGB64_Create(const SkPixmap& device, const SkPaint& paint, - SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator) { - return create(device, paint, shaderContext, allocator); +SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint& paint, + SkShader::Context* shaderContext, + SkTBlitterAllocator* allocator) { + return create(device, paint, shaderContext, allocator); } diff --git a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp index 38edd60a9dd5..7860b7cb6c03 100644 --- a/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_RGB16.cpp @@ -20,7 +20,7 @@ extern void blitmask_d565_opaque_mips(int width, int height, uint16_t* device, uint32_t expanded32, unsigned maskRB); #endif -#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) +#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) #include extern void SkRGB16BlitterBlitV_neon(uint16_t* device, int height, @@ -160,7 +160,7 @@ SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkPixmap& device, const SkPai : INHERITED(device, paint) { SkASSERT(paint.getShader() == nullptr); SkASSERT(paint.getColorFilter() == nullptr); - SkASSERT(paint.getXfermode() == nullptr); + SkASSERT(paint.isSrcOver()); SkASSERT(paint.getColor() == SK_ColorBLACK); } @@ -381,7 +381,7 @@ void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask, unsigned maskRB = mask.fRowBytes - width; uint32_t expanded32 = fExpandedRaw16; -#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) +#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) #define UNROLL 8 do { int w = width; @@ -475,7 +475,7 @@ void SkRGB16_Opaque_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { unsigned scale5 = SkAlpha255To256(alpha) >> 3; uint32_t src32 = fExpandedRaw16 * scale5; scale5 = 32 - scale5; -#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) +#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32); #else do { @@ -654,7 +654,7 @@ void SkRGB16_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { unsigned scale5 = SkAlpha255To256(alpha) * fScale >> (8 + 3); uint32_t src32 = fExpandedRaw16 * scale5; scale5 = 32 - scale5; -#if SK_ARM_NEON_IS_ALWAYS && defined(SK_CPU_LENDIAN) +#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN) SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32); #else do { @@ -683,7 +683,7 @@ SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkPixmap& device, SkShader::Context* shaderContext) : INHERITED(device, paint, shaderContext) { - SkASSERT(paint.getXfermode() == nullptr); + SkASSERT(paint.isSrcOver()); fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor)); @@ -809,9 +809,8 @@ SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter( SkShader::Context* shaderContext) : INHERITED(device, paint, shaderContext) { - fXfermode = paint.getXfermode(); + fXfermode = SkXfermode::Peek(paint.getBlendMode()); SkASSERT(fXfermode); - fXfermode->ref(); int width = device.width(); fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor)); @@ -819,7 +818,6 @@ SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter( } SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter() { - fXfermode->unref(); sk_free(fBuffer); } @@ -897,14 +895,14 @@ SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, SkBlitter* blitter; SkShader* shader = paint.getShader(); - SkXfermode* mode = paint.getXfermode(); + bool is_srcover = paint.isSrcOver(); // we require a shader if there is an xfermode, handled by our caller - SkASSERT(nullptr == mode || shader); + SkASSERT(is_srcover || shader); if (shader) { SkASSERT(shaderContext != nullptr); - if (mode) { + if (!is_srcover) { blitter = allocator->createT(device, paint, shaderContext); } else { diff --git a/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp b/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp index 27cbd61768ed..cef4cfaa2f09 100644 --- a/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp +++ b/gfx/skia/skia/src/core/SkBlitter_Sprite.cpp @@ -5,10 +5,12 @@ * found in the LICENSE file. */ +#include "SkOpts.h" #include "SkSmallAllocator.h" #include "SkSpriteBlitter.h" -SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source) : fSource(source) {} +SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source) + : fSource(source) {} void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) { fDst = dst; @@ -17,27 +19,124 @@ void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPain fPaint = &paint; } -#ifdef SK_DEBUG void SkSpriteBlitter::blitH(int x, int y, int width) { SkDEBUGFAIL("how did we get here?"); + + // Fallback to blitRect. + this->blitRect(x, y, width, 1); } -void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], - const int16_t runs[]) { +void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { SkDEBUGFAIL("how did we get here?"); + + // No fallback strategy. } void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) { SkDEBUGFAIL("how did we get here?"); + + // Fall back to superclass if the code gets here in release mode. + INHERITED::blitV(x, y, height, alpha); } -void SkSpriteBlitter::blitMask(const SkMask&, const SkIRect& clip) { +void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) { SkDEBUGFAIL("how did we get here?"); + + // Fall back to superclass if the code gets here in release mode. + INHERITED::blitMask(mask, clip); } -#endif /////////////////////////////////////////////////////////////////////////////// +// Only valid if... +// 1. src == dst format +// 2. paint has no modifiers (i.e. alpha, colorfilter, etc.) +// 3. xfermode needs no blending: e.g. kSrc_Mode or kSrcOver_Mode + opaque src +// +class SkSpriteBlitter_Src_SrcOver final : public SkSpriteBlitter { +public: + static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) { + if (dst.colorType() != src.colorType()) { + return false; + } + if (dst.info().gammaCloseToSRGB() != src.info().gammaCloseToSRGB()) { + return false; + } + if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) { + return false; + } + if (0xFF != paint.getAlpha()) { + return false; + } + SkBlendMode mode = paint.getBlendMode(); + if (SkBlendMode::kSrc == mode) { + return true; + } + if (SkBlendMode::kSrcOver == mode && src.isOpaque()) { + return true; + } + + // At this point memcpy can't be used. The following check for using SrcOver. + + if (dst.colorType() != kN32_SkColorType || !dst.info().gammaCloseToSRGB()) { + return false; + } + + return SkBlendMode::kSrcOver == mode; + } + + SkSpriteBlitter_Src_SrcOver(const SkPixmap& src) + : INHERITED(src) {} + + void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override { + SkASSERT(Supports(dst, fSource, paint)); + this->INHERITED::setup(dst, left, top, paint); + SkBlendMode mode = paint.getBlendMode(); + + SkASSERT(mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc); + + if (mode == SkBlendMode::kSrcOver && !fSource.isOpaque()) { + fUseMemcpy = false; + } + } + + void blitRect(int x, int y, int width, int height) override { + SkASSERT(fDst.colorType() == fSource.colorType()); + SkASSERT(fDst.info().gammaCloseToSRGB() == fSource.info().gammaCloseToSRGB()); + SkASSERT(width > 0 && height > 0); + + if (fUseMemcpy) { + char* dst = (char*)fDst.writable_addr(x, y); + const char* src = (const char*)fSource.addr(x - fLeft, y - fTop); + const size_t dstRB = fDst.rowBytes(); + const size_t srcRB = fSource.rowBytes(); + const size_t bytesToCopy = width << fSource.shiftPerPixel(); + + while (height --> 0) { + memcpy(dst, src, bytesToCopy); + dst += dstRB; + src += srcRB; + } + } else { + uint32_t* dst = fDst.writable_addr32(x, y); + const uint32_t* src = fSource.addr32(x - fLeft, y - fTop); + const int dstStride = fDst.rowBytesAsPixels(); + const int srcStride = fSource.rowBytesAsPixels(); + + while (height --> 0) { + SkOpts::srcover_srgb_srgb(dst, src, width, width); + dst += dstStride; + src += srcStride; + } + } + } + +private: + typedef SkSpriteBlitter INHERITED; + + bool fUseMemcpy {true}; +}; + // returning null means the caller will call SkBlitter::Choose() and // have wrapped the source bitmap inside a shader SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, @@ -53,25 +152,34 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, */ SkASSERT(allocator != nullptr); - SkSpriteBlitter* blitter; + // Defer to the general code if the pixels are unpremultipled. This case is not common, + // and this simplifies the code. + if (source.alphaType() == kUnpremul_SkAlphaType) { + return nullptr; + } - switch (dst.colorType()) { - case kRGB_565_SkColorType: - blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator); - break; - case kN32_SkColorType: - if (dst.info().isSRGB()) { - blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator); - } else { - blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); - } - break; - case kRGBA_F16_SkColorType: - blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator); - break; - default: - blitter = nullptr; - break; + SkSpriteBlitter* blitter = nullptr; + + if (SkSpriteBlitter_Src_SrcOver::Supports(dst, source, paint)) { + blitter = allocator->createT(source); + } else { + switch (dst.colorType()) { + case kRGB_565_SkColorType: + blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator); + break; + case kN32_SkColorType: + if (dst.info().gammaCloseToSRGB()) { + blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator); + } else { + blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); + } + break; + case kRGBA_F16_SkColorType: + blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator); + break; + default: + break; + } } if (blitter) { diff --git a/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp b/gfx/skia/skia/src/core/SkBlurImageFilter.cpp similarity index 68% rename from gfx/skia/skia/src/effects/SkBlurImageFilter.cpp rename to gfx/skia/skia/src/core/SkBlurImageFilter.cpp index 10c8a0b17b18..78fa071acd74 100644 --- a/gfx/skia/skia/src/effects/SkBlurImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkBlurImageFilter.cpp @@ -5,8 +5,6 @@ * found in the LICENSE file. */ -#include "SkBlurImageFilter.h" - #include "SkAutoPixmapStorage.h" #include "SkColorPriv.h" #include "SkGpuBlurUtils.h" @@ -20,6 +18,54 @@ #include "SkGr.h" #endif +class SkBlurImageFilterImpl : public SkImageFilter { +public: + SkBlurImageFilterImpl(SkScalar sigmaX, + SkScalar sigmaY, + sk_sp input, + const CropRect* cropRect); + + SkRect computeFastBounds(const SkRect&) const override; + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurImageFilterImpl) + +#ifdef SK_SUPPORT_LEGACY_IMAGEFILTER_PTR + static SkImageFilter* Create(SkScalar sigmaX, SkScalar sigmaY, SkImageFilter* input = nullptr, + const CropRect* cropRect = nullptr) { + return SkImageFilter::MakeBlur(sigmaX, sigmaY, sk_ref_sp(input), + cropRect).release(); + } +#endif + +protected: + void flatten(SkWriteBuffer&) const override; + sk_sp onFilterImage(SkSpecialImage* source, const Context&, + SkIPoint* offset) const override; + SkIRect onFilterNodeBounds(const SkIRect& src, const SkMatrix&, MapDirection) const override; + +private: + SkSize fSigma; + typedef SkImageFilter INHERITED; + + friend class SkImageFilter; +}; + +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkImageFilter) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurImageFilterImpl) +SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END + +/////////////////////////////////////////////////////////////////////////////// + +sk_sp SkImageFilter::MakeBlur(SkScalar sigmaX, SkScalar sigmaY, + sk_sp input, + const CropRect* cropRect) { + if (0 == sigmaX && 0 == sigmaY && !cropRect) { + return input; + } + return sk_sp(new SkBlurImageFilterImpl(sigmaX, sigmaY, input, cropRect)); +} + // This rather arbitrary-looking value results in a maximum box blur kernel size // of 1000 pixels on the raster path, which matches the WebKit and Firefox // implementations. Since the GPU path does not compute a box blur, putting @@ -35,7 +81,7 @@ static SkVector map_sigma(const SkSize& localSigma, const SkMatrix& ctm) { return sigma; } -SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, +SkBlurImageFilterImpl::SkBlurImageFilterImpl(SkScalar sigmaX, SkScalar sigmaY, sk_sp input, const CropRect* cropRect) @@ -43,14 +89,14 @@ SkBlurImageFilter::SkBlurImageFilter(SkScalar sigmaX, , fSigma(SkSize::Make(sigmaX, sigmaY)) { } -sk_sp SkBlurImageFilter::CreateProc(SkReadBuffer& buffer) { +sk_sp SkBlurImageFilterImpl::CreateProc(SkReadBuffer& buffer) { SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); SkScalar sigmaX = buffer.readScalar(); SkScalar sigmaY = buffer.readScalar(); - return Make(sigmaX, sigmaY, common.getInput(0), &common.cropRect()); + return SkImageFilter::MakeBlur(sigmaX, sigmaY, common.getInput(0), &common.cropRect()); } -void SkBlurImageFilter::flatten(SkWriteBuffer& buffer) const { +void SkBlurImageFilterImpl::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); buffer.writeScalar(fSigma.fWidth); buffer.writeScalar(fSigma.fHeight); @@ -71,7 +117,7 @@ static void get_box3_params(SkScalar s, int *kernelSize, int* kernelSize3, int * } } -sk_sp SkBlurImageFilter::onFilterImage(SkSpecialImage* source, +sk_sp SkBlurImageFilterImpl::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); @@ -95,7 +141,11 @@ sk_sp SkBlurImageFilter::onFilterImage(SkSpecialImage* source, const SkVector sigma = map_sigma(fSigma, ctx.ctm()); #if SK_SUPPORT_GPU - if (input->peekTexture() && input->peekTexture()->getContext()) { + if (source->isTextureBacked()) { + GrContext* context = source->getContext(); + sk_sp inputTexture(input->asTextureRef(context)); + SkASSERT(inputTexture); + if (0 == sigma.x() && 0 == sigma.y()) { offset->fX = inputBounds.x(); offset->fY = inputBounds.y(); @@ -103,29 +153,30 @@ sk_sp SkBlurImageFilter::onFilterImage(SkSpecialImage* source, -inputOffset.y())); } - GrTexture* inputTexture = input->peekTexture(); - offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; inputBounds.offset(-inputOffset); dstBounds.offset(-inputOffset); - SkRect inputBoundsF(SkRect::Make(inputBounds)); - SkAutoTUnref tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(), - inputTexture, - false, - source->props().allowSRGBInputs(), - SkRect::Make(dstBounds), - &inputBoundsF, - sigma.x(), - sigma.y())); - if (!tex) { + // We intentionally use the source's color space, not the destination's (from ctx). We + // always blur in the source's config, so we need a compatible color space. We also want to + // avoid doing gamut conversion on every fetch of the texture. + sk_sp drawContext(SkGpuBlurUtils::GaussianBlur( + context, + inputTexture.get(), + sk_ref_sp(source->getColorSpace()), + dstBounds, + &inputBounds, + sigma.x(), + sigma.y())); + if (!drawContext) { return nullptr; } - return SkSpecialImage::MakeFromGpu(source->internal_getProxy(), - SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), + // TODO: Get the colorSpace from the drawContext (once it has one) + return SkSpecialImage::MakeFromGpu(SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), kNeedNewImageUniqueID_SpecialImage, - tex, &source->props()); + drawContext->asTexture(), + sk_ref_sp(input->getColorSpace()), &source->props()); } #endif @@ -145,39 +196,39 @@ sk_sp SkBlurImageFilter::onFilterImage(SkSpecialImage* source, -inputOffset.y())); } - SkPixmap inputPixmap; + SkBitmap inputBM; - if (!input->peekPixels(&inputPixmap)) { + if (!input->getROPixels(&inputBM)) { return nullptr; } - if (inputPixmap.colorType() != kN32_SkColorType) { + if (inputBM.colorType() != kN32_SkColorType) { return nullptr; } SkImageInfo info = SkImageInfo::Make(dstBounds.width(), dstBounds.height(), - inputPixmap.colorType(), inputPixmap.alphaType()); + inputBM.colorType(), inputBM.alphaType()); SkBitmap tmp, dst; if (!tmp.tryAllocPixels(info) || !dst.tryAllocPixels(info)) { return nullptr; } - SkAutoLockPixels tmpLock(tmp), dstLock(dst); + SkAutoLockPixels inputLock(inputBM), tmpLock(tmp), dstLock(dst); offset->fX = dstBounds.fLeft; offset->fY = dstBounds.fTop; SkPMColor* t = tmp.getAddr32(0, 0); SkPMColor* d = dst.getAddr32(0, 0); int w = dstBounds.width(), h = dstBounds.height(); - const SkPMColor* s = inputPixmap.addr32(inputBounds.x() - inputOffset.x(), - inputBounds.y() - inputOffset.y()); + const SkPMColor* s = inputBM.getAddr32(inputBounds.x() - inputOffset.x(), + inputBounds.y() - inputOffset.y()); inputBounds.offset(-dstBounds.x(), -dstBounds.y()); dstBounds.offset(-dstBounds.x(), -dstBounds.y()); SkIRect inputBoundsT = SkIRect::MakeLTRB(inputBounds.top(), inputBounds.left(), inputBounds.bottom(), inputBounds.right()); SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width()); - int sw = int(inputPixmap.rowBytes() >> 2); + int sw = int(inputBM.rowBytes() >> 2); /** * @@ -214,21 +265,20 @@ sk_sp SkBlurImageFilter::onFilterImage(SkSpecialImage* source, SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w); } - return SkSpecialImage::MakeFromRaster(source->internal_getProxy(), - SkIRect::MakeWH(dstBounds.width(), + return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(dstBounds.width(), dstBounds.height()), dst, &source->props()); } -SkRect SkBlurImageFilter::computeFastBounds(const SkRect& src) const { +SkRect SkBlurImageFilterImpl::computeFastBounds(const SkRect& src) const { SkRect bounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; bounds.outset(SkScalarMul(fSigma.width(), SkIntToScalar(3)), SkScalarMul(fSigma.height(), SkIntToScalar(3))); return bounds; } -SkIRect SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, +SkIRect SkBlurImageFilterImpl::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection) const { SkVector sigma = map_sigma(fSigma, ctm); return src.makeOutset(SkScalarCeilToInt(SkScalarMul(sigma.x(), SkIntToScalar(3))), @@ -236,8 +286,8 @@ SkIRect SkBlurImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix } #ifndef SK_IGNORE_TO_STRING -void SkBlurImageFilter::toString(SkString* str) const { - str->appendf("SkBlurImageFilter: ("); +void SkBlurImageFilterImpl::toString(SkString* str) const { + str->appendf("SkBlurImageFilterImpl: ("); str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); if (this->getInput(0)) { diff --git a/gfx/skia/skia/src/core/SkCanvas.cpp b/gfx/skia/skia/src/core/SkCanvas.cpp index a23764ce22aa..505592d0f294 100644 --- a/gfx/skia/skia/src/core/SkCanvas.cpp +++ b/gfx/skia/skia/src/core/SkCanvas.cpp @@ -10,7 +10,6 @@ #include "SkCanvasPriv.h" #include "SkClipStack.h" #include "SkColorFilter.h" -#include "SkDevice.h" #include "SkDraw.h" #include "SkDrawable.h" #include "SkDrawFilter.h" @@ -18,15 +17,21 @@ #include "SkErrorInternals.h" #include "SkImage.h" #include "SkImage_Base.h" +#include "SkImageFilter.h" +#include "SkImageFilterCache.h" +#include "SkLatticeIter.h" #include "SkMatrixUtils.h" #include "SkMetaData.h" -#include "SkNinePatchIter.h" +#include "SkNx.h" #include "SkPaintPriv.h" #include "SkPatchUtils.h" #include "SkPicture.h" +#include "SkRadialShadowMapShader.h" #include "SkRasterClip.h" #include "SkReadPixelsRec.h" #include "SkRRect.h" +#include "SkShadowPaintFilterCanvas.h" +#include "SkShadowShader.h" #include "SkSmallAllocator.h" #include "SkSpecialImage.h" #include "SkSurface_Base.h" @@ -34,13 +39,13 @@ #include "SkTextFormatParams.h" #include "SkTLazy.h" #include "SkTraceEvent.h" - #include #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrRenderTarget.h" -#include "SkGr.h" +#include "SkGrPriv.h" + #endif #define RETURN_ON_NULL(ptr) do { if (nullptr == (ptr)) return; } while (0) @@ -72,12 +77,12 @@ bool SkCanvas::wouldOverwriteEntireSurface(const SkRect* rect, const SkPaint* pa } if (rect) { - if (!this->getTotalMatrix().rectStaysRect()) { + if (!this->getTotalMatrix().isScaleTranslate()) { return false; // conservative } SkRect devRect; - this->getTotalMatrix().mapRect(&devRect, *rect); + this->getTotalMatrix().mapRectScaleTranslate(&devRect, *rect); if (!devRect.contains(bounds)) { return false; } @@ -116,7 +121,6 @@ bool SkCanvas::Internal_Private_GetTreatSpriteAsBitmap() { } // experimental for faster tiled drawing... -//#define SK_ENABLE_CLIP_QUICKREJECT //#define SK_TRACE_SAVERESTORE #ifdef SK_TRACE_SAVERESTORE @@ -169,19 +173,6 @@ void SkCanvas::predrawNotify(const SkRect* rect, const SkPaint* paint, /////////////////////////////////////////////////////////////////////////////// -static uint32_t filter_paint_flags(const SkSurfaceProps& props, uint32_t flags) { - const uint32_t propFlags = props.flags(); - if (propFlags & SkSurfaceProps::kDisallowDither_Flag) { - flags &= ~SkPaint::kDither_Flag; - } - if (propFlags & SkSurfaceProps::kDisallowAntiAlias_Flag) { - flags &= ~SkPaint::kAntiAlias_Flag; - } - return flags; -} - -/////////////////////////////////////////////////////////////////////////////// - /* This is the record we keep for each SkBaseDevice that the user installs. The clip/matrix/proc are fields that reflect the top of the save/restore stack. Whenever the canvas changes, it marks a dirty flag, and then before @@ -196,27 +187,21 @@ struct DeviceCM { SkPaint* fPaint; // may be null (in the future) const SkMatrix* fMatrix; SkMatrix fMatrixStorage; - const bool fDeviceIsBitmapDevice; + SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer DeviceCM(SkBaseDevice* device, const SkPaint* paint, SkCanvas* canvas, - bool conservativeRasterClip, bool deviceIsBitmapDevice) + bool conservativeRasterClip, const SkMatrix& stashed) : fNext(nullptr) , fClip(conservativeRasterClip) - , fDeviceIsBitmapDevice(deviceIsBitmapDevice) + , fStashedMatrix(stashed) { - if (nullptr != device) { - device->ref(); - device->onAttachToCanvas(canvas); - } + SkSafeRef(device); fDevice = device; fPaint = paint ? new SkPaint(*paint) : nullptr; } ~DeviceCM() { - if (fDevice) { - fDevice->onDetachFromCanvas(); - fDevice->unref(); - } + SkSafeUnref(fDevice); delete fPaint; } @@ -228,7 +213,7 @@ struct DeviceCM { } void updateMC(const SkMatrix& totalMatrix, const SkRasterClip& totalClip, - const SkClipStack& clipStack, SkRasterClip* updateClip) { + SkRasterClip* updateClip) { int x = fDevice->getOrigin().x(); int y = fDevice->getOrigin().y(); int width = fDevice->width(); @@ -255,8 +240,6 @@ struct DeviceCM { SkRegion::kDifference_Op); } - fDevice->setMatrixClip(*fMatrix, fClip.forceGetBW(), clipStack); - #ifdef SK_DEBUG if (!fClip.isEmpty()) { SkIRect deviceR; @@ -289,17 +272,22 @@ public: SkMatrix fMatrix; int fDeferredSaveCount; + // This is the current cumulative depth (aggregate of all done translateZ calls) + SkScalar fCurDrawDepth; + MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) { fFilter = nullptr; fLayer = nullptr; fTopLayer = nullptr; fMatrix.reset(); fDeferredSaveCount = 0; + fCurDrawDepth = 0; // don't bother initializing fNext inc_rec(); } - MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix) { + MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatrix), + fCurDrawDepth(prev.fCurDrawDepth) { fFilter = SkSafeRef(prev.fFilter); fLayer = nullptr; fTopLayer = prev.fTopLayer; @@ -324,31 +312,48 @@ public: } }; +static SkIRect compute_device_bounds(SkBaseDevice* device) { + return SkIRect::MakeXYWH(device->getOrigin().x(), device->getOrigin().y(), + device->width(), device->height()); +} + class SkDrawIter : public SkDraw { public: - SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) { + SkDrawIter(SkCanvas* canvas) { canvas = canvas->canvasForDrawIter(); - fCanvas = canvas; canvas->updateDeviceCMCache(); fClipStack = canvas->fClipStack; fCurrLayer = canvas->fMCRec->fTopLayer; - fSkipEmptyClips = skipEmptyClips; + + fMultiDeviceCS = nullptr; + if (fCurrLayer->fNext) { + fMultiDeviceCS = canvas->fClipStack; + fMultiDeviceCS->save(); + } + } + + ~SkDrawIter() { + if (fMultiDeviceCS) { + fMultiDeviceCS->restore(); + } } bool next() { + if (fMultiDeviceCS && fDevice) { + // remove the previous device's bounds + fMultiDeviceCS->clipDevRect(compute_device_bounds(fDevice), SkCanvas::kDifference_Op); + } + // skip over recs with empty clips - if (fSkipEmptyClips) { - while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { - fCurrLayer = fCurrLayer->fNext; - } + while (fCurrLayer && fCurrLayer->fClip.isEmpty()) { + fCurrLayer = fCurrLayer->fNext; } const DeviceCM* rec = fCurrLayer; if (rec && rec->fDevice) { fMatrix = rec->fMatrix; - fClip = &((SkRasterClip*)&rec->fClip)->forceGetBW(); fRC = &rec->fClip; fDevice = rec->fDevice; if (!fDevice->accessPixels(&fDst)) { @@ -366,17 +371,16 @@ public: } SkBaseDevice* getDevice() const { return fDevice; } + const SkRasterClip& getClip() const { return *fRC; } int getX() const { return fDevice->getOrigin().x(); } int getY() const { return fDevice->getOrigin().y(); } const SkMatrix& getMatrix() const { return *fMatrix; } - const SkRegion& getClip() const { return *fClip; } const SkPaint* getPaint() const { return fPaint; } private: - SkCanvas* fCanvas; const DeviceCM* fCurrLayer; const SkPaint* fPaint; // May be null. - SkBool8 fSkipEmptyClips; + SkClipStack* fMultiDeviceCS; typedef SkDraw INHERITED; }; @@ -441,8 +445,7 @@ public: // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the // paint. It's used to determine the size of the offscreen layer for filters. // If null, the clip will be used instead. - AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint, - bool skipLayerForImageFilter = false, + AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false, const SkRect* rawBounds = nullptr) : fOrigPaint(paint) { fCanvas = canvas; #ifdef SK_SUPPORT_LEGACY_DRAWFILTER @@ -481,7 +484,7 @@ public: */ SkPaint tmp; tmp.setImageFilter(fPaint->getImageFilter()); - tmp.setXfermode(sk_ref_sp(fPaint->getXfermode())); + tmp.setBlendMode(fPaint->getBlendMode()); SkRect storage; if (rawBounds) { // Make rawBounds include all paint outsets except for those due to image filters. @@ -503,15 +506,6 @@ public: // can we be marked as simple? fIsSimple = !fFilter && !fTempLayerForImageFilter; } - - uint32_t oldFlags = paint.getFlags(); - fNewPaintFlags = filter_paint_flags(props, oldFlags); - if (fIsSimple && (fNewPaintFlags != oldFlags)) { - SkPaint* paint = set_if_needed(&fLazyPaintInit, fOrigPaint); - paint->setFlags(fNewPaintFlags); - fPaint = paint; - // if we're not simple, doNext() will take care of calling setFlags() - } } ~AutoDrawLooper() { @@ -545,7 +539,6 @@ private: SkDrawFilter* fFilter; const SkPaint* fPaint; int fSaveCount; - uint32_t fNewPaintFlags; bool fTempLayerForImageFilter; bool fDone; bool fIsSimple; @@ -562,11 +555,10 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { SkPaint* paint = fLazyPaintPerLooper.set(fLazyPaintInit.isValid() ? *fLazyPaintInit.get() : fOrigPaint); - paint->setFlags(fNewPaintFlags); if (fTempLayerForImageFilter) { paint->setImageFilter(nullptr); - paint->setXfermode(nullptr); + paint->setBlendMode(SkBlendMode::kSrcOver); } if (fLooperContext && !fLooperContext->next(fCanvas, paint)) { @@ -600,28 +592,28 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { ////////// macros to place around the internal draw calls ////////////////// -#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \ - this->predrawNotify(); \ - AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \ - while (looper.next(SkDrawFilter::kBitmap_Type)) { \ +#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \ + this->predrawNotify(); \ + AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \ + while (looper.next(SkDrawFilter::kBitmap_Type)) { \ SkDrawIter iter(this); #define LOOPER_BEGIN_DRAWDEVICE(paint, type) \ this->predrawNotify(); \ - AutoDrawLooper looper(this, fProps, paint, true); \ + AutoDrawLooper looper(this, paint, true); \ while (looper.next(type)) { \ SkDrawIter iter(this); #define LOOPER_BEGIN(paint, type, bounds) \ this->predrawNotify(); \ - AutoDrawLooper looper(this, fProps, paint, false, bounds); \ + AutoDrawLooper looper(this, paint, false, bounds); \ while (looper.next(type)) { \ SkDrawIter iter(this); #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ this->predrawNotify(bounds, &paint, auxOpaque); \ - AutoDrawLooper looper(this, fProps, paint, false, bounds); \ + AutoDrawLooper looper(this, paint, false, bounds); \ while (looper.next(type)) { \ SkDrawIter iter(this); @@ -629,16 +621,28 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) { //////////////////////////////////////////////////////////////////////////// +static inline SkRect qr_clip_bounds(const SkIRect& bounds) { + if (bounds.isEmpty()) { + return SkRect::MakeEmpty(); + } + + // Expand bounds out by 1 in case we are anti-aliasing. We store the + // bounds as floats to enable a faster quick reject implementation. + SkRect dst; + SkNx_cast(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft); + return dst; +} + void SkCanvas::resetForNextPicture(const SkIRect& bounds) { this->restoreToCount(1); - fCachedLocalClipBounds.setEmpty(); - fCachedLocalClipBoundsDirty = true; fClipStack->reset(); fMCRec->reset(bounds); // We're peering through a lot of structs here. Only at this scope do we // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice). static_cast(fMCRec->fLayer->fDevice)->setNewSize(bounds.size()); + fDeviceClipBounds = qr_clip_bounds(bounds); + fIsScaleTranslate = true; } SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { @@ -649,22 +653,24 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { // const-cast. *const_cast(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag); - fCachedLocalClipBounds.setEmpty(); - fCachedLocalClipBoundsDirty = true; - fAllowSoftClip = true; fAllowSimplifyClip = false; fDeviceCMDirty = true; fSaveCount = 1; fMetaData = nullptr; +#ifdef SK_EXPERIMENTAL_SHADOWING + fLights = nullptr; +#endif fClipStack.reset(new SkClipStack); fMCRec = (MCRec*)fMCStack.push_back(); new (fMCRec) MCRec(fConservativeRasterClip); + fIsScaleTranslate = true; SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; - new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, false); + new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRasterClip, + fMCRec->fMatrix); fMCRec->fTopLayer = fMCRec->fLayer; @@ -673,10 +679,11 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { if (device) { // The root device and the canvas should always have the same pixel geometry SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry()); - device->onAttachToCanvas(this); fMCRec->fLayer->fDevice = SkRef(device); fMCRec->fRasterClip.setRect(device->getGlobalBounds()); + fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds()); } + return device; } @@ -807,6 +814,10 @@ SkMetaData& SkCanvas::getMetaData() { /////////////////////////////////////////////////////////////////////////////// void SkCanvas::flush() { + this->onFlush(); +} + +void SkCanvas::onFlush() { SkBaseDevice* device = this->getDevice(); if (device) { device->flush(); @@ -841,7 +852,7 @@ SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { } bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { - if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) { + if (kUnknown_SkColorType == bitmap->colorType()) { return false; } @@ -903,10 +914,6 @@ bool SkCanvas::readPixels(const SkImageInfo& dstInfo, void* dstP, size_t rowByte } bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) { - if (bitmap.getTexture()) { - return false; - } - SkAutoPixmapUnlock unlocker; if (bitmap.requestLock(&unlocker)) { const SkPixmap& pm = unlocker.pixmap(); @@ -973,11 +980,11 @@ void SkCanvas::updateDeviceCMCache() { DeviceCM* layer = fMCRec->fTopLayer; if (nullptr == layer->fNext) { // only one layer - layer->updateMC(totalMatrix, totalClip, *fClipStack, nullptr); + layer->updateMC(totalMatrix, totalClip, nullptr); } else { SkRasterClip clip(totalClip); do { - layer->updateMC(totalMatrix, clip, *fClipStack, &clip); + layer->updateMC(totalMatrix, clip, &clip); } while ((layer = layer->fNext) != nullptr); } fDeviceCMDirty = false; @@ -1060,11 +1067,7 @@ void SkCanvas::internalSave() { } bool SkCanvas::BoundsAffectsClip(SaveLayerFlags saveLayerFlags) { -#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG return !(saveLayerFlags & SkCanvas::kDontClipToLayer_PrivateSaveLayerFlag); -#else - return true; -#endif } bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlags, @@ -1091,8 +1094,8 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag // early exit if the layer's bounds are clipped out if (!ir.intersect(clipBounds)) { if (BoundsAffectsClip(saveLayerFlags)) { - fCachedLocalClipBoundsDirty = true; fMCRec->fRasterClip.setEmpty(); + fDeviceClipBounds.setEmpty(); } return false; } @@ -1103,9 +1106,9 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag if (BoundsAffectsClip(saveLayerFlags)) { // Simplify the current clips since they will be applied properly during restore() - fCachedLocalClipBoundsDirty = true; - fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); + fClipStack->clipDevRect(ir, kReplace_Op); fMCRec->fRasterClip.setRect(ir); + fDeviceClipBounds = qr_clip_bounds(ir); } if (intersection) { @@ -1134,44 +1137,36 @@ int SkCanvas::saveLayer(const SaveLayerRec& origRec) { return this->getSaveCount() - 1; } -static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filter, - SkBaseDevice* dst, const SkMatrix& ctm) { - - SkBitmap srcBM; - -#if SK_SUPPORT_GPU - GrRenderTarget* srcRT = src->accessRenderTarget(); - if (srcRT && !srcRT->asTexture() && dst->accessRenderTarget()) { - // When both the src & the dst are on the gpu but the src doesn't have a texture, - // we create a temporary texture for the draw. - // TODO: we should actually only copy the portion of the source needed to apply the image - // filter - GrContext* context = srcRT->getContext(); - SkAutoTUnref tex(context->textureProvider()->createTexture(srcRT->desc(), - SkBudgeted::kYes)); - - context->copySurface(tex, srcRT); - - GrWrapTextureInBitmap(tex, src->width(), src->height(), src->isOpaque(), &srcBM); - } else -#endif - { - srcBM = src->accessBitmap(false); +void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filter, + SkBaseDevice* dst, const SkMatrix& ctm, + const SkClipStack* clipStack) { + SkDraw draw; + SkRasterClip rc; + rc.setRect(SkIRect::MakeWH(dst->width(), dst->height())); + if (!dst->accessPixels(&draw.fDst)) { + draw.fDst.reset(dst->imageInfo(), nullptr, 0); } - - SkCanvas c(dst); + draw.fMatrix = &SkMatrix::I(); + draw.fRC = &rc; + draw.fClipStack = clipStack; + draw.fDevice = dst; SkPaint p; p.setImageFilter(filter->makeWithLocalMatrix(ctm)); - const SkScalar x = SkIntToScalar(src->getOrigin().x()); - const SkScalar y = SkIntToScalar(src->getOrigin().y()); - c.drawBitmap(srcBM, x, y, &p); + + int x = src->getOrigin().x() - dst->getOrigin().x(); + int y = src->getOrigin().y() - dst->getOrigin().y(); + auto special = src->snapSpecial(); + if (special) { + dst->drawSpecial(draw, special.get(), x, y, p); + } } static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque, const SkPaint* paint) { // need to force L32 for now if we have an image filter. Once filters support other colortypes // e.g. sRGB or F16, we can remove this check + // SRGBTODO: Can we remove this check now? const bool hasImageFilter = paint && paint->getImageFilter(); SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; @@ -1180,7 +1175,7 @@ static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool i return SkImageInfo::MakeN32(w, h, alphaType); } else { // keep the same characteristics as the prev - return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType()); + return SkImageInfo::Make(w, h, prev.colorType(), alphaType, sk_ref_sp(prev.colorSpace())); } } @@ -1189,9 +1184,39 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra const SkPaint* paint = rec.fPaint; SaveLayerFlags saveLayerFlags = rec.fSaveLayerFlags; -#ifndef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG - saveLayerFlags &= ~kDontClipToLayer_PrivateSaveLayerFlag; -#endif + SkLazyPaint lazyP; + SkImageFilter* imageFilter = paint ? paint->getImageFilter() : NULL; + SkMatrix stashedMatrix = fMCRec->fMatrix; + SkMatrix remainder; + SkSize scale; + /* + * ImageFilters (so far) do not correctly handle matrices (CTM) that contain rotation/skew/etc. + * but they do handle scaling. To accommodate this, we do the following: + * + * 1. Stash off the current CTM + * 2. Decompose the CTM into SCALE and REMAINDER + * 3. Wack the CTM to be just SCALE, and wrap the imagefilter with a MatrixImageFilter that + * contains the REMAINDER + * 4. Proceed as usual, allowing the client to draw into the layer (now with a scale-only CTM) + * 5. During restore, we process the MatrixImageFilter, which applies REMAINDER to the output + * of the original imagefilter, and draw that (via drawSprite) + * 6. Unwack the CTM to its original state (i.e. stashedMatrix) + * + * Perhaps in the future we could augment #5 to apply REMAINDER as part of the draw (no longer + * a sprite operation) to avoid the extra buffer/overhead of MatrixImageFilter. + */ + if (imageFilter && !stashedMatrix.isScaleTranslate() && !imageFilter->canHandleComplexCTM() && + stashedMatrix.decomposeScale(&scale, &remainder)) + { + // We will restore the matrix (which we are overwriting here) in restore via fStashedMatrix + this->internalSetMatrix(SkMatrix::MakeScale(scale.width(), scale.height())); + SkPaint* p = lazyP.set(*paint); + p->setImageFilter(SkImageFilter::MakeMatrixFilter(remainder, + SkFilterQuality::kLow_SkFilterQuality, + sk_ref_sp(imageFilter))); + imageFilter = p->getImageFilter(); + paint = p; + } // do this before we create the layer. We don't call the public save() since // that would invoke a possibly overridden virtual @@ -1200,7 +1225,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra fDeviceCMDirty = true; SkIRect ir; - if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, paint ? paint->getImageFilter() : nullptr)) { + if (!this->clipRectBounds(bounds, saveLayerFlags, &ir, imageFilter)) { return; } @@ -1220,49 +1245,41 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra } } - SkBaseDevice* device = this->getTopDevice(); - if (nullptr == device) { + SkBaseDevice* priorDevice = this->getTopDevice(); + if (nullptr == priorDevice) { SkDebugf("Unable to find device for layer."); return; } - SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque, + SkImageInfo info = make_layer_info(priorDevice->imageInfo(), ir.width(), ir.height(), isOpaque, paint); - bool forceSpriteOnRestore = false; + SkAutoTUnref newDevice; { const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || (saveLayerFlags & kPreserveLCDText_SaveLayerFlag); const SkBaseDevice::TileUsage usage = SkBaseDevice::kNever_TileUsage; const SkBaseDevice::CreateInfo createInfo = SkBaseDevice::CreateInfo(info, usage, geo, - preserveLCDText, false); - SkBaseDevice* newDev = device->onCreateDevice(createInfo, paint); - if (nullptr == newDev) { - // If onCreateDevice didn't succeed, try raster (e.g. PDF couldn't handle the paint) - const SkSurfaceProps surfaceProps(fProps.flags(), createInfo.fPixelGeometry); - newDev = SkBitmapDevice::Create(createInfo.fInfo, surfaceProps); - if (nullptr == newDev) { - SkErrorInternals::SetError(kInternalError_SkError, - "Unable to create device for layer."); - return; - } - forceSpriteOnRestore = true; + preserveLCDText); + newDevice.reset(priorDevice->onCreateDevice(createInfo, paint)); + if (!newDevice) { + SkErrorInternals::SetError(kInternalError_SkError, + "Unable to create device for layer."); + return; } - device = newDev; } - device->setOrigin(ir.fLeft, ir.fTop); + newDevice->setOrigin(ir.fLeft, ir.fTop); - if (rec.fBackdrop) { - draw_filter_into_device(fMCRec->fTopLayer->fDevice, rec.fBackdrop, device, fMCRec->fMatrix); - } - - DeviceCM* layer = - new DeviceCM(device, paint, this, fConservativeRasterClip, forceSpriteOnRestore); - device->unref(); + DeviceCM* layer = new DeviceCM(newDevice, paint, this, fConservativeRasterClip, stashedMatrix); layer->fNext = fMCRec->fTopLayer; fMCRec->fLayer = layer; fMCRec->fTopLayer = layer; // this field is NOT an owner of layer + + if (rec.fBackdrop) { + DrawDeviceWithFilter(priorDevice, rec.fBackdrop, newDevice, + fMCRec->fMatrix, this->getClipStack()); + } } int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { @@ -1279,7 +1296,6 @@ void SkCanvas::internalRestore() { SkASSERT(fMCStack.count() != 0); fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; fClipStack->restore(); @@ -1300,8 +1316,9 @@ void SkCanvas::internalRestore() { if (layer) { if (layer->fNext) { const SkIPoint& origin = layer->fDevice->getOrigin(); - this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), - layer->fPaint, layer->fDeviceIsBitmapDevice); + this->internalDrawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint); + // restore what we smashed in internalSaveLayer + fMCRec->fMatrix = layer->fStashedMatrix; // reset this, since internalDrawDevice will have set it to true fDeviceCMDirty = true; delete layer; @@ -1309,8 +1326,14 @@ void SkCanvas::internalRestore() { // we're at the root SkASSERT(layer == (void*)fDeviceCMStorage); layer->~DeviceCM(); + // no need to update fMCRec, 'cause we're killing the canvas } } + + if (fMCRec) { + fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); + } } sk_sp SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) { @@ -1326,6 +1349,10 @@ sk_sp SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface } SkImageInfo SkCanvas::imageInfo() const { + return this->onImageInfo(); +} + +SkImageInfo SkCanvas::onImageInfo() const { SkBaseDevice* dev = this->getDevice(); if (dev) { return dev->imageInfo(); @@ -1335,6 +1362,10 @@ SkImageInfo SkCanvas::imageInfo() const { } bool SkCanvas::getProps(SkSurfaceProps* props) const { + return this->onGetProps(props); +} + +bool SkCanvas::onGetProps(SkSurfaceProps* props) const { SkBaseDevice* dev = this->getDevice(); if (dev) { if (props) { @@ -1395,62 +1426,42 @@ bool SkCanvas::onAccessTopLayerPixels(SkPixmap* pmap) { ///////////////////////////////////////////////////////////////////////////// -void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, - const SkPaint* paint, bool deviceIsBitmapDevice) { +void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, int x, int y, const SkPaint* paint) { SkPaint tmp; if (nullptr == paint) { paint = &tmp; } LOOPER_BEGIN_DRAWDEVICE(*paint, SkDrawFilter::kBitmap_Type) + while (iter.next()) { SkBaseDevice* dstDev = iter.fDevice; paint = &looper.paint(); SkImageFilter* filter = paint->getImageFilter(); SkIPoint pos = { x - iter.getX(), y - iter.getY() }; - if (filter && !dstDev->canHandleImageFilter(filter)) { - SkImageFilter::DeviceProxy proxy(dstDev); - SkIPoint offset = SkIPoint::Make(0, 0); - const SkBitmap& srcBM = srcDev->accessBitmap(false); - SkMatrix matrix = *iter.fMatrix; - matrix.postTranslate(SkIntToScalar(-pos.x()), SkIntToScalar(-pos.y())); - const SkIRect clipBounds = iter.fClip->getBounds().makeOffset(-pos.x(), -pos.y()); - SkAutoTUnref cache(dstDev->getImageFilterCache()); - SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); - - sk_sp srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM, - &dstDev->surfaceProps())); - if (!srcImg) { - continue; // something disastrous happened - } - - sk_sp resultImg(filter->filterImage(srcImg.get(), ctx, &offset)); - if (resultImg) { - SkPaint tmpUnfiltered(*paint); - tmpUnfiltered.setImageFilter(nullptr); - SkBitmap resultBM; - if (resultImg->internal_getBM(&resultBM)) { - // TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073) - dstDev->drawSprite(iter, resultBM, pos.x() + offset.x(), pos.y() + offset.y(), - tmpUnfiltered); - } - } - } else if (deviceIsBitmapDevice) { - const SkBitmap& src = static_cast(srcDev)->fBitmap; - dstDev->drawSprite(iter, src, pos.x(), pos.y(), *paint); + if (filter) { + dstDev->drawSpecial(iter, srcDev->snapSpecial().get(), pos.x(), pos.y(), *paint); } else { dstDev->drawDevice(iter, srcDev, pos.x(), pos.y(), *paint); } } + LOOPER_END } ///////////////////////////////////////////////////////////////////////////// void SkCanvas::translate(SkScalar dx, SkScalar dy) { - SkMatrix m; - m.setTranslate(dx, dy); - this->concat(m); + if (dx || dy) { + this->checkForDeferredSave(); + fDeviceCMDirty = true; + fMCRec->fMatrix.preTranslate(dx,dy); + + // Translate shouldn't affect the is-scale-translateness of the matrix. + SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate()); + + this->didTranslate(dx,dy); + } } void SkCanvas::scale(SkScalar sx, SkScalar sy) { @@ -1465,6 +1476,12 @@ void SkCanvas::rotate(SkScalar degrees) { this->concat(m); } +void SkCanvas::rotate(SkScalar degrees, SkScalar px, SkScalar py) { + SkMatrix m; + m.setRotate(degrees, px, py); + this->concat(m); +} + void SkCanvas::skew(SkScalar sx, SkScalar sy) { SkMatrix m; m.setSkew(sx, sy); @@ -1478,103 +1495,66 @@ void SkCanvas::concat(const SkMatrix& matrix) { this->checkForDeferredSave(); fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; fMCRec->fMatrix.preConcat(matrix); - + fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); this->didConcat(matrix); } +void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { + fDeviceCMDirty = true; + fMCRec->fMatrix = matrix; + fIsScaleTranslate = matrix.isScaleTranslate(); +} + void SkCanvas::setMatrix(const SkMatrix& matrix) { this->checkForDeferredSave(); - fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - fMCRec->fMatrix = matrix; + this->internalSetMatrix(matrix); this->didSetMatrix(matrix); } void SkCanvas::resetMatrix() { - SkMatrix matrix; - - matrix.reset(); - this->setMatrix(matrix); + this->setMatrix(SkMatrix::I()); } +#ifdef SK_EXPERIMENTAL_SHADOWING +void SkCanvas::translateZ(SkScalar z) { + this->checkForDeferredSave(); + this->fMCRec->fCurDrawDepth += z; + this->didTranslateZ(z); +} + +SkScalar SkCanvas::getZ() const { + return this->fMCRec->fCurDrawDepth; +} + +void SkCanvas::setLights(sk_sp lights) { + this->fLights = lights; +} + +sk_sp SkCanvas::getLights() const { + return this->fLights; +} +#endif + ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { +void SkCanvas::clipRect(const SkRect& rect, ClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; this->onClipRect(rect, op, edgeStyle); } -void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { -#ifdef SK_ENABLE_CLIP_QUICKREJECT - if (SkRegion::kIntersect_Op == op) { - if (fMCRec->fRasterClip.isEmpty()) { - return false; - } - - if (this->quickReject(rect)) { - fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - - fClipStack->clipEmpty(); - return fMCRec->fRasterClip.setEmpty(); - } - } -#endif - - if (!fAllowSoftClip) { - edgeStyle = kHard_ClipEdgeStyle; - } - - const bool rectStaysRect = fMCRec->fMatrix.rectStaysRect(); - SkRect devR; - if (rectStaysRect) { - fMCRec->fMatrix.mapRect(&devR, rect); - } - - // Check if we can quick-accept the clip call (and do nothing) - // - // TODO: investigate if a (conservative) version of this could be done in ::clipRect, - // so that subclasses (like PictureRecording) didn't see unnecessary clips, which in turn - // might allow lazy save/restores to eliminate entire save/restore blocks. - // - if (SkRegion::kIntersect_Op == op && - kHard_ClipEdgeStyle == edgeStyle - && rectStaysRect) - { - if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { -#if 0 - SkDebugf("------- ignored clipRect [%g %g %g %g]\n", - rect.left(), rect.top(), rect.right(), rect.bottom()); -#endif - return; - } - } - +void SkCanvas::onClipRect(const SkRect& rect, ClipOp op, ClipEdgeStyle edgeStyle) { + const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; AutoValidateClip avc(this); - + fClipStack->clipRect(rect, fMCRec->fMatrix, op, isAA); + fMCRec->fRasterClip.op(rect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op, + isAA); fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - - if (rectStaysRect) { - const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; - fClipStack->clipDevRect(devR, op, isAA); - fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); - } else { - // since we're rotated or some such thing, we convert the rect to a path - // and clip against that, since it can handle any matrix. However, to - // avoid recursion in the case where we are subclassed (e.g. Pictures) - // we explicitly call "our" version of clipPath. - SkPath path; - - path.addRect(rect); - this->SkCanvas::onClipPath(path, op, edgeStyle); - } + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } -void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { +void SkCanvas::clipRRect(const SkRRect& rrect, ClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; if (rrect.isRect()) { @@ -1584,31 +1564,20 @@ void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { } } -void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { - SkRRect transformedRRect; - if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { - AutoValidateClip avc(this); +void SkCanvas::onClipRRect(const SkRRect& rrect, ClipOp op, ClipEdgeStyle edgeStyle) { + AutoValidateClip avc(this); - fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - if (!fAllowSoftClip) { - edgeStyle = kHard_ClipEdgeStyle; - } + fDeviceCMDirty = true; - fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edgeStyle); - - fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, - kSoft_ClipEdgeStyle == edgeStyle); - return; - } - - SkPath path; - path.addRRect(rrect); - // call the non-virtual version - this->SkCanvas::onClipPath(path, op, edgeStyle); + bool isAA = kSoft_ClipEdgeStyle == edgeStyle; + fClipStack->clipRRect(rrect, fMCRec->fMatrix, op, isAA); + fMCRec->fRasterClip.op(rrect, fMCRec->fMatrix, this->getTopLayerBounds(), (SkRegion::Op)op, + isAA); + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); + return; } -void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { +void SkCanvas::clipPath(const SkPath& path, ClipOp op, bool doAA) { this->checkForDeferredSave(); ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; @@ -1633,75 +1602,44 @@ void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { this->onClipPath(path, op, edgeStyle); } -void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { -#ifdef SK_ENABLE_CLIP_QUICKREJECT - if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { - if (fMCRec->fRasterClip.isEmpty()) { - return false; - } - - if (this->quickReject(path.getBounds())) { - fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - - fClipStack->clipEmpty(); - return fMCRec->fRasterClip.setEmpty(); - } - } -#endif - +void SkCanvas::onClipPath(const SkPath& path, ClipOp op, ClipEdgeStyle edgeStyle) { AutoValidateClip avc(this); fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; - if (!fAllowSoftClip) { - edgeStyle = kHard_ClipEdgeStyle; - } + bool isAA = kSoft_ClipEdgeStyle == edgeStyle; - SkPath devPath; - path.transform(fMCRec->fMatrix, &devPath); - - // Check if the transfomation, or the original path itself - // made us empty. Note this can also happen if we contained NaN - // values. computing the bounds detects this, and will set our - // bounds to empty if that is the case. (see SkRect::set(pts, count)) - if (devPath.getBounds().isEmpty()) { - // resetting the path will remove any NaN or other wanky values - // that might upset our scan converter. - devPath.reset(); - } - - // if we called path.swap() we could avoid a deep copy of this path - fClipStack->clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); + fClipStack->clipPath(path, fMCRec->fMatrix, op, isAA); + const SkPath* rasterClipPath = &path; + const SkMatrix* matrix = &fMCRec->fMatrix; + SkPath tempPath; if (fAllowSimplifyClip) { - bool clipIsAA = getClipStack()->asPath(&devPath); - if (clipIsAA) { - edgeStyle = kSoft_ClipEdgeStyle; - } - - op = SkRegion::kReplace_Op; + isAA = getClipStack()->asPath(&tempPath); + rasterClipPath = &tempPath; + matrix = &SkMatrix::I(); + op = kReplace_Op; } - - fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); + fMCRec->fRasterClip.op(*rasterClipPath, *matrix, this->getTopLayerBounds(), (SkRegion::Op)op, + isAA); + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } -void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { +void SkCanvas::clipRegion(const SkRegion& rgn, ClipOp op) { this->checkForDeferredSave(); this->onClipRegion(rgn, op); } -void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { +void SkCanvas::onClipRegion(const SkRegion& rgn, ClipOp op) { AutoValidateClip avc(this); fDeviceCMDirty = true; - fCachedLocalClipBoundsDirty = true; // todo: signal fClipStack that we have a region, and therefore (I guess) // we have to ignore it, and use the region directly? fClipStack->clipDevRect(rgn.getBounds(), op); - fMCRec->fRasterClip.op(rgn, op); + fMCRec->fRasterClip.op(rgn, (SkRegion::Op)op); + fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); } #ifdef SK_DEBUG @@ -1724,7 +1662,7 @@ void SkCanvas::validateClip() const { switch (element->getType()) { case SkClipStack::Element::kRect_Type: element->getRect().round(&ir); - tmpClip.op(ir, element->getOp()); + tmpClip.op(ir, (SkRegion::Op)element->getOp()); break; case SkClipStack::Element::kEmpty_Type: tmpClip.setEmpty(); @@ -1732,7 +1670,8 @@ void SkCanvas::validateClip() const { default: { SkPath path; element->asPath(&path); - tmpClip.op(path, this->getTopLayerBounds(), element->getOp(), element->isAA()); + tmpClip.op(path, SkMatrix::I(), this->getTopLayerBounds(), + (SkRegion::Op)element->getOp(), element->isAA()); break; } } @@ -1760,31 +1699,74 @@ bool SkCanvas::isClipRect() const { return fMCRec->fRasterClip.isRect(); } -bool SkCanvas::quickReject(const SkRect& rect) const { - if (!rect.isFinite()) - return true; +static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) { +#if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec); + __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec); + __m128 mask = _mm_cmplt_ps(lLtT, RrBb); + return 0xF != _mm_movemask_ps(mask); +#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) + float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0]; + float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1]; + uint32x4_t mask = vcltq_f32(lLtT, RrBb); + return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask); +#else + SkRect devRectAsRect; + SkRect devClipAsRect; + devRect.store(&devRectAsRect.fLeft); + devClip.store(&devClipAsRect.fLeft); + return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect); +#endif +} +// It's important for this function to not be inlined. Otherwise the compiler will share code +// between the fast path and the slow path, resulting in two slow paths. +static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip, + const SkMatrix& matrix) { + SkRect deviceRect; + matrix.mapRect(&deviceRect, src); + return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip); +} + +bool SkCanvas::quickReject(const SkRect& src) const { +#ifdef SK_DEBUG + // Verify that fDeviceClipBounds are set properly. + SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); if (fMCRec->fRasterClip.isEmpty()) { - return true; - } - - if (fMCRec->fMatrix.hasPerspective()) { - SkRect dst; - fMCRec->fMatrix.mapRect(&dst, rect); - return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds()); + SkASSERT(fDeviceClipBounds.isEmpty()); } else { - const SkRect& clipR = this->getLocalClipBounds(); - - // for speed, do the most likely reject compares first - // TODO: should we use | instead, or compare all 4 at once? - if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { - return true; - } - if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { - return true; - } - return false; + SkASSERT(tmp == fDeviceClipBounds); } + + // Verify that fIsScaleTranslate is set properly. + SkASSERT(fIsScaleTranslate == fMCRec->fMatrix.isScaleTranslate()); +#endif + + if (!fIsScaleTranslate) { + return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix); + } + + // We inline the implementation of mapScaleTranslate() for the fast path. + float sx = fMCRec->fMatrix.getScaleX(); + float sy = fMCRec->fMatrix.getScaleY(); + float tx = fMCRec->fMatrix.getTranslateX(); + float ty = fMCRec->fMatrix.getTranslateY(); + Sk4f scale(sx, sy, sx, sy); + Sk4f trans(tx, ty, tx, ty); + + // Apply matrix. + Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans; + + // Make sure left < right, top < bottom. + Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]); + Sk4f min = Sk4f::Min(ltrb, rblt); + Sk4f max = Sk4f::Max(ltrb, rblt); + // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on + // ARM this sequence generates the fastest (a single instruction). + Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]); + + // Check if the device rect is NaN or outside the clip. + return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft)); } bool SkCanvas::quickReject(const SkPath& path) const { @@ -1841,24 +1823,14 @@ const SkRegion& SkCanvas::internal_private_getTotalClip() const { return fMCRec->fRasterClip.forceGetBW(); } -GrRenderTarget* SkCanvas::internal_private_accessTopLayerRenderTarget() { +GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() { SkBaseDevice* dev = this->getTopDevice(); - return dev ? dev->accessRenderTarget() : nullptr; + return dev ? dev->accessDrawContext() : nullptr; } GrContext* SkCanvas::getGrContext() { -#if SK_SUPPORT_GPU SkBaseDevice* device = this->getTopDevice(); - if (device) { - GrRenderTarget* renderTarget = device->accessRenderTarget(); - if (renderTarget) { - return renderTarget->getContext(); - } - } -#endif - - return nullptr; - + return device ? device->context() : nullptr; } void SkCanvas::drawDRRect(const SkRRect& outer, const SkRRect& inner, @@ -1892,6 +1864,18 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) { this->onDrawRect(r, paint); } +void SkCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) { + if (region.isEmpty()) { + return; + } + + if (region.isRect()) { + return this->drawIRect(region.getBounds(), paint); + } + + this->onDrawRegion(region, paint); +} + void SkCanvas::drawOval(const SkRect& r, const SkPaint& paint) { this->onDrawOval(r, paint); } @@ -1948,10 +1932,32 @@ void SkCanvas::drawImageNine(const SkImage* image, const SkIRect& center, const if (dst.isEmpty()) { return; } - if (!SkNinePatchIter::Valid(image->width(), image->height(), center)) { + if (SkLatticeIter::Valid(image->width(), image->height(), center)) { + this->onDrawImageNine(image, center, dst, paint); + } else { + this->drawImageRect(image, dst, paint); + } +} + +void SkCanvas::drawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint) { + RETURN_ON_NULL(image); + if (dst.isEmpty()) { + return; + } + + SkIRect bounds; + Lattice latticePlusBounds = lattice; + if (!latticePlusBounds.fBounds) { + bounds = SkIRect::MakeWH(image->width(), image->height()); + latticePlusBounds.fBounds = &bounds; + } + + if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) { + this->onDrawImageLattice(image, latticePlusBounds, dst, paint); + } else { this->drawImageRect(image, dst, paint); } - this->onDrawImageNine(image, center, dst, paint); } void SkCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, const SkPaint* paint) { @@ -1985,10 +1991,31 @@ void SkCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, con if (bitmap.drawsNothing() || dst.isEmpty()) { return; } - if (!SkNinePatchIter::Valid(bitmap.width(), bitmap.height(), center)) { + if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), center)) { + this->onDrawBitmapNine(bitmap, center, dst, paint); + } else { + this->drawBitmapRect(bitmap, dst, paint); + } +} + +void SkCanvas::drawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint) { + if (bitmap.drawsNothing() || dst.isEmpty()) { + return; + } + + SkIRect bounds; + Lattice latticePlusBounds = lattice; + if (!latticePlusBounds.fBounds) { + bounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); + latticePlusBounds.fBounds = &bounds; + } + + if (SkLatticeIter::Valid(bitmap.width(), bitmap.height(), latticePlusBounds)) { + this->onDrawBitmapLattice(bitmap, latticePlusBounds, dst, paint); + } else { this->drawBitmapRect(bitmap, dst, paint); } - this->onDrawBitmapNine(bitmap, center, dst, paint); } void SkCanvas::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], @@ -2029,6 +2056,18 @@ void SkCanvas::legacy_drawBitmapRect(const SkBitmap& bitmap, const SkRect* src, } } +void SkCanvas::temporary_internal_describeTopLayer(SkMatrix* matrix, SkIRect* clip_bounds) { + SkIRect layer_bounds = this->getTopLayerBounds(); + if (matrix) { + *matrix = this->getTotalMatrix(); + matrix->preTranslate(-layer_bounds.left(), -layer_bounds.top()); + } + if (clip_bounds) { + this->getClipDeviceBounds(clip_bounds); + clip_bounds->offset(-layer_bounds.left(), -layer_bounds.top()); + } +} + ////////////////////////////////////////////////////////////////////////////// // These are the virtual drawing methods ////////////////////////////////////////////////////////////////////////////// @@ -2087,6 +2126,14 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], LOOPER_END } +static bool needs_autodrawlooper(SkCanvas* canvas, const SkPaint& paint) { + return ((intptr_t)paint.getImageFilter() | +#ifdef SK_SUPPORT_LEGACY_DRAWFILTER + (intptr_t)canvas->getDrawFilter() | +#endif + (intptr_t)paint.getLooper() ) != 0; +} + void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRect()"); SkRect storage; @@ -2103,10 +2150,38 @@ void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { bounds = &r; } - LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) + if (needs_autodrawlooper(this, paint)) { + LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) + + while (iter.next()) { + iter.fDevice->drawRect(iter, r, looper.paint()); + } + + LOOPER_END + } else { + this->predrawNotify(bounds, &paint, false); + SkDrawIter iter(this); + while (iter.next()) { + iter.fDevice->drawRect(iter, r, paint); + } + } +} + +void SkCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { + SkRect storage; + SkRect regionRect = SkRect::Make(region.getBounds()); + const SkRect* bounds = nullptr; + if (paint.canComputeFastBounds()) { + if (this->quickReject(paint.computeFastBounds(regionRect, &storage))) { + return; + } + bounds = ®ionRect; + } + + LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds) while (iter.next()) { - iter.fDevice->drawRect(iter, r, looper.paint()); + iter.fDevice->drawRegion(iter, region, looper.paint()); } LOOPER_END @@ -2132,6 +2207,29 @@ void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { LOOPER_END } +void SkCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, + SkScalar sweepAngle, bool useCenter, + const SkPaint& paint) { + TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()"); + const SkRect* bounds = nullptr; + if (paint.canComputeFastBounds()) { + SkRect storage; + // Note we're using the entire oval as the bounds. + if (this->quickReject(paint.computeFastBounds(oval, &storage))) { + return; + } + bounds = &oval; + } + + LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) + + while (iter.next()) { + iter.fDevice->drawArc(iter, oval, startAngle, sweepAngle, useCenter, looper.paint()); + } + + LOOPER_END +} + void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRRect()"); SkRect storage; @@ -2255,17 +2353,13 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S paint = lazy.init(); } + sk_sp special; bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), *paint); if (drawAsSprite && paint->getImageFilter()) { - SkBitmap bitmap; - if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) { + special = this->getDevice()->makeSpecial(image); + if (!special) { drawAsSprite = false; - } else{ - // Until imagefilters are updated, they cannot handle any src type but N32... - if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) { - drawAsSprite = false; - } } } @@ -2273,15 +2367,12 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S while (iter.next()) { const SkPaint& pnt = looper.paint(); - if (drawAsSprite && pnt.getImageFilter()) { - SkBitmap bitmap; - if (as_IB(image)->asBitmapForImageFilters(&bitmap)) { - SkPoint pt; - iter.fMatrix->mapXY(x, y, &pt); - iter.fDevice->drawSpriteWithFilter(iter, bitmap, - SkScalarRoundToInt(pt.fX), - SkScalarRoundToInt(pt.fY), pnt); - } + if (special) { + SkPoint pt; + iter.fMatrix->mapXY(x, y, &pt); + iter.fDevice->drawSpecial(iter, special.get(), + SkScalarRoundToInt(pt.fX), + SkScalarRoundToInt(pt.fY), pnt); } else { iter.fDevice->drawImage(iter, image, x, y, pnt); } @@ -2344,11 +2435,12 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons bounds = &storage; } + sk_sp special; bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(), *paint); if (drawAsSprite && paint->getImageFilter()) { - // Until imagefilters are updated, they cannot handle any src type but N32... - if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) { + special = this->getDevice()->makeSpecial(bitmap); + if (!special) { drawAsSprite = false; } } @@ -2357,12 +2449,12 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons while (iter.next()) { const SkPaint& pnt = looper.paint(); - if (drawAsSprite && pnt.getImageFilter()) { + if (special) { SkPoint pt; iter.fMatrix->mapXY(x, y, &pt); - iter.fDevice->drawSpriteWithFilter(iter, bitmap, - SkScalarRoundToInt(pt.fX), - SkScalarRoundToInt(pt.fY), pnt); + iter.fDevice->drawSpecial(iter, special.get(), + SkScalarRoundToInt(pt.fX), + SkScalarRoundToInt(pt.fY), pnt); } else { iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); } @@ -2459,6 +2551,52 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c LOOPER_END } +void SkCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst, + const SkPaint* paint) { + if (nullptr == paint || paint->canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { + return; + } + } + + SkLazyPaint lazy; + if (nullptr == paint) { + paint = lazy.init(); + } + + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) + + while (iter.next()) { + iter.fDevice->drawImageLattice(iter, image, lattice, dst, looper.paint()); + } + + LOOPER_END +} + +void SkCanvas::onDrawBitmapLattice(const SkBitmap& bitmap, const Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + if (nullptr == paint || paint->canComputeFastBounds()) { + SkRect storage; + if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { + return; + } + } + + SkLazyPaint lazy; + if (nullptr == paint) { + paint = lazy.init(); + } + + LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, &dst) + + while (iter.next()) { + iter.fDevice->drawBitmapLattice(iter, bitmap, lattice, dst, looper.paint()); + } + + LOOPER_END +} + class SkDeviceFilteredPaint { public: SkDeviceFilteredPaint(SkBaseDevice* device, const SkPaint& paint) { @@ -2497,8 +2635,8 @@ void SkCanvas::DrawTextDecorations(const SkDraw& draw, const SkPaint& paint, // nothing to draw if (text == nullptr || byteLength == 0 || - draw.fClip->isEmpty() || - (paint.getAlpha() == 0 && paint.getXfermode() == nullptr)) { + draw.fRC->isEmpty() || + (paint.getAlpha() == 0 && paint.isSrcOver())) { return; } @@ -2608,6 +2746,21 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat LOOPER_END } +void SkCanvas::onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cullRect, const SkPaint& paint) { + if (cullRect && this->quickReject(*cullRect)) { + return; + } + + LOOPER_BEGIN(paint, SkDrawFilter::kText_Type, nullptr) + + while (iter.next()) { + iter.fDevice->drawTextRSXform(iter, text, byteLength, xform, looper.paint()); + } + + LOOPER_END +} + void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { @@ -2643,22 +2796,37 @@ void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, void SkCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawText()"); - this->onDrawText(text, byteLength, x, y, paint); + if (byteLength) { + this->onDrawText(text, byteLength, x, y, paint); + } } void SkCanvas::drawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosText()"); - this->onDrawPosText(text, byteLength, pos, paint); + if (byteLength) { + this->onDrawPosText(text, byteLength, pos, paint); + } } void SkCanvas::drawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawPosTextH()"); - this->onDrawPosTextH(text, byteLength, xpos, constY, paint); + if (byteLength) { + this->onDrawPosTextH(text, byteLength, xpos, constY, paint); + } } void SkCanvas::drawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextOnPath()"); - this->onDrawTextOnPath(text, byteLength, path, matrix, paint); + if (byteLength) { + this->onDrawTextOnPath(text, byteLength, path, matrix, paint); + } +} +void SkCanvas::drawTextRSXform(const void* text, size_t byteLength, const SkRSXform xform[], + const SkRect* cullRect, const SkPaint& paint) { + TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawTextRSXform()"); + if (byteLength) { + this->onDrawTextRSXform(text, byteLength, xform, cullRect, paint); + } } void SkCanvas::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { @@ -2691,6 +2859,11 @@ void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], return; } + this->onDrawPatch(cubics, colors, texCoords, xmode, paint); +} + +void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { // Since a patch is always within the convex hull of the control points, we discard it when its // bounding rectangle is completely outside the current clip. SkRect bounds; @@ -2699,12 +2872,6 @@ void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4], return; } - this->onDrawPatch(cubics, colors, texCoords, xmode, paint); -} - -void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], - const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) { - LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, nullptr) while (iter.next()) { @@ -2733,13 +2900,8 @@ void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) { } void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) { - SkRect bounds = dr->getBounds(); - if (matrix) { - matrix->mapRect(&bounds); - } - if (this->quickReject(bounds)) { - return; - } + // drawable bounds are no longer reliable (e.g. android displaylist) + // so don't use them for quick-reject dr->draw(this, matrix); } @@ -2778,26 +2940,21 @@ void SkCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* va // methods, rather than actually drawing themselves. ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, - SkXfermode::Mode mode) { +void SkCanvas::drawARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b, SkBlendMode mode) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawARGB()"); SkPaint paint; paint.setARGB(a, r, g, b); - if (SkXfermode::kSrcOver_Mode != mode) { - paint.setXfermodeMode(mode); - } + paint.setBlendMode(mode); this->drawPaint(paint); } -void SkCanvas::drawColor(SkColor c, SkXfermode::Mode mode) { +void SkCanvas::drawColor(SkColor c, SkBlendMode mode) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawColor()"); SkPaint paint; paint.setColor(c); - if (SkXfermode::kSrcOver_Mode != mode) { - paint.setXfermodeMode(mode); - } + paint.setBlendMode(mode); this->drawPaint(paint); } @@ -2855,12 +3012,6 @@ void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawRoundRect()"); if (rx > 0 && ry > 0) { - if (paint.canComputeFastBounds()) { - SkRect storage; - if (this->quickReject(paint.computeFastBounds(r, &storage))) { - return; - } - } SkRRect rrect; rrect.setRectXY(r, rx, ry); this->drawRRect(rrect, paint); @@ -2873,19 +3024,10 @@ void SkCanvas::drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()"); - if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) { - this->drawOval(oval, paint); - } else { - SkPath path; - if (useCenter) { - path.moveTo(oval.centerX(), oval.centerY()); - } - path.arcTo(oval, startAngle, sweepAngle, !useCenter); - if (useCenter) { - path.close(); - } - this->drawPath(path, paint); + if (oval.isEmpty() || !sweepAngle) { + return; } + this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint); } void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength, @@ -2939,28 +3081,212 @@ void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, } } - SkBaseDevice* device = this->getTopDevice(); - if (device) { - // Canvas has to first give the device the opportunity to render - // the picture itself. - if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) { - return; // the device has rendered the entire picture - } - } - SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); picture->playback(this); } +#ifdef SK_EXPERIMENTAL_SHADOWING +void SkCanvas::drawShadowedPicture(const SkPicture* picture, + const SkMatrix* matrix, + const SkPaint* paint, + const SkShadowParams& params) { + RETURN_ON_NULL(picture); + + TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawShadowedPicture()"); + + this->onDrawShadowedPicture(picture, matrix, paint, params); +} + +void SkCanvas::onDrawShadowedPicture(const SkPicture* picture, + const SkMatrix* matrix, + const SkPaint* paint, + const SkShadowParams& params) { + if (!paint || paint->canComputeFastBounds()) { + SkRect bounds = picture->cullRect(); + if (paint) { + paint->computeFastBounds(bounds, &bounds); + } + if (matrix) { + matrix->mapRect(&bounds); + } + if (this->quickReject(bounds)) { + return; + } + } + + SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect()); + + sk_sp povDepthMap; + sk_sp diffuseMap; + + // povDepthMap + { + SkLights::Builder builder; + builder.add(SkLights::Light::MakeDirectional(SkColor3f::Make(1.0f, 1.0f, 1.0f), + SkVector3::Make(0.0f, 0.0f, 1.0f))); + sk_sp povLight = builder.finish(); + + SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(), + picture->cullRect().height(), + kBGRA_8888_SkColorType, + kOpaque_SkAlphaType); + + // Create a new surface (that matches the backend of canvas) + // to create the povDepthMap + sk_sp surf(this->makeSurface(info)); + + // Wrap another SPFCanvas around the surface + sk_sp depthMapCanvas = + sk_make_sp(surf->getCanvas()); + + // set the depth map canvas to have the light as the user's POV + depthMapCanvas->setLights(std::move(povLight)); + + depthMapCanvas->drawPicture(picture); + povDepthMap = surf->makeImageSnapshot(); + } + + // diffuseMap + { + SkImageInfo info = SkImageInfo::Make(picture->cullRect().width(), + picture->cullRect().height(), + kBGRA_8888_SkColorType, + kOpaque_SkAlphaType); + + sk_sp surf(this->makeSurface(info)); + surf->getCanvas()->drawPicture(picture); + + diffuseMap = surf->makeImageSnapshot(); + } + + sk_sp povDepthShader = povDepthMap->makeShader(SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + sk_sp diffuseShader = diffuseMap->makeShader(SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + + // TODO: pass the depth to the shader in vertices, or uniforms + // so we don't have to render depth and color separately + for (int i = 0; i < fLights->numLights(); ++i) { + // skip over ambient lights; they don't cast shadows + // lights that have shadow maps do not need updating (because lights are immutable) + sk_sp depthMap; + SkISize shMapSize; + + if (fLights->light(i).getShadowMap() != nullptr) { + continue; + } + + if (fLights->light(i).isRadial()) { + shMapSize.fHeight = 1; + shMapSize.fWidth = (int) picture->cullRect().width(); + + SkImageInfo info = SkImageInfo::Make(diffuseMap->width(), 1, + kBGRA_8888_SkColorType, + kOpaque_SkAlphaType); + + // Create new surface (that matches the backend of canvas) + // for each shadow map + sk_sp surf(this->makeSurface(info)); + + // Wrap another SPFCanvas around the surface + SkCanvas* depthMapCanvas = surf->getCanvas(); + + SkLights::Builder builder; + builder.add(fLights->light(i)); + sk_sp curLight = builder.finish(); + + sk_sp shadowMapShader; + shadowMapShader = SkRadialShadowMapShader::Make( + povDepthShader, curLight, + (int) picture->cullRect().width(), + (int) picture->cullRect().height()); + + SkPaint shadowMapPaint; + shadowMapPaint.setShader(std::move(shadowMapShader)); + + depthMapCanvas->setLights(curLight); + + depthMapCanvas->drawRect(SkRect::MakeIWH(diffuseMap->width(), + diffuseMap->height()), + shadowMapPaint); + + depthMap = surf->makeImageSnapshot(); + + } else { + // TODO: compute the correct size of the depth map from the light properties + // TODO: maybe add a kDepth_8_SkColorType + // TODO: find actual max depth of picture + shMapSize = SkShadowPaintFilterCanvas::ComputeDepthMapSize( + fLights->light(i), 255, + (int) picture->cullRect().width(), + (int) picture->cullRect().height()); + + SkImageInfo info = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight, + kBGRA_8888_SkColorType, + kOpaque_SkAlphaType); + + // Create a new surface (that matches the backend of canvas) + // for each shadow map + sk_sp surf(this->makeSurface(info)); + + // Wrap another SPFCanvas around the surface + sk_sp depthMapCanvas = + sk_make_sp(surf->getCanvas()); + depthMapCanvas->setShadowParams(params); + + // set the depth map canvas to have the light we're drawing. + SkLights::Builder builder; + builder.add(fLights->light(i)); + sk_sp curLight = builder.finish(); + depthMapCanvas->setLights(std::move(curLight)); + + depthMapCanvas->drawPicture(picture); + depthMap = surf->makeImageSnapshot(); + } + + if (params.fType == SkShadowParams::kNoBlur_ShadowType) { + fLights->light(i).setShadowMap(std::move(depthMap)); + } else if (params.fType == SkShadowParams::kVariance_ShadowType) { + // we blur the variance map + SkPaint blurPaint; + blurPaint.setImageFilter(SkImageFilter::MakeBlur(params.fShadowRadius, + params.fShadowRadius, nullptr)); + + SkImageInfo blurInfo = SkImageInfo::Make(shMapSize.fWidth, shMapSize.fHeight, + kBGRA_8888_SkColorType, + kOpaque_SkAlphaType); + + sk_sp blurSurf(this->makeSurface(blurInfo)); + + blurSurf->getCanvas()->drawImage(std::move(depthMap), 0, 0, &blurPaint); + + fLights->light(i).setShadowMap(blurSurf->makeImageSnapshot()); + } + } + + SkPaint shadowPaint; + sk_sp shadowShader = SkShadowShader::Make(std::move(povDepthShader), + std::move(diffuseShader), + fLights, + diffuseMap->width(), + diffuseMap->height(), + params); + + shadowPaint.setShader(shadowShader); + + this->drawRect(SkRect::MakeIWH(diffuseMap->width(), diffuseMap->height()), shadowPaint); +} +#endif + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) { +SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) { static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small"); SkASSERT(canvas); - fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips); + fImpl = new (fStorage) SkDrawIter(canvas); fDone = !fImpl->next(); } @@ -2988,7 +3314,7 @@ const SkPaint& SkCanvas::LayerIter::paint() const { return *paint; } -const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } +const SkRasterClip& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } int SkCanvas::LayerIter::x() const { return fImpl->getX(); } int SkCanvas::LayerIter::y() const { return fImpl->getY(); } @@ -3062,3 +3388,19 @@ SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p return this->makeSurface(info, props).release(); } #endif + +///////////////////////////////// + +const SkCanvas::ClipOp SkCanvas::kDifference_Op; +const SkCanvas::ClipOp SkCanvas::kIntersect_Op; +const SkCanvas::ClipOp SkCanvas::kUnion_Op; +const SkCanvas::ClipOp SkCanvas::kXOR_Op; +const SkCanvas::ClipOp SkCanvas::kReverseDifference_Op; +const SkCanvas::ClipOp SkCanvas::kReplace_Op; + +static_assert((int)SkRegion::kDifference_Op == (int)kDifference_SkClipOp, ""); +static_assert((int)SkRegion::kIntersect_Op == (int)kIntersect_SkClipOp, ""); +static_assert((int)SkRegion::kUnion_Op == (int)kUnion_SkClipOp, ""); +static_assert((int)SkRegion::kXOR_Op == (int)kXOR_SkClipOp, ""); +static_assert((int)SkRegion::kReverseDifference_Op == (int)kReverseDifference_SkClipOp, ""); +static_assert((int)SkRegion::kReplace_Op == (int)kReplace_SkClipOp, ""); diff --git a/gfx/skia/skia/src/core/SkChecksum.cpp b/gfx/skia/skia/src/core/SkChecksum.cpp deleted file mode 100644 index 4457eb4f9976..000000000000 --- a/gfx/skia/skia/src/core/SkChecksum.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkChecksum.h" - -uint32_t SkChecksum::Murmur3(const void* data, size_t bytes, uint32_t seed) { - // Use may_alias to remind the compiler we're intentionally violating strict aliasing, - // and so not to apply strict-aliasing-based optimizations. - typedef uint32_t SK_ATTRIBUTE(may_alias) aliased_uint32_t; - typedef uint8_t SK_ATTRIBUTE(may_alias) aliased_uint8_t; - - // Handle 4 bytes at a time while possible. - const aliased_uint32_t* safe_data = (const aliased_uint32_t*)data; - const size_t words = bytes/4; - uint32_t hash = seed; - for (size_t i = 0; i < words; i++) { - uint32_t k = safe_data[i]; - k *= 0xcc9e2d51; - k = (k << 15) | (k >> 17); - k *= 0x1b873593; - - hash ^= k; - hash = (hash << 13) | (hash >> 19); - hash *= 5; - hash += 0xe6546b64; - } - - // Handle last 0-3 bytes. - const aliased_uint8_t* safe_tail = (const uint8_t*)(safe_data + words); - uint32_t k = 0; - switch (bytes & 3) { - case 3: k ^= safe_tail[2] << 16; - case 2: k ^= safe_tail[1] << 8; - case 1: k ^= safe_tail[0] << 0; - k *= 0xcc9e2d51; - k = (k << 15) | (k >> 17); - k *= 0x1b873593; - hash ^= k; - } - - hash ^= bytes; - return SkChecksum::Mix(hash); -} diff --git a/gfx/skia/skia/src/core/SkChunkAlloc.cpp b/gfx/skia/skia/src/core/SkChunkAlloc.cpp index 8c5b8fb6a45d..90650a7ad8f2 100644 --- a/gfx/skia/skia/src/core/SkChunkAlloc.cpp +++ b/gfx/skia/skia/src/core/SkChunkAlloc.cpp @@ -23,7 +23,7 @@ struct SkChunkAlloc::Block { char* fFreePtr; // data[] follows - size_t blockSize() { + size_t blockSize() const { char* start = this->startOfData(); size_t bytes = fFreePtr - start; return fFreeSize + bytes; @@ -35,8 +35,8 @@ struct SkChunkAlloc::Block { fFreePtr = this->startOfData(); } - char* startOfData() { - return reinterpret_cast(this + 1); + char* startOfData() const { + return reinterpret_cast(SkAlign8(reinterpret_cast(this + 1))); } static void FreeChain(Block* block) { @@ -45,11 +45,11 @@ struct SkChunkAlloc::Block { sk_free(block); block = next; } - }; + } bool contains(const void* addr) const { const char* ptr = reinterpret_cast(addr); - return ptr >= (const char*)(this + 1) && ptr < fFreePtr; + return ptr >= this->startOfData() && ptr < fFreePtr; } }; @@ -121,7 +121,7 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { size = fChunkSize; } - Block* block = (Block*)sk_malloc_flags(sizeof(Block) + size, + Block* block = (Block*)sk_malloc_flags(SkAlign8(sizeof(Block)) + size, ftype == kThrow_AllocFailType ? SK_MALLOC_THROW : 0); if (block) { @@ -137,7 +137,7 @@ SkChunkAlloc::Block* SkChunkAlloc::newBlock(size_t bytes, AllocFailType ftype) { } SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailType ftype) { - SkASSERT(SkIsAlign4(bytes)); + SkASSERT(SkIsAlign8(bytes)); if (!fBlock || bytes > fBlock->fFreeSize) { Block* block = this->newBlock(bytes, ftype); @@ -160,7 +160,7 @@ SkChunkAlloc::Block* SkChunkAlloc::addBlockIfNecessary(size_t bytes, AllocFailTy void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { SkDEBUGCODE(this->validate();) - bytes = SkAlign4(bytes); + bytes = SkAlign8(bytes); Block* block = this->addBlockIfNecessary(bytes, ftype); if (!block) { @@ -173,6 +173,7 @@ void* SkChunkAlloc::alloc(size_t bytes, AllocFailType ftype) { block->fFreeSize -= bytes; block->fFreePtr = ptr + bytes; SkDEBUGCODE(this->validate();) + SkASSERT(SkIsAlign8((size_t)ptr)); return ptr; } diff --git a/gfx/skia/skia/src/core/SkClipStack.cpp b/gfx/skia/skia/src/core/SkClipStack.cpp index 4e53d8b850d5..f155b49c4f59 100644 --- a/gfx/skia/skia/src/core/SkClipStack.cpp +++ b/gfx/skia/skia/src/core/SkClipStack.cpp @@ -83,7 +83,7 @@ void SkClipStack::Element::replay(SkCanvasClipVisitor* visitor) const { visitor->clipRect(this->getRect(), this->getOp(), this->isAA()); break; case kEmpty_Type: - visitor->clipRect(kEmptyRect, SkRegion::kIntersect_Op, false); + visitor->clipRect(kEmptyRect, SkCanvas::kIntersect_Op, false); break; } } @@ -111,7 +111,7 @@ void SkClipStack::Element::invertShapeFillType() { } } -void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkRegion::Op op, +void SkClipStack::Element::initPath(int saveCount, const SkPath& path, SkCanvas::ClipOp op, bool doAA) { if (!path.isInverseFillType()) { SkRect r; @@ -176,16 +176,16 @@ void SkClipStack::Element::checkEmpty() const { SkASSERT(!fPath.isValid()); } -bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const { +bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkCanvas::ClipOp op) const { if (kEmpty_Type == fType && - (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) { + (SkCanvas::kDifference_Op == op || SkCanvas::kIntersect_Op == op)) { return true; } // Only clips within the same save/restore frame (as captured by // the save count) can be merged return fSaveCount == saveCount && - SkRegion::kIntersect_Op == op && - (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp); + SkCanvas::kIntersect_Op == op && + (SkCanvas::kIntersect_Op == fOp || SkCanvas::kReplace_Op == fOp); } bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const { @@ -237,10 +237,10 @@ void SkClipStack::Element::combineBoundsDiff(FillCombo combination, const SkRect // is erased, so the only pixels that can remain set // occur w/in the intersection of the two finite bounds if (!fFiniteBound.intersect(prevFinite)) { - this->setEmpty(); - } else { - fFiniteBoundType = kNormal_BoundsType; + fFiniteBound.setEmpty(); + fGenID = kEmptyGenID; } + fFiniteBoundType = kNormal_BoundsType; break; case kPrev_Cur_FillCombo: // The most conservative result bound is that of the @@ -399,9 +399,9 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { fFiniteBound = this->getRect(); fFiniteBoundType = kNormal_BoundsType; - if (SkRegion::kReplace_Op == fOp || - (SkRegion::kIntersect_Op == fOp && nullptr == prior) || - (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && + if (SkCanvas::kReplace_Op == fOp || + (SkCanvas::kIntersect_Op == fOp && nullptr == prior) || + (SkCanvas::kIntersect_Op == fOp && prior->fIsIntersectionOfRects && prior->rectRectIntersectAllowed(this->getRect(), fDoAA))) { fIsIntersectionOfRects = true; } @@ -460,28 +460,28 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { // Now integrate with clip with the prior clips switch (fOp) { - case SkRegion::kDifference_Op: + case SkCanvas::kDifference_Op: this->combineBoundsDiff(combination, prevFinite); break; - case SkRegion::kXOR_Op: + case SkCanvas::kXOR_Op: this->combineBoundsXOR(combination, prevFinite); break; - case SkRegion::kUnion_Op: + case SkCanvas::kUnion_Op: this->combineBoundsUnion(combination, prevFinite); break; - case SkRegion::kIntersect_Op: + case SkCanvas::kIntersect_Op: this->combineBoundsIntersection(combination, prevFinite); break; - case SkRegion::kReverseDifference_Op: + case SkCanvas::kReverseDifference_Op: this->combineBoundsRevDiff(combination, prevFinite); break; - case SkRegion::kReplace_Op: + case SkCanvas::kReplace_Op: // Replace just ignores everything prior // The current clip's bound information is already filled in // so nothing to do break; default: - SkDebugf("SkRegion::Op error\n"); + SkDebugf("SkCanvas::ClipOp error\n"); SkASSERT(0); break; } @@ -503,24 +503,6 @@ SkClipStack::SkClipStack(const SkClipStack& b) *this = b; } -SkClipStack::SkClipStack(const SkRect& r) - : fDeque(sizeof(Element), kDefaultElementAllocCnt) - , fSaveCount(0) { - if (!r.isEmpty()) { - this->clipDevRect(r, SkRegion::kReplace_Op, false); - } -} - -SkClipStack::SkClipStack(const SkIRect& r) - : fDeque(sizeof(Element), kDefaultElementAllocCnt) - , fSaveCount(0) { - if (!r.isEmpty()) { - SkRect temp; - temp.set(r); - this->clipDevRect(temp, SkRegion::kReplace_Op, false); - } -} - SkClipStack::~SkClipStack() { reset(); } @@ -621,12 +603,12 @@ void SkClipStack::getBounds(SkRect* canvFiniteBound, } } -bool SkClipStack::quickContains(const SkRect& rect) const { +bool SkClipStack::internalQuickContains(const SkRect& rect) const { Iter iter(*this, Iter::kTop_IterStart); const Element* element = iter.prev(); while (element != nullptr) { - if (SkRegion::kIntersect_Op != element->getOp() && SkRegion::kReplace_Op != element->getOp()) + if (SkCanvas::kIntersect_Op != element->getOp() && SkCanvas::kReplace_Op != element->getOp()) return false; if (element->isInverseFilled()) { // Part of 'rect' could be trimmed off by the inverse-filled clip element @@ -638,7 +620,32 @@ bool SkClipStack::quickContains(const SkRect& rect) const { return false; } } - if (SkRegion::kReplace_Op == element->getOp()) { + if (SkCanvas::kReplace_Op == element->getOp()) { + break; + } + element = iter.prev(); + } + return true; +} + +bool SkClipStack::internalQuickContains(const SkRRect& rrect) const { + + Iter iter(*this, Iter::kTop_IterStart); + const Element* element = iter.prev(); + while (element != nullptr) { + if (SkCanvas::kIntersect_Op != element->getOp() && SkCanvas::kReplace_Op != element->getOp()) + return false; + if (element->isInverseFilled()) { + // Part of 'rrect' could be trimmed off by the inverse-filled clip element + if (SkRect::Intersects(element->getBounds(), rrect.getBounds())) { + return false; + } + } else { + if (!element->contains(rrect)) { + return false; + } + } + if (SkCanvas::kReplace_Op == element->getOp()) { break; } element = iter.prev(); @@ -659,8 +666,8 @@ bool SkClipStack::asPath(SkPath *path) const { element->asPath(&operand); } - SkRegion::Op elementOp = element->getOp(); - if (elementOp == SkRegion::kReplace_Op) { + SkCanvas::ClipOp elementOp = element->getOp(); + if (elementOp == SkCanvas::kReplace_Op) { *path = operand; } else { Op(*path, operand, (SkPathOp)elementOp, path); @@ -711,7 +718,7 @@ void SkClipStack::pushElement(const Element& element) { } break; } - } else if (SkRegion::kReplace_Op == element.getOp()) { + } else if (SkCanvas::kReplace_Op == element.getOp()) { this->restoreTo(fSaveCount - 1); prior = (Element*) fDeque.back(); } @@ -720,25 +727,48 @@ void SkClipStack::pushElement(const Element& element) { newElement->updateBoundAndGenID(prior); } -void SkClipStack::clipDevRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { - Element element(fSaveCount, rrect, op, doAA); - this->pushElement(element); +void SkClipStack::clipRRect(const SkRRect& rrect, const SkMatrix& matrix, SkCanvas::ClipOp op, + bool doAA) { + SkRRect transformedRRect; + if (rrect.transform(matrix, &transformedRRect)) { + Element element(fSaveCount, transformedRRect, op, doAA); + this->pushElement(element); + return; + } + SkPath path; + path.addRRect(rrect); + path.setIsVolatile(true); + this->clipPath(path, matrix, op, doAA); } -void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { - Element element(fSaveCount, rect, op, doAA); - this->pushElement(element); +void SkClipStack::clipRect(const SkRect& rect, const SkMatrix& matrix, SkCanvas::ClipOp op, + bool doAA) { + if (matrix.rectStaysRect()) { + SkRect devRect; + matrix.mapRect(&devRect, rect); + Element element(fSaveCount, devRect, op, doAA); + this->pushElement(element); + return; + } + SkPath path; + path.addRect(rect); + path.setIsVolatile(true); + this->clipPath(path, matrix, op, doAA); } -void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { - Element element(fSaveCount, path, op, doAA); +void SkClipStack::clipPath(const SkPath& path, const SkMatrix& matrix, SkCanvas::ClipOp op, + bool doAA) { + SkPath devPath; + path.transform(matrix, &devPath); + + Element element(fSaveCount, devPath, op, doAA); this->pushElement(element); } void SkClipStack::clipEmpty() { Element* element = (Element*) fDeque.back(); - if (element && element->canBeIntersectedInPlace(fSaveCount, SkRegion::kIntersect_Op)) { + if (element && element->canBeIntersectedInPlace(fSaveCount, SkCanvas::kIntersect_Op)) { element->setEmpty(); } new (fDeque.push_back()) Element(fSaveCount); @@ -746,10 +776,6 @@ void SkClipStack::clipEmpty() { ((Element*)fDeque.back())->fGenID = kEmptyGenID; } -bool SkClipStack::isWideOpen() const { - return this->getTopmostGenID() == kWideOpenGenID; -} - /////////////////////////////////////////////////////////////////////////////// SkClipStack::Iter::Iter() : fStack(nullptr) { @@ -768,7 +794,7 @@ const SkClipStack::Element* SkClipStack::Iter::prev() { return (const SkClipStack::Element*)fIter.prev(); } -const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkRegion::Op op) { +const SkClipStack::Element* SkClipStack::Iter::skipToTopmost(SkCanvas::ClipOp op) { if (nullptr == fStack) { return nullptr; @@ -841,6 +867,50 @@ void SkClipStack::getConservativeBounds(int offsetX, } } +bool SkClipStack::isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const { + // We limit to 5 elements. This means the back element will be bounds checked at most 4 times if + // it is an rrect. + int cnt = fDeque.count(); + if (!cnt || cnt > 5) { + return false; + } + const Element* back = static_cast(fDeque.back()); + if (back->getType() != SkClipStack::Element::kRect_Type && + back->getType() != SkClipStack::Element::kRRect_Type) { + return false; + } + if (back->getOp() == SkCanvas::kReplace_Op) { + *rrect = back->asRRect(); + *aa = back->isAA(); + return true; + } + + if (back->getOp() == SkCanvas::kIntersect_Op) { + SkRect backBounds; + if (!backBounds.intersect(bounds, back->asRRect().rect())) { + return false; + } + if (cnt > 1) { + SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); + SkAssertResult(static_cast(iter.prev()) == back); + while (const Element* prior = (const Element*)iter.prev()) { + if ((prior->getOp() != SkCanvas::kIntersect_Op && + prior->getOp() != SkCanvas::kReplace_Op) || + !prior->contains(backBounds)) { + return false; + } + if (prior->getOp() == SkCanvas::kReplace_Op) { + break; + } + } + } + *rrect = back->asRRect(); + *aa = back->isAA(); + return true; + } + return false; +} + int32_t SkClipStack::GetNextGenID() { // TODO: handle overflow. return sk_atomic_inc(&gGenID); @@ -859,7 +929,7 @@ int32_t SkClipStack::getTopmostGenID() const { return back->getGenID(); } -#ifdef SK_DEVELOPER +#ifdef SK_DEBUG void SkClipStack::Element::dump() const { static const char* kTypeStrings[] = { "empty", @@ -881,12 +951,12 @@ void SkClipStack::Element::dump() const { "reverse-difference", "replace", }; - static_assert(0 == SkRegion::kDifference_Op, "op_str"); - static_assert(1 == SkRegion::kIntersect_Op, "op_str"); - static_assert(2 == SkRegion::kUnion_Op, "op_str"); - static_assert(3 == SkRegion::kXOR_Op, "op_str"); - static_assert(4 == SkRegion::kReverseDifference_Op, "op_str"); - static_assert(5 == SkRegion::kReplace_Op, "op_str"); + static_assert(0 == SkCanvas::kDifference_Op, "op_str"); + static_assert(1 == SkCanvas::kIntersect_Op, "op_str"); + static_assert(2 == SkCanvas::kUnion_Op, "op_str"); + static_assert(3 == SkCanvas::kXOR_Op, "op_str"); + static_assert(4 == SkCanvas::kReverseDifference_Op, "op_str"); + static_assert(5 == SkCanvas::kReplace_Op, "op_str"); static_assert(SK_ARRAY_COUNT(kOpStrings) == SkRegion::kOpCnt, "op_str"); SkDebugf("Type: %s, Op: %s, AA: %s, Save Count: %d\n", kTypeStrings[fType], diff --git a/gfx/skia/skia/src/core/SkColor.cpp b/gfx/skia/skia/src/core/SkColor.cpp index ab6330011978..6dacc063e0be 100644 --- a/gfx/skia/skia/src/core/SkColor.cpp +++ b/gfx/skia/skia/src/core/SkColor.cpp @@ -106,10 +106,7 @@ SkColor SkHSVToColor(U8CPU a, const SkScalar hsv[3]) { #include "SkHalf.h" SkPM4f SkPM4f::FromPMColor(SkPMColor c) { - Sk4f value = to_4f_rgba(c); - SkPM4f c4; - (value * Sk4f(1.0f / 255)).store(&c4); - return c4; + return From4f(swizzle_rb_if_bgra(Sk4f_fromL32(c))); } SkColor4f SkPM4f::unpremul() const { @@ -118,7 +115,7 @@ SkColor4f SkPM4f::unpremul() const { return { 0, 0, 0, 0 }; } else { float invAlpha = 1 / alpha; - return { alpha, fVec[R] * invAlpha, fVec[G] * invAlpha, fVec[B] * invAlpha }; + return { fVec[R] * invAlpha, fVec[G] * invAlpha, fVec[B] * invAlpha, alpha }; } } @@ -152,26 +149,35 @@ void SkPM4f::assertIsUnit() const { /////////////////////////////////////////////////////////////////////////////////////////////////// -SkColor4f SkColor4f::FromColor(SkColor c) { - Sk4f value = SkNx_shuffle<3,2,1,0>(SkNx_cast(Sk4b::Load(&c))); - SkColor4f c4; - (value * Sk4f(1.0f / 255)).store(&c4); - return c4; +SkColor4f SkColor4f::FromColor(SkColor bgra) { + SkColor4f rgba; + swizzle_rb(Sk4f_fromS32(bgra)).store(rgba.vec()); + return rgba; } -SkColor4f SkColor4f::Pin(float a, float r, float g, float b) { +SkColor4f SkColor4f::FromColor3f(SkColor3f color3f, float a) { + SkColor4f rgba; + rgba.fR = color3f.fX; + rgba.fG = color3f.fY; + rgba.fB = color3f.fZ; + rgba.fA = a; + return rgba; +} + +SkColor SkColor4f::toSkColor() const { + return Sk4f_toS32(swizzle_rb(Sk4f::Load(this->vec()))); +} + +SkColor4f SkColor4f::Pin(float r, float g, float b, float a) { SkColor4f c4; - Sk4f::Min(Sk4f::Max(Sk4f(a, r, g, b), Sk4f(0)), Sk4f(1)).store(c4.vec()); + Sk4f::Min(Sk4f::Max(Sk4f(r, g, b, a), Sk4f(0)), Sk4f(1)).store(c4.vec()); return c4; } SkPM4f SkColor4f::premul() const { auto src = Sk4f::Load(this->pin().vec()); - float srcAlpha = src[0]; // need the pinned version of our alpha - src = src * Sk4f(1, srcAlpha, srcAlpha, srcAlpha); + float srcAlpha = src[3]; // need the pinned version of our alpha + src = src * Sk4f(srcAlpha, srcAlpha, srcAlpha, 1); - // ARGB -> RGBA - Sk4f dst = SkNx_shuffle<1,2,3,0>(src); - - return SkPM4f::From4f(dst); + return SkPM4f::From4f(src); } diff --git a/gfx/skia/skia/src/core/SkColorFilter.cpp b/gfx/skia/skia/src/core/SkColorFilter.cpp index e3d89579471a..31c0ddb06b27 100644 --- a/gfx/skia/skia/src/core/SkColorFilter.cpp +++ b/gfx/skia/skia/src/core/SkColorFilter.cpp @@ -31,19 +31,34 @@ bool SkColorFilter::asComponentTable(SkBitmap*) const { return false; } -void SkColorFilter::filterSpan4f(const SkPM4f[], int count, SkPM4f span[]) const { +#if SK_SUPPORT_GPU +sk_sp SkColorFilter::asFragmentProcessor(GrContext*) const { + return nullptr; +} +#endif + +bool SkColorFilter::appendStages(SkRasterPipeline* pipeline) const { + return this->onAppendStages(pipeline); +} + +bool SkColorFilter::onAppendStages(SkRasterPipeline*) const { + return false; +} + +void SkColorFilter::filterSpan4f(const SkPM4f src[], int count, SkPM4f result[]) const { const int N = 128; SkPMColor tmp[N]; while (count > 0) { int n = SkTMin(count, N); for (int i = 0; i < n; ++i) { - SkNx_cast(Sk4f::Load(span[i].fVec) * Sk4f(255) + Sk4f(0.5f)).store(&tmp[i]); + tmp[i] = src[i].toPMColor(); } this->filterSpan(tmp, n, tmp); for (int i = 0; i < n; ++i) { - span[i] = SkPM4f::FromPMColor(tmp[i]); + result[i] = SkPM4f::FromPMColor(tmp[i]); } - span += n; + src += n; + result += n; count -= n; } } @@ -99,13 +114,13 @@ public: #endif #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext* context) const override { - SkAutoTUnref innerFP(fInner->asFragmentProcessor(context)); - SkAutoTUnref outerFP(fOuter->asFragmentProcessor(context)); + sk_sp asFragmentProcessor(GrContext* context) const override { + sk_sp innerFP(fInner->asFragmentProcessor(context)); + sk_sp outerFP(fOuter->asFragmentProcessor(context)); if (!innerFP || !outerFP) { return nullptr; } - const GrFragmentProcessor* series[] = { innerFP, outerFP }; + sk_sp series[] = { std::move(innerFP), std::move(outerFP) }; return GrFragmentProcessor::RunInSeries(series, 2); } #endif diff --git a/gfx/skia/skia/src/core/SkColorFilterShader.cpp b/gfx/skia/skia/src/core/SkColorFilterShader.cpp index 500ead4f7431..8bf82b8b182b 100644 --- a/gfx/skia/skia/src/core/SkColorFilterShader.cpp +++ b/gfx/skia/skia/src/core/SkColorFilterShader.cpp @@ -97,25 +97,19 @@ void SkColorFilterShader::FilterShaderContext::shadeSpan4f(int x, int y, SkPM4f #if SK_SUPPORT_GPU ///////////////////////////////////////////////////////////////////// -const GrFragmentProcessor* SkColorFilterShader::asFragmentProcessor( - GrContext* context, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality fq) const { +sk_sp SkColorFilterShader::asFragmentProcessor(const AsFPArgs& args) const { - SkAutoTUnref fp1(fShader->asFragmentProcessor(context, viewM, - localMatrix, fq)); - if (!fp1.get()) { + sk_sp fp1(fShader->asFragmentProcessor(args)); + if (!fp1) { return nullptr; } - SkAutoTUnref fp2(fFilter->asFragmentProcessor(context)); - if (!fp2.get()) { - return fp1.release(); + sk_sp fp2(fFilter->asFragmentProcessor(args.fContext)); + if (!fp2) { + return fp1; } - const GrFragmentProcessor* fpSeries[] = { fp1.get(), fp2.get() }; - + sk_sp fpSeries[] = { std::move(fp1), std::move(fp2) }; return GrFragmentProcessor::RunInSeries(fpSeries, 2); } #endif diff --git a/gfx/skia/skia/src/core/SkColorFilterShader.h b/gfx/skia/skia/src/core/SkColorFilterShader.h index e42d06c66790..035acd839773 100644 --- a/gfx/skia/skia/src/core/SkColorFilterShader.h +++ b/gfx/skia/skia/src/core/SkColorFilterShader.h @@ -16,10 +16,7 @@ public: SkColorFilterShader(sk_sp shader, sk_sp filter); #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality) const override; + sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif class FilterShaderContext : public SkShader::Context { diff --git a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp index c158a7948fec..29a3f107b8f0 100644 --- a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp +++ b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.cpp @@ -8,11 +8,12 @@ #include "SkColorMatrixFilterRowMajor255.h" #include "SkColorPriv.h" #include "SkNx.h" -#include "SkReadBuffer.h" -#include "SkWriteBuffer.h" -#include "SkUnPreMultiply.h" -#include "SkString.h" #include "SkPM4fPriv.h" +#include "SkReadBuffer.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkUnPreMultiply.h" +#include "SkWriteBuffer.h" static void transpose(float dst[20], const float src[20]) { const float* srcR = src + 0; @@ -125,7 +126,7 @@ struct SkPMColorAdaptor { return round(swizzle_rb_if_bgra(c4)); } static Sk4f To4f(SkPMColor c) { - return to_4f(c) * Sk4f(1.0f/255); + return Sk4f_fromL32(c); } }; void SkColorMatrixFilterRowMajor255::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { @@ -247,8 +248,8 @@ SkColorMatrixFilterRowMajor255::makeComposed(sk_sp innerFilter) c class ColorMatrixEffect : public GrFragmentProcessor { public: - static const GrFragmentProcessor* Create(const SkScalar matrix[20]) { - return new ColorMatrixEffect(matrix); + static sk_sp Make(const SkScalar matrix[20]) { + return sk_sp(new ColorMatrixEffect(matrix)); } const char* name() const override { return "Color Matrix"; } @@ -387,16 +388,16 @@ private: GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect); -const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d) { +sk_sp ColorMatrixEffect::TestCreate(GrProcessorTestData* d) { SkScalar colorMatrix[20]; for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix); ++i) { colorMatrix[i] = d->fRandom->nextSScalar1(); } - return ColorMatrixEffect::Create(colorMatrix); + return ColorMatrixEffect::Make(colorMatrix); } -const GrFragmentProcessor* SkColorMatrixFilterRowMajor255::asFragmentProcessor(GrContext*) const { - return ColorMatrixEffect::Create(fMatrix); +sk_sp SkColorMatrixFilterRowMajor255::asFragmentProcessor(GrContext*) const { + return ColorMatrixEffect::Make(fMatrix); } #endif diff --git a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h index 0ad64fa2f0ed..c1158859f857 100644 --- a/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h +++ b/gfx/skia/skia/src/core/SkColorMatrixFilterRowMajor255.h @@ -12,7 +12,7 @@ class SK_API SkColorMatrixFilterRowMajor255 : public SkColorFilter { public: - SkColorMatrixFilterRowMajor255() {}; + SkColorMatrixFilterRowMajor255() {} explicit SkColorMatrixFilterRowMajor255(const SkScalar array[20]); /** Creates a color matrix filter that returns the same value in all four channels. */ @@ -25,7 +25,7 @@ public: sk_sp makeComposed(sk_sp) const override; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*) const override; + sk_sp asFragmentProcessor(GrContext*) const override; #endif SK_TO_STRING_OVERRIDE() diff --git a/gfx/skia/skia/src/core/SkColorShader.cpp b/gfx/skia/skia/src/core/SkColorShader.cpp new file mode 100644 index 000000000000..cfa071fed8d4 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorShader.cpp @@ -0,0 +1,303 @@ +/* + * 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 "SkColorShader.h" +#include "SkColorSpace.h" +#include "SkReadBuffer.h" +#include "SkUtils.h" + +SkColorShader::SkColorShader(SkColor c) : fColor(c) {} + +bool SkColorShader::isOpaque() const { + return SkColorGetA(fColor) == 255; +} + +sk_sp SkColorShader::CreateProc(SkReadBuffer& buffer) { + return sk_make_sp(buffer.readColor()); +} + +void SkColorShader::flatten(SkWriteBuffer& buffer) const { + buffer.writeColor(fColor); +} + +uint32_t SkColorShader::ColorShaderContext::getFlags() const { + return fFlags; +} + +SkShader::Context* SkColorShader::onCreateContext(const ContextRec& rec, void* storage) const { + return new (storage) ColorShaderContext(*this, rec); +} + +SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shader, + const ContextRec& rec) + : INHERITED(shader, rec) +{ + SkColor color = shader.fColor; + unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha())); + + unsigned r = SkColorGetR(color); + unsigned g = SkColorGetG(color); + unsigned b = SkColorGetB(color); + + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + fPMColor = SkPackARGB32(a, r, g, b); + + SkColor4f c4 = SkColor4f::FromColor(shader.fColor); + c4.fA *= rec.fPaint->getAlpha() / 255.0f; + fPM4f = c4.premul(); + + fFlags = kConstInY32_Flag; + if (255 == a) { + fFlags |= kOpaqueAlpha_Flag; + } +} + +void SkColorShader::ColorShaderContext::shadeSpan(int x, int y, SkPMColor span[], int count) { + sk_memset32(span, fPMColor, count); +} + +void SkColorShader::ColorShaderContext::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { + memset(alpha, SkGetPackedA32(fPMColor), count); +} + +void SkColorShader::ColorShaderContext::shadeSpan4f(int x, int y, SkPM4f span[], int count) { + for (int i = 0; i < count; ++i) { + span[i] = fPM4f; + } +} + +SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { + if (info) { + if (info->fColors && info->fColorCount >= 1) { + info->fColors[0] = fColor; + } + info->fColorCount = 1; + info->fTileMode = SkShader::kRepeat_TileMode; + } + return kColor_GradientType; +} + +#if SK_SUPPORT_GPU + +#include "SkGr.h" +#include "effects/GrConstColorProcessor.h" +sk_sp SkColorShader::asFragmentProcessor(const AsFPArgs&) const { + GrColor color = SkColorToPremulGrColor(fColor); + return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode); +} + +#endif + +#ifndef SK_IGNORE_TO_STRING +void SkColorShader::toString(SkString* str) const { + str->append("SkColorShader: ("); + + str->append("Color: "); + str->appendHex(fColor); + + this->INHERITED::toString(str); + + str->append(")"); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static unsigned unit_to_byte(float unit) { + SkASSERT(unit >= 0 && unit <= 1); + return (unsigned)(unit * 255 + 0.5); +} + +static SkColor unit_to_skcolor(const SkColor4f& unit, SkColorSpace* cs) { + return SkColorSetARGB(unit_to_byte(unit.fA), unit_to_byte(unit.fR), + unit_to_byte(unit.fG), unit_to_byte(unit.fB)); +} + +SkColor4Shader::SkColor4Shader(const SkColor4f& color, sk_sp space) + : fColorSpace(std::move(space)) + , fColor4(color) + , fCachedByteColor(unit_to_skcolor(color.pin(), space.get())) +{} + +sk_sp SkColor4Shader::CreateProc(SkReadBuffer& buffer) { + SkColor4f color; + buffer.readColor4f(&color); + if (buffer.readBool()) { + // TODO how do we unflatten colorspaces + } + return SkShader::MakeColorShader(color, nullptr); +} + +void SkColor4Shader::flatten(SkWriteBuffer& buffer) const { + buffer.writeColor4f(fColor4); + buffer.writeBool(false); // TODO how do we flatten colorspaces? +} + +uint32_t SkColor4Shader::Color4Context::getFlags() const { + return fFlags; +} + +SkShader::Context* SkColor4Shader::onCreateContext(const ContextRec& rec, void* storage) const { + return new (storage) Color4Context(*this, rec); +} + +SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader, + const ContextRec& rec) +: INHERITED(shader, rec) +{ + SkColor color = shader.fCachedByteColor; + unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(rec.fPaint->getAlpha())); + + unsigned r = SkColorGetR(color); + unsigned g = SkColorGetG(color); + unsigned b = SkColorGetB(color); + + if (a != 255) { + r = SkMulDiv255Round(r, a); + g = SkMulDiv255Round(g, a); + b = SkMulDiv255Round(b, a); + } + fPMColor = SkPackARGB32(a, r, g, b); + + SkColor4f c4 = shader.fColor4; + c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f); + fPM4f = c4.premul(); + + fFlags = kConstInY32_Flag; + if (255 == a) { + fFlags |= kOpaqueAlpha_Flag; + } +} + +void SkColor4Shader::Color4Context::shadeSpan(int x, int y, SkPMColor span[], int count) { + sk_memset32(span, fPMColor, count); +} + +void SkColor4Shader::Color4Context::shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) { + memset(alpha, SkGetPackedA32(fPMColor), count); +} + +void SkColor4Shader::Color4Context::shadeSpan4f(int x, int y, SkPM4f span[], int count) { + for (int i = 0; i < count; ++i) { + span[i] = fPM4f; + } +} + +// TODO: do we need an updated version of this method for color4+colorspace? +SkShader::GradientType SkColor4Shader::asAGradient(GradientInfo* info) const { + if (info) { + if (info->fColors && info->fColorCount >= 1) { + info->fColors[0] = fCachedByteColor; + } + info->fColorCount = 1; + info->fTileMode = SkShader::kRepeat_TileMode; + } + return kColor_GradientType; +} + +#if SK_SUPPORT_GPU + +#include "SkGr.h" +#include "effects/GrConstColorProcessor.h" +sk_sp SkColor4Shader::asFragmentProcessor(const AsFPArgs&) const { + // TODO: how to communicate color4f to Gr + GrColor color = SkColorToPremulGrColor(fCachedByteColor); + return GrConstColorProcessor::Make(color, GrConstColorProcessor::kModulateA_InputMode); +} + +#endif + +#ifndef SK_IGNORE_TO_STRING +void SkColor4Shader::toString(SkString* str) const { + str->append("SkColor4Shader: ("); + + str->append("RGBA:"); + for (int i = 0; i < 4; ++i) { + str->appendf(" %g", fColor4.vec()[i]); + } + str->append(" )"); +} +#endif + +sk_sp SkShader::MakeColorShader(const SkColor4f& color, sk_sp space) { + if (!SkScalarsAreFinite(color.vec(), 4)) { + return nullptr; + } + return sk_make_sp(color, std::move(space)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static void D32_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, + int count) { + SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0]; + const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; + proc(state->fXfer, dst.writable_addr32(x, y), src, count, nullptr); +} + +static void D32_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, + int count, const SkAlpha aa[]) { + SkXfermode::D32Proc proc = (SkXfermode::D32Proc)state->fStorage[0]; + const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; + proc(state->fXfer, dst.writable_addr32(x, y), src, count, aa); +} + +static void F16_BlitBW(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, + int count) { + SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0]; + const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; + proc(state->fXfer, dst.writable_addr64(x, y), src, count, nullptr); +} + +static void F16_BlitAA(SkShader::Context::BlitState* state, int x, int y, const SkPixmap& dst, + int count, const SkAlpha aa[]) { + SkXfermode::F16Proc proc = (SkXfermode::F16Proc)state->fStorage[0]; + const SkPM4f* src = (const SkPM4f*)state->fStorage[1]; + proc(state->fXfer, dst.writable_addr64(x, y), src, count, aa); +} + +static bool choose_blitprocs(const SkPM4f* pm4, const SkImageInfo& info, + SkShader::Context::BlitState* state) { + uint32_t flags = SkXfermode::kSrcIsSingle_D32Flag; + if (pm4->a() == 1) { + flags |= SkXfermode::kSrcIsOpaque_D32Flag; + } + switch (info.colorType()) { + case kN32_SkColorType: + if (info.gammaCloseToSRGB()) { + flags |= SkXfermode::kDstIsSRGB_D32Flag; + } + state->fStorage[0] = (void*)SkXfermode::GetD32Proc(state->fXfer, flags); + state->fStorage[1] = (void*)pm4; + state->fBlitBW = D32_BlitBW; + state->fBlitAA = D32_BlitAA; + return true; + case kRGBA_F16_SkColorType: + state->fStorage[0] = (void*)SkXfermode::GetF16Proc(state->fXfer, flags); + state->fStorage[1] = (void*)pm4; + state->fBlitBW = F16_BlitBW; + state->fBlitAA = F16_BlitAA; + return true; + default: + return false; + } +} + +bool SkColorShader::ColorShaderContext::onChooseBlitProcs(const SkImageInfo& info, + BlitState* state) { + return choose_blitprocs(&fPM4f, info, state); +} + +bool SkColor4Shader::Color4Context::onChooseBlitProcs(const SkImageInfo& info, BlitState* state) { + return choose_blitprocs(&fPM4f, info, state); +} diff --git a/gfx/skia/skia/src/core/SkColorShader.h b/gfx/skia/skia/src/core/SkColorShader.h index db71b6ef9fdc..0bd270222374 100644 --- a/gfx/skia/skia/src/core/SkColorShader.h +++ b/gfx/skia/skia/src/core/SkColorShader.h @@ -49,8 +49,7 @@ public: GradientType asAGradient(GradientInfo* info) const override; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*, const SkMatrix& viewM, - const SkMatrix*, SkFilterQuality) const override; + sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif SK_TO_STRING_OVERRIDE() @@ -72,4 +71,59 @@ private: typedef SkShader INHERITED; }; +class SkColor4Shader : public SkShader { +public: + SkColor4Shader(const SkColor4f&, sk_sp); + + bool isOpaque() const override { + return SkColorGetA(fCachedByteColor) == 255; + } + + class Color4Context : public SkShader::Context { + public: + Color4Context(const SkColor4Shader& shader, const ContextRec&); + + uint32_t getFlags() const override; + void shadeSpan(int x, int y, SkPMColor span[], int count) override; + void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count) override; + void shadeSpan4f(int x, int y, SkPM4f[], int count) override; + + protected: + bool onChooseBlitProcs(const SkImageInfo&, BlitState*) override; + + private: + SkPM4f fPM4f; + SkPMColor fPMColor; + uint32_t fFlags; + + typedef SkShader::Context INHERITED; + }; + + GradientType asAGradient(GradientInfo* info) const override; + +#if SK_SUPPORT_GPU + sk_sp asFragmentProcessor(const AsFPArgs&) const override; +#endif + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkColorShader) + +protected: + SkColor4Shader(SkReadBuffer&); + void flatten(SkWriteBuffer&) const override; + Context* onCreateContext(const ContextRec&, void* storage) const override; + size_t onContextSize(const ContextRec&) const override { return sizeof(Color4Context); } + bool onAsLuminanceColor(SkColor* lum) const override { + *lum = fCachedByteColor; + return true; + } + +private: + sk_sp fColorSpace; + const SkColor4f fColor4; + const SkColor fCachedByteColor; + + typedef SkShader INHERITED; +}; + #endif diff --git a/gfx/skia/skia/src/core/SkColorSpace.cpp b/gfx/skia/skia/src/core/SkColorSpace.cpp index 549946965146..c6bf4b943130 100644 --- a/gfx/skia/skia/src/core/SkColorSpace.cpp +++ b/gfx/skia/skia/src/core/SkColorSpace.cpp @@ -5,546 +5,468 @@ * found in the LICENSE file. */ -#include "SkAtomics.h" #include "SkColorSpace.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpacePriv.h" +#include "SkOnce.h" -static inline bool SkFloatIsFinite(float x) { return 0 == x * 0; } +SkColorSpace_Base::SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) + : fGammaNamed(gammaNamed) + , fGammas(nullptr) + , fProfileData(nullptr) + , fToXYZD50(toXYZD50) + , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) +{} -// -// SkFloat3x3 -// -// In memory order, values are a, b, c, d, e, f, g, h, i -// -// When applied to a color component vector (e.g. [ r, r, r ] or [ g, g, g ] we do -// -// [ r r r ] * [ a b c ] + [ g g g ] * [ d e f ] + [ b b b ] * [ g h i ] -// -// Thus in our point-on-the-right notation, the matrix looks like -// -// [ a d g ] [ r ] -// [ b e h ] * [ g ] -// [ c f i ] [ b ] -// -static SkFloat3x3 concat(const SkFloat3x3& left, const SkFloat3x3& rite) { - SkFloat3x3 result; - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 3; ++col) { - double tmp = 0; - for (int i = 0; i < 3; ++i) { - tmp += (double)left.fMat[row + i * 3] * rite.fMat[i + col * 3]; - } - result.fMat[row + col * 3] = (double)tmp; - } - } - return result; +SkColorSpace_Base::SkColorSpace_Base(sk_sp colorLUT, SkGammaNamed gammaNamed, + sk_sp gammas, const SkMatrix44& toXYZD50, + sk_sp profileData) + : fColorLUT(std::move(colorLUT)) + , fGammaNamed(gammaNamed) + , fGammas(std::move(gammas)) + , fProfileData(std::move(profileData)) + , fToXYZD50(toXYZD50) + , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) +{} + +static constexpr float gSRGB_toXYZD50[] { + 0.4358f, 0.3853f, 0.1430f, // Rx, Gx, Bx + 0.2224f, 0.7170f, 0.0606f, // Ry, Gy, Gz + 0.0139f, 0.0971f, 0.7139f, // Rz, Gz, Bz +}; + +static constexpr float gAdobeRGB_toXYZD50[] { + 0.6098f, 0.2052f, 0.1492f, // Rx, Gx, Bx + 0.3111f, 0.6257f, 0.0632f, // Ry, Gy, By + 0.0195f, 0.0609f, 0.7448f, // Rz, Gz, Bz +}; + +/** + * Checks if our toXYZ matrix is a close match to a known color gamut. + * + * @param toXYZD50 transformation matrix deduced from profile data + * @param standard 3x3 canonical transformation matrix + */ +static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard) { + return color_space_almost_equal(toXYZD50.getFloat(0, 0), standard[0]) && + color_space_almost_equal(toXYZD50.getFloat(0, 1), standard[1]) && + color_space_almost_equal(toXYZD50.getFloat(0, 2), standard[2]) && + color_space_almost_equal(toXYZD50.getFloat(1, 0), standard[3]) && + color_space_almost_equal(toXYZD50.getFloat(1, 1), standard[4]) && + color_space_almost_equal(toXYZD50.getFloat(1, 2), standard[5]) && + color_space_almost_equal(toXYZD50.getFloat(2, 0), standard[6]) && + color_space_almost_equal(toXYZD50.getFloat(2, 1), standard[7]) && + color_space_almost_equal(toXYZD50.getFloat(2, 2), standard[8]) && + color_space_almost_equal(toXYZD50.getFloat(0, 3), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(1, 3), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(2, 3), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(3, 0), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(3, 1), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(3, 2), 0.0f) && + color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); } -static double det(const SkFloat3x3& m) { - return (double)m.fMat[0] * m.fMat[4] * m.fMat[8] + - (double)m.fMat[3] * m.fMat[7] * m.fMat[2] + - (double)m.fMat[6] * m.fMat[1] * m.fMat[5] - - (double)m.fMat[0] * m.fMat[7] * m.fMat[5] - - (double)m.fMat[3] * m.fMat[1] * m.fMat[8] - - (double)m.fMat[6] * m.fMat[4] * m.fMat[2]; -} - -static double det2x2(const SkFloat3x3& m, int a, int b, int c, int d) { - return (double)m.fMat[a] * m.fMat[b] - (double)m.fMat[c] * m.fMat[d]; -} - -static SkFloat3x3 invert(const SkFloat3x3& m) { - double d = det(m); - SkASSERT(SkFloatIsFinite((float)d)); - double scale = 1 / d; - SkASSERT(SkFloatIsFinite((float)scale)); - - return {{ - (float)(scale * det2x2(m, 4, 8, 5, 7)), - (float)(scale * det2x2(m, 7, 2, 8, 1)), - (float)(scale * det2x2(m, 1, 5, 2, 4)), - - (float)(scale * det2x2(m, 6, 5, 8, 3)), - (float)(scale * det2x2(m, 0, 8, 2, 6)), - (float)(scale * det2x2(m, 3, 2, 5, 0)), - - (float)(scale * det2x2(m, 3, 7, 4, 6)), - (float)(scale * det2x2(m, 6, 1, 7, 0)), - (float)(scale * det2x2(m, 0, 4, 1, 3)), - }}; -} - -void SkFloat3::dump() const { - SkDebugf("[%7.4f %7.4f %7.4f]\n", fVec[0], fVec[1], fVec[2]); -} - -void SkFloat3x3::dump() const { - SkDebugf("[%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f] [%7.4f %7.4f %7.4f]\n", - fMat[0], fMat[1], fMat[2], - fMat[3], fMat[4], fMat[5], - fMat[6], fMat[7], fMat[8]); -} - -////////////////////////////////////////////////////////////////////////////////////////////////// - -static int32_t gUniqueColorSpaceID; - -SkColorSpace::SkColorSpace(const SkFloat3x3& toXYZD50, const SkFloat3& gamma, Named named) - : fToXYZD50(toXYZD50) - , fGamma(gamma) - , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) - , fNamed(named) -{ - for (int i = 0; i < 3; ++i) { - SkASSERT(SkFloatIsFinite(gamma.fVec[i])); - for (int j = 0; j < 3; ++j) { - SkASSERT(SkFloatIsFinite(toXYZD50.fMat[3*i + j])); - } - } -} - -sk_sp SkColorSpace::NewRGB(const SkFloat3x3& toXYZD50, const SkFloat3& gamma) { - for (int i = 0; i < 3; ++i) { - if (!SkFloatIsFinite(gamma.fVec[i]) || gamma.fVec[i] < 0) { - return nullptr; - } - for (int j = 0; j < 3; ++j) { - if (!SkFloatIsFinite(toXYZD50.fMat[3*i + j])) { - return nullptr; - } - } - } - - // check the matrix for invertibility - float d = det(toXYZD50); - if (!SkFloatIsFinite(d) || !SkFloatIsFinite(1 / d)) { +sk_sp SkColorSpace_Base::NewRGB(const float values[3], const SkMatrix44& toXYZD50) { + if (0.0f > values[0] || 0.0f > values[1] || 0.0f > values[2]) { return nullptr; } - return sk_sp(new SkColorSpace(toXYZD50, gamma, kUnknown_Named)); + SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; + if (color_space_almost_equal(2.2f, values[0]) && + color_space_almost_equal(2.2f, values[1]) && + color_space_almost_equal(2.2f, values[2])) { + gammaNamed = k2Dot2Curve_SkGammaNamed; + } else if (color_space_almost_equal(1.0f, values[0]) && + color_space_almost_equal(1.0f, values[1]) && + color_space_almost_equal(1.0f, values[2])) { + gammaNamed = kLinear_SkGammaNamed; + } + + if (kNonStandard_SkGammaNamed == gammaNamed) { + sk_sp gammas = sk_sp(new SkGammas()); + gammas->fRedType = SkGammas::Type::kValue_Type; + gammas->fGreenType = SkGammas::Type::kValue_Type; + gammas->fBlueType = SkGammas::Type::kValue_Type; + gammas->fRedData.fValue = values[0]; + gammas->fGreenData.fValue = values[1]; + gammas->fBlueData.fValue = values[2]; + return sk_sp(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed, gammas, + toXYZD50, nullptr)); + } + + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50); } -void SkColorSpace::dump() const { - fToXYZD50.dump(); - fGamma.dump(); +sk_sp SkColorSpace_Base::NewRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) { + switch (gammaNamed) { + case kSRGB_SkGammaNamed: + if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { + return SkColorSpace::NewNamed(kSRGB_Named); + } + break; + case k2Dot2Curve_SkGammaNamed: + if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { + return SkColorSpace::NewNamed(kAdobeRGB_Named); + } + break; + case kLinear_SkGammaNamed: + if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { + return SkColorSpace::NewNamed(kSRGBLinear_Named); + } + break; + case kNonStandard_SkGammaNamed: + // This is not allowed. + return nullptr; + default: + break; + } + + return sk_sp(new SkColorSpace_Base(gammaNamed, toXYZD50)); } -////////////////////////////////////////////////////////////////////////////////////////////////// +sk_sp SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50) { + switch (gamma) { + case kLinear_RenderTargetGamma: + return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, toXYZD50); + case kSRGB_RenderTargetGamma: + return SkColorSpace_Base::NewRGB(kSRGB_SkGammaNamed, toXYZD50); + default: + return nullptr; + } +} -const SkFloat3 gDevice_gamma {{ 0, 0, 0 }}; -const SkFloat3x3 gDevice_toXYZD50 {{ - 1, 0, 0, - 0, 1, 0, - 0, 0, 1 -}}; - -const SkFloat3 gSRGB_gamma {{ 2.2f, 2.2f, 2.2f }}; -const SkFloat3x3 gSRGB_toXYZD50 {{ - 0.4358f, 0.2224f, 0.0139f, // * R - 0.3853f, 0.7170f, 0.0971f, // * G - 0.1430f, 0.0606f, 0.7139f, // * B -}}; +static SkColorSpace* gAdobeRGB; +static SkColorSpace* gSRGB; +static SkColorSpace* gSRGBLinear; sk_sp SkColorSpace::NewNamed(Named named) { + static SkOnce sRGBOnce; + static SkOnce adobeRGBOnce; + static SkOnce sRGBLinearOnce; + switch (named) { - case kDevice_Named: - return sk_sp(new SkColorSpace(gDevice_toXYZD50, gDevice_gamma, - kDevice_Named)); - case kSRGB_Named: - return sk_sp(new SkColorSpace(gSRGB_toXYZD50, gSRGB_gamma, kSRGB_Named)); + case kSRGB_Named: { + sRGBOnce([] { + SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); + srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); + + // Force the mutable type mask to be computed. This avoids races. + (void)srgbToxyzD50.getType(); + gSRGB = new SkColorSpace_Base(kSRGB_SkGammaNamed, srgbToxyzD50); + }); + return sk_ref_sp(gSRGB); + } + case kAdobeRGB_Named: { + adobeRGBOnce([] { + SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Constructor); + adobergbToxyzD50.set3x3RowMajorf(gAdobeRGB_toXYZD50); + + // Force the mutable type mask to be computed. This avoids races. + (void)adobergbToxyzD50.getType(); + gAdobeRGB = new SkColorSpace_Base(k2Dot2Curve_SkGammaNamed, adobergbToxyzD50); + }); + return sk_ref_sp(gAdobeRGB); + } + case kSRGBLinear_Named: { + sRGBLinearOnce([] { + SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); + srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); + + // Force the mutable type mask to be computed. This avoids races. + (void)srgbToxyzD50.getType(); + gSRGBLinear = new SkColorSpace_Base(kLinear_SkGammaNamed, srgbToxyzD50); + }); + return sk_ref_sp(gSRGBLinear); + } default: break; } return nullptr; } +sk_sp SkColorSpace::makeLinearGamma() { + if (this->gammaIsLinear()) { + return sk_ref_sp(this); + } + return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, as_CSB(this)->fToXYZD50); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// -#include "SkFixed.h" -#include "SkTemplates.h" - -#define SkColorSpacePrintf(...) - -#define return_if_false(pred, msg) \ - do { \ - if (!(pred)) { \ - SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ - return false; \ - } \ - } while (0) - -#define return_null(msg) \ - do { \ - SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ - return nullptr; \ - } while (0) - -static uint16_t read_big_endian_short(const uint8_t* ptr) { - return ptr[0] << 8 | ptr[1]; +bool SkColorSpace::gammaCloseToSRGB() const { + return kSRGB_SkGammaNamed == as_CSB(this)->fGammaNamed || + k2Dot2Curve_SkGammaNamed == as_CSB(this)->fGammaNamed; } -static uint32_t read_big_endian_int(const uint8_t* ptr) { - return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; +bool SkColorSpace::gammaIsLinear() const { + return kLinear_SkGammaNamed == as_CSB(this)->fGammaNamed; } -// This is equal to the header size according to the ICC specification (128) -// plus the size of the tag count (4). We include the tag count since we -// always require it to be present anyway. -static const size_t kICCHeaderSize = 132; - -// Contains a signature (4), offset (4), and size (4). -static const size_t kICCTagTableEntrySize = 12; - -static const uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); -static const uint32_t kGray_ColorSpace = SkSetFourByteTag('G', 'R', 'A', 'Y'); - -struct ICCProfileHeader { - // TODO (msarett): - // Can we ignore less of these fields? - uint32_t fSize; - uint32_t fCMMType_ignored; - uint32_t fVersion; - uint32_t fClassProfile; - uint32_t fColorSpace; - uint32_t fPCS; - uint32_t fDateTime_ignored[3]; - uint32_t fSignature; - uint32_t fPlatformTarget_ignored; - uint32_t fFlags_ignored; - uint32_t fManufacturer_ignored; - uint32_t fDeviceModel_ignored; - uint32_t fDeviceAttributes_ignored[2]; - uint32_t fRenderingIntent; - uint32_t fIlluminantXYZ_ignored[3]; - uint32_t fCreator_ignored; - uint32_t fProfileId_ignored[4]; - uint32_t fReserved_ignored[7]; - uint32_t fTagCount; - - void init(const uint8_t* src, size_t len) { - SkASSERT(kICCHeaderSize == sizeof(*this)); - - uint32_t* dst = (uint32_t*) this; - for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) { - dst[i] = read_big_endian_int(src); +const SkMatrix44& SkColorSpace_Base::fromXYZD50() const { + fFromXYZOnce([this] { + if (!fToXYZD50.invert(&fFromXYZD50)) { + // If a client gives us a dst gamut with a transform that we can't invert, we will + // simply give them back a transform to sRGB gamut. + SkDEBUGFAIL("Non-invertible XYZ matrix, defaulting to sRGB"); + SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); + srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); + srgbToxyzD50.invert(&fFromXYZD50); } - } + }); + return fFromXYZD50; +} - bool valid() const { - // TODO (msarett): - // For now it's nice to fail loudly on invalid inputs. But, can we - // recover from some of these errors? +/////////////////////////////////////////////////////////////////////////////////////////////////// - return_if_false(fSize >= kICCHeaderSize, "Size is too small"); - - uint8_t majorVersion = fVersion >> 24; - return_if_false(majorVersion <= 4, "Unsupported version"); - - const uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); - const uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); - const uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); - // TODO (msarett): - // Should we also support DeviceLink, ColorSpace, Abstract, or NamedColor? - return_if_false(fClassProfile == kDisplay_Profile || - fClassProfile == kInput_Profile || - fClassProfile == kOutput_Profile, - "Unsupported class profile"); - - // TODO (msarett): - // There are many more color spaces that we could try to support. - return_if_false(fColorSpace == kRGB_ColorSpace || fColorSpace == kGray_ColorSpace, - "Unsupported color space"); - - const uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); - // TODO (msarett): - // Can we support PCS LAB as well? - return_if_false(fPCS == kXYZ_PCSSpace, "Unsupported PCS space"); - - return_if_false(fSignature == SkSetFourByteTag('a', 'c', 's', 'p'), "Bad signature"); - - // TODO (msarett): - // Should we treat different rendering intents differently? - // Valid rendering intents include kPerceptual (0), kRelative (1), - // kSaturation (2), and kAbsolute (3). - return_if_false(fRenderingIntent <= 3, "Bad rendering intent"); - - return_if_false(fTagCount <= 100, "Too many tags"); - - return true; - } +enum Version { + k0_Version, // Initial version, header + flags for matrix and profile }; -struct ICCTag { - uint32_t fSignature; - uint32_t fOffset; - uint32_t fLength; +struct ColorSpaceHeader { + /** + * If kMatrix_Flag is set, we will write 12 floats after the header. + * Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag. + */ + static constexpr uint8_t kMatrix_Flag = 1 << 0; - const uint8_t* init(const uint8_t* src) { - fSignature = read_big_endian_int(src); - fOffset = read_big_endian_int(src + 4); - fLength = read_big_endian_int(src + 8); - return src + 12; + /** + * If kICC_Flag is set, we will write an ICC profile after the header. + * The ICC profile will be written as a uint32 size, followed immediately + * by the data (padded to 4 bytes). + * Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Flag. + */ + static constexpr uint8_t kICC_Flag = 1 << 1; + + /** + * If kFloatGamma_Flag is set, we will write 15 floats after the header. + * The first three are the gamma values, and the next twelve are the + * matrix. + * Should not be set at the same time as the kICC_Flag or kMatrix_Flag. + */ + static constexpr uint8_t kFloatGamma_Flag = 1 << 2; + + static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNamed, uint8_t flags) + { + ColorSpaceHeader header; + + SkASSERT(k0_Version == version); + header.fVersion = (uint8_t) version; + + SkASSERT(named <= SkColorSpace::kSRGBLinear_Named); + header.fNamed = (uint8_t) named; + + SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed); + header.fGammaNamed = (uint8_t) gammaNamed; + + SkASSERT(flags <= kFloatGamma_Flag); + header.fFlags = flags; + return header; } - bool valid(size_t len) { - return_if_false(fOffset + fLength <= len, "Tag too large for ICC profile"); - return true; - } - - const uint8_t* addr(const uint8_t* src) const { - return src + fOffset; - } - - static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature) { - for (int i = 0; i < count; ++i) { - if (tags[i].fSignature == signature) { - return &tags[i]; - } - } - return nullptr; - } + uint8_t fVersion; // Always zero + uint8_t fNamed; // Must be a SkColorSpace::Named + uint8_t fGammaNamed; // Must be a SkGammaNamed + uint8_t fFlags; // Some combination of the flags listed above }; -// TODO (msarett): -// Should we recognize more tags? -static const uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); -static const uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); -static const uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); -static const uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); -static const uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); -static const uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); - -bool load_xyz(float dst[3], const uint8_t* src, size_t len) { - if (len < 20) { - SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); - return false; - } - - dst[0] = SkFixedToFloat(read_big_endian_int(src + 8)); - dst[1] = SkFixedToFloat(read_big_endian_int(src + 12)); - dst[2] = SkFixedToFloat(read_big_endian_int(src + 16)); - SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); - return true; -} - -static const uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); -static const uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); - -static bool load_gamma(float* gamma, const uint8_t* src, size_t len) { - if (len < 14) { - SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); - return false; - } - - uint32_t type = read_big_endian_int(src); - switch (type) { - case kTAG_CurveType: { - uint32_t count = read_big_endian_int(src + 8); - if (0 == count) { - return false; +size_t SkColorSpace::writeToMemory(void* memory) const { + // Start by trying the serialization fast path. If we haven't saved ICC profile data, + // we must have a profile that we can serialize easily. + if (!as_CSB(this)->fProfileData) { + // If we have a named profile, only write the enum. + if (this == gSRGB) { + if (memory) { + *((ColorSpaceHeader*) memory) = + ColorSpaceHeader::Pack(k0_Version, kSRGB_Named, + as_CSB(this)->fGammaNamed, 0); } - - const uint16_t* table = (const uint16_t*) (src + 12); - if (1 == count) { - // Table entry is the exponent (bias 256). - uint16_t value = read_big_endian_short((const uint8_t*) table); - *gamma = value / 256.0f; - SkColorSpacePrintf("gamma %d %g\n", value, *gamma); - return true; + return sizeof(ColorSpaceHeader); + } else if (this == gAdobeRGB) { + if (memory) { + *((ColorSpaceHeader*) memory) = + ColorSpaceHeader::Pack(k0_Version, kAdobeRGB_Named, + as_CSB(this)->fGammaNamed, 0); } - - // Check length again if we have a table. - if (len < 12 + 2 * count) { - SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); - return false; + return sizeof(ColorSpaceHeader); + } else if (this == gSRGBLinear) { + if (memory) { + *((ColorSpaceHeader*)memory) = + ColorSpaceHeader::Pack(k0_Version, kSRGBLinear_Named, + as_CSB(this)->fGammaNamed, 0); } - - // Print the interpolation table. For now, we ignore this and guess 2.2f. - for (uint32_t i = 0; i < count; i++) { - SkColorSpacePrintf("curve[%d] %d\n", i, - read_big_endian_short((const uint8_t*) &table[i])); - } - - *gamma = 2.2f; - return true; + return sizeof(ColorSpaceHeader); + } + + // If we have a named gamma, write the enum and the matrix. + switch (as_CSB(this)->fGammaNamed) { + case kSRGB_SkGammaNamed: + case k2Dot2Curve_SkGammaNamed: + case kLinear_SkGammaNamed: { + if (memory) { + *((ColorSpaceHeader*) memory) = + ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::kMatrix_Flag); + memory = SkTAddOffset(memory, sizeof(ColorSpaceHeader)); + as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + } + return sizeof(ColorSpaceHeader) + 12 * sizeof(float); + } + default: + // Otherwise, write the gamma values and the matrix. + if (memory) { + *((ColorSpaceHeader*) memory) = + ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::kFloatGamma_Flag); + memory = SkTAddOffset(memory, sizeof(ColorSpaceHeader)); + + const SkGammas* gammas = as_CSB(this)->gammas(); + SkASSERT(gammas); + SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType && + SkGammas::Type::kValue_Type == gammas->fGreenType && + SkGammas::Type::kValue_Type == gammas->fBlueType); + *(((float*) memory) + 0) = gammas->fRedData.fValue; + *(((float*) memory) + 1) = gammas->fGreenData.fValue; + *(((float*) memory) + 2) = gammas->fBlueData.fValue; + memory = SkTAddOffset(memory, 3 * sizeof(float)); + + as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + } + return sizeof(ColorSpaceHeader) + 15 * sizeof(float); } - case kTAG_ParaCurveType: - // Guess 2.2f. - SkColorSpacePrintf("parametric curve\n"); - *gamma = 2.2f; - return true; - default: - SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); - return false; } + + // Otherwise, serialize the ICC data. + size_t profileSize = as_CSB(this)->fProfileData->size(); + if (SkAlign4(profileSize) != (uint32_t) SkAlign4(profileSize)) { + return 0; + } + + if (memory) { + *((ColorSpaceHeader*) memory) = ColorSpaceHeader::Pack(k0_Version, 0, + kNonStandard_SkGammaNamed, + ColorSpaceHeader::kICC_Flag); + memory = SkTAddOffset(memory, sizeof(ColorSpaceHeader)); + + *((uint32_t*) memory) = (uint32_t) SkAlign4(profileSize); + memory = SkTAddOffset(memory, sizeof(uint32_t)); + + memcpy(memory, as_CSB(this)->fProfileData->data(), profileSize); + memset(SkTAddOffset(memory, profileSize), 0, SkAlign4(profileSize) - profileSize); + } + return sizeof(ColorSpaceHeader) + sizeof(uint32_t) + SkAlign4(profileSize); } -sk_sp SkColorSpace::NewICC(const void* base, size_t len) { - const uint8_t* ptr = (const uint8_t*) base; - - if (len < kICCHeaderSize) { - return_null("Data is not large enough to contain an ICC profile"); - } - - // Read the ICC profile header and check to make sure that it is valid. - ICCProfileHeader header; - header.init(ptr, len); - if (!header.valid()) { +sk_sp SkColorSpace::serialize() const { + size_t size = this->writeToMemory(nullptr); + if (0 == size) { return nullptr; } - // Adjust ptr and len before reading the tags. - if (len < header.fSize) { - SkColorSpacePrintf("ICC profile might be truncated.\n"); - } else if (len > header.fSize) { - SkColorSpacePrintf("Caller provided extra data beyond the end of the ICC profile.\n"); - len = header.fSize; - } - ptr += kICCHeaderSize; - len -= kICCHeaderSize; + sk_sp data = SkData::MakeUninitialized(size); + this->writeToMemory(data->writable_data()); + return data; +} - // Parse tag headers. - uint32_t tagCount = header.fTagCount; - SkColorSpacePrintf("ICC profile contains %d tags.\n", tagCount); - if (len < kICCTagTableEntrySize * tagCount) { - return_null("Not enough input data to read tag table entries"); +sk_sp SkColorSpace::Deserialize(const void* data, size_t length) { + if (length < sizeof(ColorSpaceHeader)) { + return nullptr; } - SkAutoTArray tags(tagCount); - for (uint32_t i = 0; i < tagCount; i++) { - ptr = tags[i].init(ptr); - SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24) & 0xFF, - (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF, - (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLength); - - if (!tags[i].valid(kICCHeaderSize + len)) { - return_null("Tag is too large to fit in ICC profile"); - } + ColorSpaceHeader header = *((const ColorSpaceHeader*) data); + data = SkTAddOffset(data, sizeof(ColorSpaceHeader)); + length -= sizeof(ColorSpaceHeader); + if (0 == header.fFlags) { + return NewNamed((Named) header.fNamed); } - // Load our XYZ and gamma matrices. - SkFloat3x3 toXYZ; - SkFloat3 gamma {{ 1.0f, 1.0f, 1.0f }}; - switch (header.fColorSpace) { - case kRGB_ColorSpace: { - const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); - const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); - const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); - if (!r || !g || !b) { - return_null("Need rgb tags for XYZ space"); + switch ((SkGammaNamed) header.fGammaNamed) { + case kSRGB_SkGammaNamed: + case k2Dot2Curve_SkGammaNamed: + case kLinear_SkGammaNamed: { + if (ColorSpaceHeader::kMatrix_Flag != header.fFlags || length < 12 * sizeof(float)) { + return nullptr; } - if (!load_xyz(&toXYZ.fMat[0], r->addr((const uint8_t*) base), r->fLength) || - !load_xyz(&toXYZ.fMat[3], g->addr((const uint8_t*) base), g->fLength) || - !load_xyz(&toXYZ.fMat[6], b->addr((const uint8_t*) base), b->fLength)) - { - return_null("Need valid rgb tags for XYZ space"); - } - - r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); - g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); - b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); - if (!r || !load_gamma(&gamma.fVec[0], r->addr((const uint8_t*) base), r->fLength)) { - SkColorSpacePrintf("Failed to read R gamma tag.\n"); - } - if (!g || !load_gamma(&gamma.fVec[1], g->addr((const uint8_t*) base), g->fLength)) { - SkColorSpacePrintf("Failed to read G gamma tag.\n"); - } - if (!b || !load_gamma(&gamma.fVec[2], b->addr((const uint8_t*) base), b->fLength)) { - SkColorSpacePrintf("Failed to read B gamma tag.\n"); - } - return SkColorSpace::NewRGB(toXYZ, gamma); + SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); + toXYZ.set3x4RowMajorf((const float*) data); + return SkColorSpace_Base::NewRGB((SkGammaNamed) header.fGammaNamed, toXYZ); } default: break; } - return_null("ICC profile contains unsupported colorspace"); -} + switch (header.fFlags) { + case ColorSpaceHeader::kICC_Flag: { + if (length < sizeof(uint32_t)) { + return nullptr; + } -/////////////////////////////////////////////////////////////////////////////////////////////////// + uint32_t profileSize = *((uint32_t*) data); + data = SkTAddOffset(data, sizeof(uint32_t)); + length -= sizeof(uint32_t); + if (length < profileSize) { + return nullptr; + } -SkColorSpace::Result SkColorSpace::Concat(const SkColorSpace* src, const SkColorSpace* dst, - SkFloat3x3* result) { - if (!src || !dst || (src->named() == kDevice_Named) || (src->named() == dst->named())) { - if (result) { - *result = {{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }}; + return NewICC(data, profileSize); } - return kIdentity_Result; - } - if (result) { - *result = concat(src->fToXYZD50, invert(dst->fToXYZD50)); - } - return kNormal_Result; -} + case ColorSpaceHeader::kFloatGamma_Flag: { + if (length < 15 * sizeof(float)) { + return nullptr; + } -#include "SkColor.h" -#include "SkNx.h" -#include "SkPM4f.h" + float gammas[3]; + gammas[0] = *(((const float*) data) + 0); + gammas[1] = *(((const float*) data) + 1); + gammas[2] = *(((const float*) data) + 2); + data = SkTAddOffset(data, 3 * sizeof(float)); -void SkApply3x3ToPM4f(const SkFloat3x3& m, const SkPM4f src[], SkPM4f dst[], int count) { - SkASSERT(1 == SkPM4f::G); - SkASSERT(3 == SkPM4f::A); - - Sk4f cr, cg, cb; - cg = Sk4f::Load(m.fMat + 3); - if (0 == SkPM4f::R) { - SkASSERT(2 == SkPM4f::B); - cr = Sk4f::Load(m.fMat + 0); - cb = Sk4f(m.fMat[6], m.fMat[7], m.fMat[8], 0); - } else { - SkASSERT(0 == SkPM4f::B); - SkASSERT(2 == SkPM4f::R); - cb = Sk4f::Load(m.fMat + 0); - cr = Sk4f(m.fMat[6], m.fMat[7], m.fMat[8], 0); - } - cr = cr * Sk4f(1, 1, 1, 0); - cg = cg * Sk4f(1, 1, 1, 0); - cb = cb * Sk4f(1, 1, 1, 0); - - for (int i = 0; i < count; ++i) { - Sk4f r = Sk4f(src[i].fVec[SkPM4f::R]); - Sk4f g = Sk4f(src[i].fVec[SkPM4f::G]); - Sk4f b = Sk4f(src[i].fVec[SkPM4f::B]); - Sk4f a = Sk4f(0, 0, 0, src[i].fVec[SkPM4f::A]); - (cr * r + cg * g + cb * b + a).store(&dst[i]); + SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); + toXYZ.set3x4RowMajorf((const float*) data); + return SkColorSpace_Base::NewRGB(gammas, toXYZ); + } + default: + return nullptr; } } -/////////////////////////////////////////////////////////////////////////////////////////////////// +bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) { + if (src == dst) { + return true; + } -void SkColorSpace::Test() { - SkFloat3x3 mat {{ 2, 0, 0, 0, 3, 0, 0, 0, 4 }}; - SkFloat3x3 inv = invert(mat); - mat.dump(); - inv.dump(); - concat(mat, inv).dump(); - concat(inv, mat).dump(); - SkDebugf("\n"); + if (!src || !dst) { + return false; + } - mat = gSRGB_toXYZD50; - inv = invert(mat); - mat.dump(); - inv.dump(); - concat(mat, inv).dump(); - concat(inv, mat).dump(); - SkDebugf("\n"); + SkData* srcData = as_CSB(src)->fProfileData.get(); + SkData* dstData = as_CSB(dst)->fProfileData.get(); + if (srcData || dstData) { + if (srcData && dstData) { + return srcData->size() == dstData->size() && + 0 == memcmp(srcData->data(), dstData->data(), srcData->size()); + } - sk_sp cs0(SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)); - sk_sp cs1(SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)); + return false; + } - cs0->dump(); - cs1->dump(); - SkFloat3x3 xform; - (void)SkColorSpace::Concat(cs0.get(), cs1.get(), &xform); - xform.dump(); - SkDebugf("\n"); + // It's important to check fProfileData before named gammas. Some profiles may have named + // gammas, but also include other wacky features that cause us to save the data. + switch (as_CSB(src)->fGammaNamed) { + case kSRGB_SkGammaNamed: + case k2Dot2Curve_SkGammaNamed: + case kLinear_SkGammaNamed: + return (as_CSB(src)->fGammaNamed == as_CSB(dst)->fGammaNamed) && + (as_CSB(src)->fToXYZD50 == as_CSB(dst)->fToXYZD50); + default: + if (as_CSB(src)->fGammaNamed != as_CSB(dst)->fGammaNamed) { + return false; + } + + // It is unlikely that we will reach this case. + sk_sp srcData = src->serialize(); + sk_sp dstData = dst->serialize(); + return srcData->size() == dstData->size() && + 0 == memcmp(srcData->data(), dstData->data(), srcData->size()); + } } - -// D65 white point of Rec. 709 [8] are: -// -// D65 white-point in unit luminance XYZ = 0.9505, 1.0000, 1.0890 -// -// R G B white -// x 0.640 0.300 0.150 0.3127 -// y 0.330 0.600 0.060 0.3290 -// z 0.030 0.100 0.790 0.3582 diff --git a/gfx/skia/skia/src/core/SkColorSpace.h b/gfx/skia/skia/src/core/SkColorSpace.h deleted file mode 100644 index 777be9da2b4e..000000000000 --- a/gfx/skia/skia/src/core/SkColorSpace.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 - -// Some terms -// -// PCS : Profile Connection Space : where color number values have an absolute meaning. -// Part of the work float is to convert colors to and from this space... -// src_linear_unit_floats --> PCS --> PCS' --> dst_linear_unit_floats -// -// Some nice documents -// -// http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm -// https://www.w3.org/Graphics/Color/srgb -// http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html -// - -#include "SkRefCnt.h" - -struct SkFloat3 { - float fVec[3]; - - void dump() const; -}; - -struct SkFloat3x3 { - float fMat[9]; - - void dump() const; -}; - -struct SkPM4f; -void SkApply3x3ToPM4f(const SkFloat3x3&, const SkPM4f src[], SkPM4f dst[], int count); - -class SkColorSpace : public SkRefCnt { -public: - enum Named { - kUnknown_Named, - kDevice_Named, - kSRGB_Named, - }; - - /** - * Return a colorspace instance, given a 3x3 transform from linear_RGB to D50_XYZ - * and the src-gamma, return a ColorSpace - */ - static sk_sp NewRGB(const SkFloat3x3& toXYZD50, const SkFloat3& gamma); - - static sk_sp NewNamed(Named); - static sk_sp NewICC(const void*, size_t); - - SkFloat3 gamma() const { return fGamma; } - SkFloat3x3 xyz() const { return fToXYZD50; } - Named named() const { return fNamed; } - uint32_t uniqueID() const { return fUniqueID; } - - enum Result { - kFailure_Result, - kIdentity_Result, - kNormal_Result, - }; - - /** - * Given a src and dst colorspace, return the 3x3 matrix that will convert src_linear_RGB - * values into dst_linear_RGB values. - */ - static Result Concat(const SkColorSpace* src, const SkColorSpace* dst, SkFloat3x3* result); - - static void Test(); - void dump() const; - -protected: - SkColorSpace(const SkFloat3x3& toXYZ, const SkFloat3& gamma, Named); - -private: - const SkFloat3x3 fToXYZD50; - const SkFloat3 fGamma; - const uint32_t fUniqueID; - const Named fNamed; -}; - -#endif diff --git a/gfx/skia/skia/src/core/SkColorSpacePriv.h b/gfx/skia/skia/src/core/SkColorSpacePriv.h new file mode 100644 index 000000000000..e7c8aaa10382 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpacePriv.h @@ -0,0 +1,12 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#define SkColorSpacePrintf(...) + +inline bool color_space_almost_equal(float a, float b) { + return SkTAbs(a - b) < 0.01f; +} diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform.cpp b/gfx/skia/skia/src/core/SkColorSpaceXform.cpp new file mode 100644 index 000000000000..f7a0239d272a --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXform.cpp @@ -0,0 +1,1440 @@ +/* + * 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 "SkColorPriv.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpacePriv.h" +#include "SkColorSpaceXform.h" +#include "SkHalf.h" +#include "SkOpts.h" +#include "SkSRGB.h" + +static constexpr float sk_linear_from_2dot2[256] = { + 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f, + 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f, + 0.000492503787191433f, 0.000638182842167022f, 0.000804658499513058f, 0.000992374304074325f, + 0.001201739522438400f, 0.001433134589671860f, 0.001686915316789280f, 0.001963416213396470f, + 0.002262953160706430f, 0.002585825596234170f, 0.002932318323938360f, 0.003302703032003640f, + 0.003697239578900130f, 0.004116177093282750f, 0.004559754922526020f, 0.005028203456855540f, + 0.005521744850239660f, 0.006040593654849810f, 0.006584957382581690f, 0.007155037004573030f, + 0.007751027397660610f, 0.008373117745148580f, 0.009021491898012130f, 0.009696328701658230f, + 0.010397802292555300f, 0.011126082368383200f, 0.011881334434813700f, 0.012663720031582100f, + 0.013473396940142600f, 0.014310519374884100f, 0.015175238159625200f, 0.016067700890886900f, + 0.016988052089250000f, 0.017936433339950200f, 0.018912983423721500f, 0.019917838438785700f, + 0.020951131914781100f, 0.022012994919336500f, 0.023103556157921400f, 0.024222942067534200f, + 0.025371276904734600f, 0.026548682828472900f, 0.027755279978126000f, 0.028991186547107800f, + 0.030256518852388700f, 0.031551391400226400f, 0.032875916948383800f, 0.034230206565082000f, + 0.035614369684918800f, 0.037028514161960200f, 0.038472746320194600f, 0.039947171001525600f, + 0.041451891611462500f, 0.042987010162657100f, 0.044552627316421400f, 0.046148842422351000f, + 0.047775753556170600f, 0.049433457555908000f, 0.051122050056493400f, 0.052841625522879000f, + 0.054592277281760300f, 0.056374097551979800f, 0.058187177473685400f, 0.060031607136313200f, + 0.061907475605455800f, 0.063814870948677200f, 0.065753880260330100f, 0.067724589685424300f, + 0.069727084442598800f, 0.071761448846239100f, 0.073827766327784600f, 0.075926119456264800f, + 0.078056589958101900f, 0.080219258736215100f, 0.082414205888459200f, 0.084641510725429500f, + 0.086901251787660300f, 0.089193506862247800f, 0.091518352998919500f, 0.093875866525577800f, + 0.096266123063339700f, 0.098689197541094500f, 0.101145164209600000f, 0.103634096655137000f, + 0.106156067812744000f, 0.108711149979039000f, 0.111299414824660000f, 0.113920933406333000f, + 0.116575776178572000f, 0.119264013005047000f, 0.121985713169619000f, 0.124740945387051000f, + 0.127529777813422000f, 0.130352278056244000f, 0.133208513184300000f, 0.136098549737202000f, + 0.139022453734703000f, 0.141980290685736000f, 0.144972125597231000f, 0.147998022982685000f, + 0.151058046870511000f, 0.154152260812165000f, 0.157280727890073000f, 0.160443510725344000f, + 0.163640671485290000f, 0.166872271890766000f, 0.170138373223312000f, 0.173439036332135000f, + 0.176774321640903000f, 0.180144289154390000f, 0.183548998464951000f, 0.186988508758844000f, + 0.190462878822409000f, 0.193972167048093000f, 0.197516431440340000f, 0.201095729621346000f, + 0.204710118836677000f, 0.208359655960767000f, 0.212044397502288000f, 0.215764399609395000f, + 0.219519718074868000f, 0.223310408341127000f, 0.227136525505149000f, 0.230998124323267000f, + 0.234895259215880000f, 0.238827984272048000f, 0.242796353254002000f, 0.246800419601550000f, + 0.250840236436400000f, 0.254915856566385000f, 0.259027332489606000f, 0.263174716398492000f, + 0.267358060183772000f, 0.271577415438375000f, 0.275832833461245000f, 0.280124365261085000f, + 0.284452061560024000f, 0.288815972797219000f, 0.293216149132375000f, 0.297652640449211000f, + 0.302125496358853000f, 0.306634766203158000f, 0.311180499057984000f, 0.315762743736397000f, + 0.320381548791810000f, 0.325036962521076000f, 0.329729032967515000f, 0.334457807923889000f, + 0.339223334935327000f, 0.344025661302187000f, 0.348864834082879000f, 0.353740900096629000f, + 0.358653905926199000f, 0.363603897920553000f, 0.368590922197487000f, 0.373615024646202000f, + 0.378676250929840000f, 0.383774646487975000f, 0.388910256539059000f, 0.394083126082829000f, + 0.399293299902674000f, 0.404540822567962000f, 0.409825738436323000f, 0.415148091655907000f, + 0.420507926167587000f, 0.425905285707146000f, 0.431340213807410000f, 0.436812753800359000f, + 0.442322948819202000f, 0.447870841800410000f, 0.453456475485731000f, 0.459079892424160000f, + 0.464741134973889000f, 0.470440245304218000f, 0.476177265397440000f, 0.481952237050698000f, + 0.487765201877811000f, 0.493616201311074000f, 0.499505276603030000f, 0.505432468828216000f, + 0.511397818884880000f, 0.517401367496673000f, 0.523443155214325000f, 0.529523222417277000f, + 0.535641609315311000f, 0.541798355950137000f, 0.547993502196972000f, 0.554227087766085000f, + 0.560499152204328000f, 0.566809734896638000f, 0.573158875067523000f, 0.579546611782525000f, + 0.585972983949661000f, 0.592438030320847000f, 0.598941789493296000f, 0.605484299910907000f, + 0.612065599865624000f, 0.618685727498780000f, 0.625344720802427000f, 0.632042617620641000f, + 0.638779455650817000f, 0.645555272444935000f, 0.652370105410821000f, 0.659223991813387000f, + 0.666116968775851000f, 0.673049073280942000f, 0.680020342172095000f, 0.687030812154625000f, + 0.694080519796882000f, 0.701169501531402000f, 0.708297793656032000f, 0.715465432335048000f, + 0.722672453600255000f, 0.729918893352071000f, 0.737204787360605000f, 0.744530171266715000f, + 0.751895080583051000f, 0.759299550695091000f, 0.766743616862161000f, 0.774227314218442000f, + 0.781750677773962000f, 0.789313742415586000f, 0.796916542907978000f, 0.804559113894567000f, + 0.812241489898490000f, 0.819963705323528000f, 0.827725794455034000f, 0.835527791460841000f, + 0.843369730392169000f, 0.851251645184515000f, 0.859173569658532000f, 0.867135537520905000f, + 0.875137582365205000f, 0.883179737672745000f, 0.891262036813419000f, 0.899384513046529000f, + 0.907547199521614000f, 0.915750129279253000f, 0.923993335251873000f, 0.932276850264543000f, + 0.940600707035753000f, 0.948964938178195000f, 0.957369576199527000f, 0.965814653503130000f, + 0.974300202388861000f, 0.982826255053791000f, 0.991392843592940000f, 1.000000000000000000f, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static void build_table_linear_from_gamma(float* outTable, float exponent) { + for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) { + *outTable++ = powf(x, exponent); + } +} + +// Interpolating lookup in a variably sized table. +static float interp_lut(float input, const float* table, int tableSize) { + float index = input * (tableSize - 1); + float diff = index - sk_float_floor2int(index); + return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + + table[(int) sk_float_ceil2int(index)] * diff; +} + +// outTable is always 256 entries, inTable may be larger or smaller. +static void build_table_linear_from_gamma(float* outTable, const float* inTable, + int inTableSize) { + if (256 == inTableSize) { + memcpy(outTable, inTable, sizeof(float) * 256); + return; + } + + for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) { + *outTable++ = interp_lut(x, inTable, inTableSize); + } +} + +static void build_table_linear_from_gamma(float* outTable, float g, float a, float b, float c, + float d, float e, float f) { + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + for (float x = 0.0f; x <= 1.0f; x += (1.0f/255.0f)) { + if (x >= d) { + *outTable++ = powf(a * x + b, g) + c; + } else { + *outTable++ = e * x + f; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Expand range from 0-1 to 0-255, then convert. +static uint8_t clamp_normalized_float_to_byte(float v) { + // The ordering of the logic is a little strange here in order + // to make sure we convert NaNs to 0. + v = v * 255.0f; + if (v >= 254.5f) { + return 255; + } else if (v >= 0.5f) { + return (uint8_t) (v + 0.5f); + } else { + return 0; + } +} + +static const int kDstGammaTableSize = + SkColorSpaceXform_Base + ::kDstGammaTableSize; + +static void build_table_linear_to_gamma(uint8_t* outTable, float exponent) { + float toGammaExp = 1.0f / exponent; + + for (int i = 0; i < kDstGammaTableSize; i++) { + float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); + outTable[i] = clamp_normalized_float_to_byte(powf(x, toGammaExp)); + } +} + +// Inverse table lookup. Ex: what index corresponds to the input value? This will +// have strange results when the table is non-increasing. But any sane gamma +// function will be increasing. +static float inverse_interp_lut(float input, const float* table, int tableSize) { + if (input <= table[0]) { + return table[0]; + } else if (input >= table[tableSize - 1]) { + return 1.0f; + } + + for (int i = 1; i < tableSize; i++) { + if (table[i] >= input) { + // We are guaranteed that input is greater than table[i - 1]. + float diff = input - table[i - 1]; + float distance = table[i] - table[i - 1]; + float index = (i - 1) + diff / distance; + return index / (tableSize - 1); + } + } + + // Should be unreachable, since we'll return before the loop if input is + // larger than the last entry. + SkASSERT(false); + return 0.0f; +} + +static void build_table_linear_to_gamma(uint8_t* outTable, const float* inTable, + int inTableSize) { + for (int i = 0; i < kDstGammaTableSize; i++) { + float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); + float y = inverse_interp_lut(x, inTable, inTableSize); + outTable[i] = clamp_normalized_float_to_byte(y); + } +} + +static float inverse_parametric(float x, float g, float a, float b, float c, float d, float e, + float f) { + // We need to take the inverse of the following piecewise function. + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + + // Assume that the gamma function is continuous, or this won't make much sense anyway. + // Plug in |d| to the first equation to calculate the new piecewise interval. + // Then simply use the inverse of the original functions. + float interval = e * d + f; + if (x < interval) { + // X = (Y - F) / E + if (0.0f == e) { + // The gamma curve for this segment is constant, so the inverse is undefined. + // Since this is the lower segment, guess zero. + return 0.0f; + } + + return (x - f) / e; + } + + // X = ((Y - C)^(1 / G) - B) / A + if (0.0f == a || 0.0f == g) { + // The gamma curve for this segment is constant, so the inverse is undefined. + // Since this is the upper segment, guess one. + return 1.0f; + } + + return (powf(x - c, 1.0f / g) - b) / a; +} + +static void build_table_linear_to_gamma(uint8_t* outTable, float g, float a, + float b, float c, float d, float e, float f) { + for (int i = 0; i < kDstGammaTableSize; i++) { + float x = ((float) i) * (1.0f / ((float) (kDstGammaTableSize - 1))); + float y = inverse_parametric(x, g, a, b, c, d, e, f); + outTable[i] = clamp_normalized_float_to_byte(y); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct GammaFns { + const T* fSRGBTable; + const T* f2Dot2Table; + void (*fBuildFromValue)(T*, float); + void (*fBuildFromTable)(T*, const float*, int); + void (*fBuildFromParam)(T*, float, float, float, float, float, float, float); +}; + +static const GammaFns kToLinear { + sk_linear_from_srgb, + sk_linear_from_2dot2, + &build_table_linear_from_gamma, + &build_table_linear_from_gamma, + &build_table_linear_from_gamma, +}; + +static const GammaFns kFromLinear { + nullptr, + nullptr, + &build_table_linear_to_gamma, + &build_table_linear_to_gamma, + &build_table_linear_to_gamma, +}; + +// Build tables to transform src gamma to linear. +template +static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize, + SkColorSpace* space, const GammaFns& fns, bool gammasAreMatching) +{ + switch (as_CSB(space)->gammaNamed()) { + case kSRGB_SkGammaNamed: + outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable; + break; + case k2Dot2Curve_SkGammaNamed: + outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.f2Dot2Table; + break; + case kLinear_SkGammaNamed: + outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr; + break; + default: { + const SkGammas* gammas = as_CSB(space)->gammas(); + SkASSERT(gammas); + + auto build_table = [=](int i) { + if (gammas->isNamed(i)) { + switch (gammas->data(i).fNamed) { + case kSRGB_SkGammaNamed: + (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], 2.4f, + (1.0f / 1.055f), (0.055f / 1.055f), 0.0f, + 0.04045f, (1.0f / 12.92f), 0.0f); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + break; + case k2Dot2Curve_SkGammaNamed: + (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 2.2f); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + break; + case kLinear_SkGammaNamed: + (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], 1.0f); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + break; + default: + SkASSERT(false); + break; + } + } else if (gammas->isValue(i)) { + (*fns.fBuildFromValue)(&gammaTableStorage[i * gammaTableSize], + gammas->data(i).fValue); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + } else if (gammas->isTable(i)) { + (*fns.fBuildFromTable)(&gammaTableStorage[i * gammaTableSize], gammas->table(i), + gammas->data(i).fTable.fSize); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + } else { + SkASSERT(gammas->isParametric(i)); + const SkGammas::Params& params = gammas->params(i); + (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG, + params.fA, params.fB, params.fC, params.fD, params.fE, + params.fF); + outGammaTables[i] = &gammaTableStorage[i * gammaTableSize]; + } + }; + + if (gammasAreMatching) { + build_table(0); + outGammaTables[1] = outGammaTables[0]; + outGammaTables[2] = outGammaTables[0]; + } else { + build_table(0); + build_table(1); + build_table(2); + } + + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline bool is_almost_identity(const SkMatrix44& srcToDst) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + float expected = (i == j) ? 1.0f : 0.0f; + if (!color_space_almost_equal(srcToDst.getFloat(i,j), expected)) { + return false; + } + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr SkColorSpaceXform::New(SkColorSpace* srcSpace, + SkColorSpace* dstSpace) { + if (!srcSpace || !dstSpace) { + // Invalid input + return nullptr; + } + + ColorSpaceMatch csm = kNone_ColorSpaceMatch; + SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); + if (SkColorSpace::Equals(srcSpace, dstSpace)) { + srcToDst.setIdentity(); + csm = kFull_ColorSpaceMatch; + } else { + srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), as_CSB(srcSpace)->toXYZD50()); + + if (is_almost_identity(srcToDst)) { + srcToDst.setIdentity(); + csm = kGamut_ColorSpaceMatch; + } + } + + switch (csm) { + case kNone_ColorSpaceMatch: + switch (as_CSB(dstSpace)->gammaNamed()) { + case kSRGB_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + case k2Dot2Curve_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + case kLinear_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + default: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + } + case kGamut_ColorSpaceMatch: + switch (as_CSB(dstSpace)->gammaNamed()) { + case kSRGB_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + case k2Dot2Curve_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + case kLinear_SkGammaNamed: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + default: + if (srcSpace->gammaIsLinear()) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } else { + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + } + case kFull_ColorSpaceMatch: + switch (as_CSB(dstSpace)->gammaNamed()) { + case kSRGB_SkGammaNamed: + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + case k2Dot2Curve_SkGammaNamed: + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + case kLinear_SkGammaNamed: + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + default: + return std::unique_ptr(new SkColorSpaceXform_Base + + (srcSpace, srcToDst, dstSpace)); + } + default: + SkASSERT(false); + return nullptr; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static float byte_to_float(uint8_t byte) { + return ((float) byte) * (1.0f / 255.0f); +} + +// Clamp to the 0-1 range. +static float clamp_normalized_float(float v) { + if (v > 1.0f) { + return 1.0f; + } else if ((v < 0.0f) || sk_float_isnan(v)) { + return 0.0f; + } else { + return v; + } +} + +static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) { + // Call the src components x, y, and z. + uint8_t maxX = colorLUT->fGridPoints[0] - 1; + uint8_t maxY = colorLUT->fGridPoints[1] - 1; + uint8_t maxZ = colorLUT->fGridPoints[2] - 1; + + // An approximate index into each of the three dimensions of the table. + float x = src[0] * maxX; + float y = src[1] * maxY; + float z = src[2] * maxZ; + + // This gives us the low index for our interpolation. + int ix = sk_float_floor2int(x); + int iy = sk_float_floor2int(y); + int iz = sk_float_floor2int(z); + + // Make sure the low index is not also the max index. + ix = (maxX == ix) ? ix - 1 : ix; + iy = (maxY == iy) ? iy - 1 : iy; + iz = (maxZ == iz) ? iz - 1 : iz; + + // Weighting factors for the interpolation. + float diffX = x - ix; + float diffY = y - iy; + float diffZ = z - iz; + + // Constants to help us navigate the 3D table. + // Ex: Assume x = a, y = b, z = c. + // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c]. + const int n000 = 0; + const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2]; + const int n010 = 3 * colorLUT->fGridPoints[2]; + const int n011 = n001 + n010; + const int n100 = 3; + const int n101 = n100 + n001; + const int n110 = n100 + n010; + const int n111 = n110 + n001; + + // Base ptr into the table. + const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]); + + // The code below performs a tetrahedral interpolation for each of the three + // dst components. Once the tetrahedron containing the interpolation point is + // identified, the interpolation is a weighted sum of grid values at the + // vertices of the tetrahedron. The claim is that tetrahedral interpolation + // provides a more accurate color conversion. + // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/ + // + // I have one test image, and visually I can't tell the difference between + // tetrahedral and trilinear interpolation. In terms of computation, the + // tetrahedral code requires more branches but less computation. The + // SampleICC library provides an option for the client to choose either + // tetrahedral or trilinear. + for (int i = 0; i < 3; i++) { + if (diffZ < diffY) { + if (diffZ < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + + diffY * (ptr[n010] - ptr[n000]) + + diffX * (ptr[n111] - ptr[n110])); + } else if (diffY < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + + diffY * (ptr[n011] - ptr[n001]) + + diffX * (ptr[n001] - ptr[n000])); + } else { + dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + + diffY * (ptr[n010] - ptr[n000]) + + diffX * (ptr[n011] - ptr[n010])); + } + } else { + if (diffZ < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + + diffY * (ptr[n111] - ptr[n101]) + + diffX * (ptr[n001] - ptr[n000])); + } else if (diffY < diffX) { + dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + + diffY * (ptr[n111] - ptr[n101]) + + diffX * (ptr[n101] - ptr[n100])); + } else { + dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + + diffY * (ptr[n110] - ptr[n100]) + + diffX * (ptr[n111] - ptr[n110])); + } + } + + // Increment the table ptr in order to handle the next component. + // Note that this is the how table is designed: all of nXXX + // variables are multiples of 3 because there are 3 output + // components. + ptr++; + } +} + +static void handle_color_lut(uint32_t* dst, const uint32_t* src, int len, + SkColorLookUpTable* colorLUT) { + while (len-- > 0) { + uint8_t r = (*src >> 0) & 0xFF, + g = (*src >> 8) & 0xFF, + b = (*src >> 16) & 0xFF; + + float in[3]; + float out[3]; + in[0] = byte_to_float(r); + in[1] = byte_to_float(g); + in[2] = byte_to_float(b); + interp_3d_clut(out, in, colorLUT); + + r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); + g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); + b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); + *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); + + src++; + dst++; + } +} + +static inline void load_matrix(const float matrix[16], + Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) { + rXgXbX = Sk4f::Load(matrix + 0); + rYgYbY = Sk4f::Load(matrix + 4); + rZgZbZ = Sk4f::Load(matrix + 8); + rTgTbT = Sk4f::Load(matrix + 12); +} + +enum Order { + kRGBA_Order, + kBGRA_Order, +}; + +static inline void set_rb_shifts(Order kOrder, int* kRShift, int* kBShift) { + if (kRGBA_Order == kOrder) { + *kRShift = 0; + *kBShift = 16; + } else { + *kRShift = 16; + *kBShift = 0; + } +} + +template +static inline void load_rgb_from_tables(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = { srcTables[0][(src[0] >> kRShift) & 0xFF], + srcTables[0][(src[1] >> kRShift) & 0xFF], + srcTables[0][(src[2] >> kRShift) & 0xFF], + srcTables[0][(src[3] >> kRShift) & 0xFF], }; + g = { srcTables[1][(src[0] >> kGShift) & 0xFF], + srcTables[1][(src[1] >> kGShift) & 0xFF], + srcTables[1][(src[2] >> kGShift) & 0xFF], + srcTables[1][(src[3] >> kGShift) & 0xFF], }; + b = { srcTables[2][(src[0] >> kBShift) & 0xFF], + srcTables[2][(src[1] >> kBShift) & 0xFF], + srcTables[2][(src[2] >> kBShift) & 0xFF], + srcTables[2][(src[3] >> kBShift) & 0xFF], }; + a = 0.0f; // Don't let the compiler complain that |a| is uninitialized. +} + +template +static inline void load_rgba_from_tables(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = { srcTables[0][(src[0] >> kRShift) & 0xFF], + srcTables[0][(src[1] >> kRShift) & 0xFF], + srcTables[0][(src[2] >> kRShift) & 0xFF], + srcTables[0][(src[3] >> kRShift) & 0xFF], }; + g = { srcTables[1][(src[0] >> kGShift) & 0xFF], + srcTables[1][(src[1] >> kGShift) & 0xFF], + srcTables[1][(src[2] >> kGShift) & 0xFF], + srcTables[1][(src[3] >> kGShift) & 0xFF], }; + b = { srcTables[2][(src[0] >> kBShift) & 0xFF], + srcTables[2][(src[1] >> kBShift) & 0xFF], + srcTables[2][(src[2] >> kBShift) & 0xFF], + srcTables[2][(src[3] >> kBShift) & 0xFF], }; + a = (1.0f / 255.0f) * SkNx_cast(Sk4u::Load(src) >> 24); +} + +template +static inline void load_rgb_linear(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kRShift) & 0xFF); + g = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kGShift) & 0xFF); + b = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kBShift) & 0xFF); + a = 0.0f; // Don't let the compiler complain that |a| is uninitialized. +} + +template +static inline void load_rgba_linear(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kRShift) & 0xFF); + g = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kGShift) & 0xFF); + b = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> kBShift) & 0xFF); + a = (1.0f / 255.0f) * SkNx_cast((Sk4u::Load(src) >> 24)); +} + +template +static inline void load_rgb_from_tables_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]); + g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]); + b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]); +} + +template +static inline void load_rgba_from_tables_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = Sk4f(srcTables[0][(*src >> kRShift) & 0xFF]); + g = Sk4f(srcTables[1][(*src >> kGShift) & 0xFF]); + b = Sk4f(srcTables[2][(*src >> kBShift) & 0xFF]); + a = (1.0f / 255.0f) * Sk4f(*src >> 24); +} + +template +static inline void load_rgb_linear_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f&, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF)); + g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF)); + b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF)); +} + +template +static inline void load_rgba_linear_1(const uint32_t* src, + Sk4f& r, Sk4f& g, Sk4f& b, Sk4f& a, + const float* const srcTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + r = Sk4f((1.0f / 255.0f) * ((*src >> kRShift) & 0xFF)); + g = Sk4f((1.0f / 255.0f) * ((*src >> kGShift) & 0xFF)); + b = Sk4f((1.0f / 255.0f) * ((*src >> kBShift) & 0xFF)); + a = Sk4f((1.0f / 255.0f) * ((*src >> 24))); +} + +static inline void transform_gamut(const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a, + const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da) { + dr = rXgXbX[0]*r + rYgYbY[0]*g + rZgZbZ[0]*b; + dg = rXgXbX[1]*r + rYgYbY[1]*g + rZgZbZ[1]*b; + db = rXgXbX[2]*r + rYgYbY[2]*g + rZgZbZ[2]*b; + da = a; +} + +static inline void transform_gamut_1(const Sk4f& r, const Sk4f& g, const Sk4f& b, + const Sk4f& rXgXbX, const Sk4f& rYgYbY, const Sk4f& rZgZbZ, + Sk4f& rgba) { + rgba = rXgXbX*r + rYgYbY*g + rZgZbZ*b; +} + +static inline void translate_gamut(const Sk4f& rTgTbT, Sk4f& dr, Sk4f& dg, Sk4f& db) { + dr = dr + rTgTbT[0]; + dg = dg + rTgTbT[1]; + db = db + rTgTbT[2]; +} + +static inline void translate_gamut_1(const Sk4f& rTgTbT, Sk4f& rgba) { + rgba = rgba + rTgTbT; +} + +static inline void premultiply(Sk4f& dr, Sk4f& dg, Sk4f& db, const Sk4f& da) { + dr = da * dr; + dg = da * dg; + db = da * db; +} + +static inline void premultiply_1(const Sk4f& a, Sk4f& rgba) { + rgba = a * rgba; +} + +template +static inline void store_srgb(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + dr = sk_linear_to_srgb_needs_trunc(dr); + dg = sk_linear_to_srgb_needs_trunc(dg); + db = sk_linear_to_srgb_needs_trunc(db); + + dr = sk_clamp_0_255(dr); + dg = sk_clamp_0_255(dg); + db = sk_clamp_0_255(db); + + Sk4i da = Sk4i::Load(src) & 0xFF000000; + + Sk4i rgba = (SkNx_cast(dr) << kRShift) + | (SkNx_cast(dg) << kGShift) + | (SkNx_cast(db) << kBShift) + | (da ); + rgba.store(dst); +} + +template +static inline void store_srgb_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { + rgba = sk_clamp_0_255(sk_linear_to_srgb_needs_trunc(rgba)); + + uint32_t tmp; + SkNx_cast(SkNx_cast(rgba)).store(&tmp); + tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF); + if (kBGRA_Order == kOrder) { + tmp = SkSwizzle_RB(tmp); + } + + *(uint32_t*)dst = tmp; +} + +static inline Sk4f linear_to_2dot2(const Sk4f& x) { + // x^(29/64) is a very good approximation of the true value, x^(1/2.2). + auto x2 = x.rsqrt(), // x^(-1/2) + x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32) + x64 = x32.rsqrt(); // x^(+1/64) + + // 29 = 32 - 2 - 1 + return 255.0f * x2.invert() * x32 * x64.invert(); +} + +template +static inline void store_2dot2(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + dr = linear_to_2dot2(dr); + dg = linear_to_2dot2(dg); + db = linear_to_2dot2(db); + + dr = sk_clamp_0_255(dr); + dg = sk_clamp_0_255(dg); + db = sk_clamp_0_255(db); + + Sk4i da = Sk4i::Load(src) & 0xFF000000; + + Sk4i rgba = (Sk4f_round(dr) << kRShift) + | (Sk4f_round(dg) << kGShift) + | (Sk4f_round(db) << kBShift) + | (da ); + rgba.store(dst); +} + +template +static inline void store_2dot2_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { + rgba = sk_clamp_0_255(linear_to_2dot2(rgba)); + + uint32_t tmp; + SkNx_cast(Sk4f_round(rgba)).store(&tmp); + tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF); + if (kBGRA_Order == kOrder) { + tmp = SkSwizzle_RB(tmp); + } + + *(uint32_t*)dst = tmp; +} + +template +static inline void store_linear(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + dr = sk_clamp_0_255(255.0f * dr); + dg = sk_clamp_0_255(255.0f * dg); + db = sk_clamp_0_255(255.0f * db); + + Sk4i da = Sk4i::Load(src) & 0xFF000000; + + Sk4i rgba = (Sk4f_round(dr) << kRShift) + | (Sk4f_round(dg) << kGShift) + | (Sk4f_round(db) << kBShift) + | (da ); + rgba.store(dst); +} + +template +static inline void store_linear_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { + rgba = sk_clamp_0_255(255.0f * rgba); + + uint32_t tmp; + SkNx_cast(Sk4f_round(rgba)).store(&tmp); + tmp = (*src & 0xFF000000) | (tmp & 0x00FFFFFF); + if (kBGRA_Order == kOrder) { + tmp = SkSwizzle_RB(tmp); + } + + *(uint32_t*)dst = tmp; +} + +template +static inline void store_f16(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, + const uint8_t* const[3]) { + Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr), + SkFloatToHalf_finite_ftz(dg), + SkFloatToHalf_finite_ftz(db), + SkFloatToHalf_finite_ftz(da)); +} + +template +static inline void store_f16_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f& a, + const uint8_t* const[3]) { + rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); + SkFloatToHalf_finite_ftz(rgba).store((uint64_t*) dst); +} + +template +static inline void store_f32(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, + const uint8_t* const[3]) { + Sk4f_store4(dst, dr, dg, db, da); +} + +template +static inline void store_f32_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f& a, + const uint8_t* const[3]) { + rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); + rgba.store((float*) dst); +} + +template +static inline void store_f16_opaque(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const[3]) { + Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr), + SkFloatToHalf_finite_ftz(dg), + SkFloatToHalf_finite_ftz(db), + SK_Half1); +} + +template +static inline void store_f16_1_opaque(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const[3]) { + uint64_t tmp; + SkFloatToHalf_finite_ftz(rgba).store(&tmp); + tmp |= static_cast(SK_Half1) << 48; + *((uint64_t*) dst) = tmp; +} + +template +static inline void store_generic(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, + const uint8_t* const dstTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + dr = Sk4f::Min(Sk4f::Max(1023.0f * dr, 0.0f), 1023.0f); + dg = Sk4f::Min(Sk4f::Max(1023.0f * dg, 0.0f), 1023.0f); + db = Sk4f::Min(Sk4f::Max(1023.0f * db, 0.0f), 1023.0f); + + Sk4i ir = Sk4f_round(dr); + Sk4i ig = Sk4f_round(dg); + Sk4i ib = Sk4f_round(db); + + Sk4i da = Sk4i::Load(src) & 0xFF000000; + + uint32_t* dst32 = (uint32_t*) dst; + dst32[0] = dstTables[0][ir[0]] << kRShift + | dstTables[1][ig[0]] << kGShift + | dstTables[2][ib[0]] << kBShift + | da[0]; + dst32[1] = dstTables[0][ir[1]] << kRShift + | dstTables[1][ig[1]] << kGShift + | dstTables[2][ib[1]] << kBShift + | da[1]; + dst32[2] = dstTables[0][ir[2]] << kRShift + | dstTables[1][ig[2]] << kGShift + | dstTables[2][ib[2]] << kBShift + | da[2]; + dst32[3] = dstTables[0][ir[3]] << kRShift + | dstTables[1][ig[3]] << kGShift + | dstTables[2][ib[3]] << kBShift + | da[3]; +} + +template +static inline void store_generic_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f&, + const uint8_t* const dstTables[3]) { + int kRShift, kGShift = 8, kBShift; + set_rb_shifts(kOrder, &kRShift, &kBShift); + rgba = Sk4f::Min(Sk4f::Max(1023.0f * rgba, 0.0f), 1023.0f); + + Sk4i indices = Sk4f_round(rgba); + + *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift + | dstTables[1][indices[1]] << kGShift + | dstTables[2][indices[2]] << kBShift + | (*src & 0xFF000000); +} + +typedef decltype(load_rgb_from_tables )* LoadFn; +typedef decltype(load_rgb_from_tables_1)* Load1Fn; +typedef decltype(store_generic )* StoreFn; +typedef decltype(store_generic_1 )* Store1Fn; + +template +static inline void do_color_xform(void* dst, const uint32_t* src, int len, + const float* const srcTables[3], const float matrix[16], + const uint8_t* const dstTables[3], LoadFn load, Load1Fn load_1, + StoreFn store, Store1Fn store_1, size_t sizeOfDstPixel) { + Sk4f rXgXbX, rYgYbY, rZgZbZ, rTgTbT; + load_matrix(matrix, rXgXbX, rYgYbY, rZgZbZ, rTgTbT); + + if (len >= 4) { + // Naively this would be a loop of load-transform-store, but we found it faster to + // move the N+1th load ahead of the Nth store. We don't bother doing this for N<4. + Sk4f r, g, b, a; + load(src, r, g, b, a, srcTables); + src += 4; + len -= 4; + + Sk4f dr, dg, db, da; + while (len >= 4) { + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); + translate_gamut(rTgTbT, dr, dg, db); + } else { + dr = r; + dg = g; + db = b; + da = a; + } + + if (kPremul_SkAlphaType == kAlphaType) { + premultiply(dr, dg, db, da); + } + + load(src, r, g, b, a, srcTables); + + store(dst, src - 4, dr, dg, db, da, dstTables); + dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); + src += 4; + len -= 4; + } + + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut(r, g, b, a, rXgXbX, rYgYbY, rZgZbZ, dr, dg, db, da); + translate_gamut(rTgTbT, dr, dg, db); + } else { + dr = r; + dg = g; + db = b; + da = a; + } + + if (kPremul_SkAlphaType == kAlphaType) { + premultiply(dr, dg, db, da); + } + + store(dst, src - 4, dr, dg, db, da, dstTables); + dst = SkTAddOffset(dst, 4 * sizeOfDstPixel); + } + + while (len > 0) { + Sk4f r, g, b, a; + load_1(src, r, g, b, a, srcTables); + + Sk4f rgba; + if (kNone_ColorSpaceMatch == kCSM) { + transform_gamut_1(r, g, b, rXgXbX, rYgYbY, rZgZbZ, rgba); + translate_gamut_1(rTgTbT, rgba); + } else { + rgba = Sk4f(r[0], g[0], b[0], a[0]); + } + + if (kPremul_SkAlphaType == kAlphaType) { + premultiply_1(a, rgba); + } + + store_1(dst, src, rgba, a, dstTables); + + src += 1; + len -= 1; + dst = SkTAddOffset(dst, sizeOfDstPixel); + } +} + +enum SrcFormat { + kRGBA_8888_Linear_SrcFormat, + kRGBA_8888_Table_SrcFormat, + kBGRA_8888_Linear_SrcFormat, + kBGRA_8888_Table_SrcFormat, +}; + +enum DstFormat { + kRGBA_8888_Linear_DstFormat, + kRGBA_8888_SRGB_DstFormat, + kRGBA_8888_2Dot2_DstFormat, + kRGBA_8888_Table_DstFormat, + kBGRA_8888_Linear_DstFormat, + kBGRA_8888_SRGB_DstFormat, + kBGRA_8888_2Dot2_DstFormat, + kBGRA_8888_Table_DstFormat, + kF16_Linear_DstFormat, + kF32_Linear_DstFormat, +}; + +template +static void color_xform_RGBA(void* dst, const uint32_t* src, int len, + const float* const srcTables[3], const float matrix[16], + const uint8_t* const dstTables[3]) { + LoadFn load; + Load1Fn load_1; + static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) || + (kF16_Linear_DstFormat == kDst) || + (kF32_Linear_DstFormat == kDst); + switch (kSrc) { + case kRGBA_8888_Linear_SrcFormat: + if (loadAlpha) { + load = load_rgba_linear; + load_1 = load_rgba_linear_1; + } else { + load = load_rgb_linear; + load_1 = load_rgb_linear_1; + } + break; + case kRGBA_8888_Table_SrcFormat: + if (loadAlpha) { + load = load_rgba_from_tables; + load_1 = load_rgba_from_tables_1; + } else { + load = load_rgb_from_tables; + load_1 = load_rgb_from_tables_1; + } + break; + case kBGRA_8888_Linear_SrcFormat: + if (loadAlpha) { + load = load_rgba_linear; + load_1 = load_rgba_linear_1; + } else { + load = load_rgb_linear; + load_1 = load_rgb_linear_1; + } + break; + case kBGRA_8888_Table_SrcFormat: + if (loadAlpha) { + load = load_rgba_from_tables; + load_1 = load_rgba_from_tables_1; + } else { + load = load_rgb_from_tables; + load_1 = load_rgb_from_tables_1; + } + break; + } + + StoreFn store; + Store1Fn store_1; + size_t sizeOfDstPixel; + switch (kDst) { + case kRGBA_8888_Linear_DstFormat: + store = store_linear; + store_1 = store_linear_1; + sizeOfDstPixel = 4; + break; + case kRGBA_8888_SRGB_DstFormat: + store = store_srgb; + store_1 = store_srgb_1; + sizeOfDstPixel = 4; + break; + case kRGBA_8888_2Dot2_DstFormat: + store = store_2dot2; + store_1 = store_2dot2_1; + sizeOfDstPixel = 4; + break; + case kRGBA_8888_Table_DstFormat: + store = store_generic; + store_1 = store_generic_1; + sizeOfDstPixel = 4; + break; + case kBGRA_8888_Linear_DstFormat: + store = store_linear; + store_1 = store_linear_1; + sizeOfDstPixel = 4; + break; + case kBGRA_8888_SRGB_DstFormat: + store = store_srgb; + store_1 = store_srgb_1; + sizeOfDstPixel = 4; + break; + case kBGRA_8888_2Dot2_DstFormat: + store = store_2dot2; + store_1 = store_2dot2_1; + sizeOfDstPixel = 4; + break; + case kBGRA_8888_Table_DstFormat: + store = store_generic; + store_1 = store_generic_1; + sizeOfDstPixel = 4; + break; + case kF16_Linear_DstFormat: + store = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_opaque : + store_f16; + store_1 = (kOpaque_SkAlphaType == kAlphaType) ? store_f16_1_opaque : + store_f16_1; + sizeOfDstPixel = 8; + break; + case kF32_Linear_DstFormat: + store = store_f32; + store_1 = store_f32_1; + sizeOfDstPixel = 16; + break; + } + + do_color_xform + (dst, src, len, srcTables, matrix, dstTables, load, load_1, store, store_1, + sizeOfDstPixel); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline int num_tables(SkColorSpace* space) { + switch (as_CSB(space)->gammaNamed()) { + case kSRGB_SkGammaNamed: + case k2Dot2Curve_SkGammaNamed: + case kLinear_SkGammaNamed: + return 0; + default: { + const SkGammas* gammas = as_CSB(space)->gammas(); + SkASSERT(gammas); + + bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) && + (gammas->data(0) == gammas->data(1)) && + (gammas->type(0) == gammas->type(2)) && + (gammas->data(0) == gammas->data(2)); + + // It's likely that each component will have the same gamma. In this case, + // we only need to build one table. + return gammasAreMatching ? 1 : 3; + } + } +} + +template +SkColorSpaceXform_Base +::SkColorSpaceXform_Base(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, SkColorSpace* dstSpace) + : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) +{ + srcToDst.asColMajorf(fSrcToDst); + + const int numSrcTables = num_tables(srcSpace); + const int numDstTables = num_tables(dstSpace); + const size_t srcTableBytes = numSrcTables * 256 * sizeof(float); + const size_t dstTableBytes = numDstTables * kDstGammaTableSize * sizeof(uint8_t); + fStorage.reset(srcTableBytes + dstTableBytes); + float* srcStorage = (float*) fStorage.get(); + uint8_t* dstStorage = SkTAddOffset(fStorage.get(), srcTableBytes); + + const bool srcGammasAreMatching = (1 >= numSrcTables); + const bool dstGammasAreMatching = (1 >= numDstTables); + build_gamma_tables(fSrcGammaTables, srcStorage, 256, srcSpace, kToLinear, srcGammasAreMatching); + build_gamma_tables(fDstGammaTables, dstStorage, kDstGammaTableSize, dstSpace, kFromLinear, + dstGammasAreMatching); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +template +static inline void apply_set_alpha(void* dst, const uint32_t* src, int len, SkAlphaType alphaType, + const float* const srcTables[3], const float matrix[16], + const uint8_t* const dstTables[3]) { + switch (alphaType) { + case kOpaque_SkAlphaType: + return color_xform_RGBA + (dst, src, len, srcTables, matrix, dstTables); + case kPremul_SkAlphaType: + return color_xform_RGBA + (dst, src, len, srcTables, matrix, dstTables); + case kUnpremul_SkAlphaType: + return color_xform_RGBA + (dst, src, len, srcTables, matrix, dstTables); + default: + SkASSERT(false); + return; + } +} + +template +static inline void apply_set_src(void* dst, const uint32_t* src, int len, SkAlphaType alphaType, + const float* const srcTables[3], const float matrix[16], + const uint8_t* const dstTables[3], + SkColorSpaceXform::ColorFormat srcColorFormat) { + switch (srcColorFormat) { + case SkColorSpaceXform::kRGBA_8888_ColorFormat: + switch (kSrc) { + case kLinear_SrcGamma: + return apply_set_alpha + (dst, src, len, alphaType, nullptr, matrix, dstTables); + case kTable_SrcGamma: + return apply_set_alpha + (dst, src, len, alphaType, srcTables, matrix, dstTables); + } + case SkColorSpaceXform::kBGRA_8888_ColorFormat: + switch (kSrc) { + case kLinear_SrcGamma: + return apply_set_alpha + (dst, src, len, alphaType, nullptr, matrix, dstTables); + case kTable_SrcGamma: + return apply_set_alpha + (dst, src, len, alphaType, srcTables, matrix, dstTables); + } + default: + SkASSERT(false); + } +} + +template +void SkColorSpaceXform_Base +::apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, + ColorFormat srcColorFormat, SkAlphaType alphaType) +const +{ + if (kFull_ColorSpaceMatch == kCSM) { + switch (alphaType) { + case kPremul_SkAlphaType: + // We can't skip the xform since we need to perform a premultiply in the + // linear space. + break; + default: + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: + return (void) memcpy(dst, src, len * sizeof(uint32_t)); + case kBGRA_8888_ColorFormat: + return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); + case kRGBA_F16_ColorFormat: + case kRGBA_F32_ColorFormat: + // There's still work to do to xform to linear floats. + break; + default: + SkASSERT(false); + return; + } + } + } + +#if defined(GOOGLE3) + // Stack frame size is limited in GOOGLE3. + SkAutoSMalloc<256 * sizeof(uint32_t)> storage; +#else + SkAutoSMalloc<1024 * sizeof(uint32_t)> storage; +#endif + if (fColorLUT) { + size_t storageBytes = len * sizeof(uint32_t); + storage.reset(storageBytes); + handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); + src = (const uint32_t*) storage.get(); + } + + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: + switch (kDst) { + case kLinear_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case kSRGB_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case k2Dot2_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case kTable_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables, + srcColorFormat); + } + case kBGRA_8888_ColorFormat: + switch (kDst) { + case kLinear_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case kSRGB_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case k2Dot2_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + case kTable_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables, + srcColorFormat); + } + case kRGBA_F16_ColorFormat: + switch (kDst) { + case kLinear_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + default: + SkASSERT(false); + return; + } + case kRGBA_F32_ColorFormat: + switch (kDst) { + case kLinear_DstGamma: + return apply_set_src + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr, + srcColorFormat); + default: + SkASSERT(false); + return; + } + default: + SkASSERT(false); + return; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr SlowIdentityXform(SkColorSpace* space) { + return std::unique_ptr(new SkColorSpaceXform_Base + + (space, SkMatrix::I(), space)); +} diff --git a/gfx/skia/skia/src/core/SkColorSpaceXform.h b/gfx/skia/skia/src/core/SkColorSpaceXform.h new file mode 100644 index 000000000000..bb99071fe033 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpaceXform.h @@ -0,0 +1,102 @@ +/* + * 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 SkColorSpaceXform_DEFINED +#define SkColorSpaceXform_DEFINED + +#include "SkColorSpace.h" +#include "SkColorSpace_Base.h" +#include "SkImageInfo.h" + +class SkColorSpaceXform : SkNoncopyable { +public: + + /** + * Create an object to handle color space conversions. + * + * @param srcSpace The encoded color space. + * @param dstSpace The destination color space. + * + */ + static std::unique_ptr New(SkColorSpace* srcSpace, SkColorSpace* dstSpace); + + enum ColorFormat : uint8_t { + kRGBA_8888_ColorFormat, + kBGRA_8888_ColorFormat, + kRGBA_F16_ColorFormat, + kRGBA_F32_ColorFormat, + }; + + /** + * Apply the color conversion to a |src| buffer, storing the output in the |dst| buffer. + * + * @param dst Stored in the format described by |dstColorFormat| + * @param src Stored in the format described by |srcColorFormat| + * @param len Number of pixels in the buffers + * @param dstColorFormat Describes color format of |dst| + * @param srcColorFormat Describes color format of |src| + * Must be kRGBA_8888 or kBGRA_8888 + * @param alphaType Describes alpha properties of the |dst| (and |src|) + * kUnpremul preserves input alpha values + * kPremul performs a premultiplication and also preserves alpha values + * kOpaque optimization hint, |dst| alphas set to 1 + * + */ + virtual void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, + ColorFormat srcColorFormat, SkAlphaType alphaType) const = 0; + + virtual ~SkColorSpaceXform() {} +}; + +enum SrcGamma { + kLinear_SrcGamma, + kTable_SrcGamma, +}; + +enum DstGamma { + kLinear_DstGamma, + kSRGB_DstGamma, + k2Dot2_DstGamma, + kTable_DstGamma, +}; + +enum ColorSpaceMatch { + kNone_ColorSpaceMatch, + kGamut_ColorSpaceMatch, + kFull_ColorSpaceMatch, +}; + +template +class SkColorSpaceXform_Base : public SkColorSpaceXform { +public: + + void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, + ColorFormat srcColorFormat, SkAlphaType alphaType) const override; + + static constexpr int kDstGammaTableSize = 1024; + +private: + SkColorSpaceXform_Base(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, + SkColorSpace* dstSpace); + + sk_sp fColorLUT; + + // Contain pointers into storage or pointers into precomputed tables. + const float* fSrcGammaTables[3]; + const uint8_t* fDstGammaTables[3]; + SkAutoMalloc fStorage; + + float fSrcToDst[16]; + + friend class SkColorSpaceXform; + friend std::unique_ptr SlowIdentityXform(SkColorSpace* space); +}; + +// For testing. Bypasses opts for when src and dst color spaces are equal. +std::unique_ptr SlowIdentityXform(SkColorSpace* space); + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpace_Base.h b/gfx/skia/skia/src/core/SkColorSpace_Base.h new file mode 100644 index 000000000000..07fa3832530d --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_Base.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 SkColorSpace_Base_DEFINED +#define SkColorSpace_Base_DEFINED + +#include "SkColorSpace.h" +#include "SkData.h" +#include "SkOnce.h" +#include "SkTemplates.h" + +enum SkGammaNamed : uint8_t { + kLinear_SkGammaNamed, + kSRGB_SkGammaNamed, + k2Dot2Curve_SkGammaNamed, + kNonStandard_SkGammaNamed, +}; + +struct SkGammas : SkRefCnt { + + // There are four possible representations for gamma curves. kNone_Type is used + // as a placeholder until the struct is initialized. It is not a valid value. + enum class Type : uint8_t { + kNone_Type, + kNamed_Type, + kValue_Type, + kTable_Type, + kParam_Type, + }; + + // Contains information for a gamma table. + struct Table { + size_t fOffset; + int fSize; + + const float* table(const SkGammas* base) const { + return SkTAddOffset(base, sizeof(SkGammas) + fOffset); + } + }; + + // Contains the parameters for a parametric curve. + struct Params { + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + float fG; + float fA; + float fB; + float fC; + float fD; + float fE; + float fF; + }; + + // Contains the actual gamma curve information. Should be interpreted + // based on the type of the gamma curve. + union Data { + Data() + : fTable{ 0, 0 } + {} + + inline bool operator==(const Data& that) const { + return this->fTable.fOffset == that.fTable.fOffset && + this->fTable.fSize == that.fTable.fSize; + } + + SkGammaNamed fNamed; + float fValue; + Table fTable; + size_t fParamOffset; + + const Params& params(const SkGammas* base) const { + return *SkTAddOffset(base, sizeof(SkGammas) + fParamOffset); + } + }; + + bool isNamed(int i) const { + return Type::kNamed_Type == this->type(i); + } + + bool isValue(int i) const { + return Type::kValue_Type == this->type(i); + } + + bool isTable(int i) const { + return Type::kTable_Type == this->type(i); + } + + bool isParametric(int i) const { + return Type::kParam_Type == this->type(i); + } + + const Data& data(int i) const { + switch (i) { + case 0: + return fRedData; + case 1: + return fGreenData; + case 2: + return fBlueData; + default: + SkASSERT(false); + return fRedData; + } + } + + const float* table(int i) const { + SkASSERT(isTable(i)); + return this->data(i).fTable.table(this); + } + + const Params& params(int i) const { + SkASSERT(isParametric(i)); + return this->data(i).params(this); + } + + Type type(int i) const { + switch (i) { + case 0: + return fRedType; + case 1: + return fGreenType; + case 2: + return fBlueType; + default: + SkASSERT(false); + return fRedType; + } + } + + SkGammas() + : fRedType(Type::kNone_Type) + , fGreenType(Type::kNone_Type) + , fBlueType(Type::kNone_Type) + {} + + // These fields should only be modified when initializing the struct. + Data fRedData; + Data fGreenData; + Data fBlueData; + Type fRedType; + Type fGreenType; + Type fBlueType; + + // Objects of this type are sometimes created in a custom fashion using + // sk_malloc_throw and therefore must be sk_freed. We overload new to + // also call sk_malloc_throw so that memory can be unconditionally released + // using sk_free in an overloaded delete. Overloading regular new means we + // must also overload placement new. + void* operator new(size_t size) { return sk_malloc_throw(size); } + void* operator new(size_t, void* p) { return p; } + void operator delete(void* p) { sk_free(p); } +}; + +struct SkColorLookUpTable : public SkRefCnt { + static constexpr uint8_t kOutputChannels = 3; + + uint8_t fInputChannels; + uint8_t fGridPoints[3]; + + const float* table() const { + return SkTAddOffset(this, sizeof(SkColorLookUpTable)); + } + + SkColorLookUpTable(uint8_t inputChannels, uint8_t gridPoints[3]) + : fInputChannels(inputChannels) + { + SkASSERT(3 == inputChannels); + memcpy(fGridPoints, gridPoints, 3 * sizeof(uint8_t)); + } + + // Objects of this type are created in a custom fashion using sk_malloc_throw + // and therefore must be sk_freed. + void* operator new(size_t size) = delete; + void* operator new(size_t, void* p) { return p; } + void operator delete(void* p) { sk_free(p); } +}; + +class SkColorSpace_Base : public SkColorSpace { +public: + + static sk_sp NewRGB(const float gammas[3], const SkMatrix44& toXYZD50); + + SkGammaNamed gammaNamed() const { return fGammaNamed; } + const SkGammas* gammas() const { return fGammas.get(); } + + const SkColorLookUpTable* colorLUT() const { return fColorLUT.get(); } + + const SkMatrix44& toXYZD50() const { return fToXYZD50; } + const SkMatrix44& fromXYZD50() const; + +private: + + /** + * FIXME (msarett): + * Hiding this function until we can determine if we need it. Known issues include: + * Only writes 3x3 matrices + * Only writes float gammas + * Rejected by some parsers because the "profile description" is empty + */ + sk_sp writeToICC() const; + + static sk_sp NewRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50); + + SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZ); + + SkColorSpace_Base(sk_sp colorLUT, SkGammaNamed gammaNamed, + sk_sp gammas, const SkMatrix44& toXYZ, sk_sp profileData); + + sk_sp fColorLUT; + const SkGammaNamed fGammaNamed; + sk_sp fGammas; + sk_sp fProfileData; + + const SkMatrix44 fToXYZD50; + mutable SkMatrix44 fFromXYZD50; + mutable SkOnce fFromXYZOnce; + + friend class SkColorSpace; + friend class ColorSpaceXformTest; + friend class ColorSpaceTest; + typedef SkColorSpace INHERITED; +}; + +static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) { + return static_cast(colorSpace); +} + +static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) { + return static_cast(colorSpace); +} + +static inline SkColorSpace_Base* as_CSB(const sk_sp& colorSpace) { + return static_cast(colorSpace.get()); +} + +#endif diff --git a/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp b/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp new file mode 100644 index 000000000000..4ef9f2b0a831 --- /dev/null +++ b/gfx/skia/skia/src/core/SkColorSpace_ICC.cpp @@ -0,0 +1,1338 @@ +/* + * 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 "SkColorSpace.h" +#include "SkColorSpace_Base.h" +#include "SkColorSpacePriv.h" +#include "SkEndian.h" +#include "SkFixed.h" +#include "SkTemplates.h" + +#define return_if_false(pred, msg) \ + do { \ + if (!(pred)) { \ + SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ + return false; \ + } \ + } while (0) + +#define return_null(msg) \ + do { \ + SkColorSpacePrintf("Invalid ICC Profile: %s.\n", (msg)); \ + return nullptr; \ + } while (0) + +static uint16_t read_big_endian_u16(const uint8_t* ptr) { + return ptr[0] << 8 | ptr[1]; +} + +static uint32_t read_big_endian_u32(const uint8_t* ptr) { + return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; +} + +static int32_t read_big_endian_i32(const uint8_t* ptr) { + return (int32_t) read_big_endian_u32(ptr); +} + +// This is equal to the header size according to the ICC specification (128) +// plus the size of the tag count (4). We include the tag count since we +// always require it to be present anyway. +static constexpr size_t kICCHeaderSize = 132; + +// Contains a signature (4), offset (4), and size (4). +static constexpr size_t kICCTagTableEntrySize = 12; + +static constexpr uint32_t kRGB_ColorSpace = SkSetFourByteTag('R', 'G', 'B', ' '); +static constexpr uint32_t kDisplay_Profile = SkSetFourByteTag('m', 'n', 't', 'r'); +static constexpr uint32_t kInput_Profile = SkSetFourByteTag('s', 'c', 'n', 'r'); +static constexpr uint32_t kOutput_Profile = SkSetFourByteTag('p', 'r', 't', 'r'); +static constexpr uint32_t kColorSpace_Profile = SkSetFourByteTag('s', 'p', 'a', 'c'); +static constexpr uint32_t kXYZ_PCSSpace = SkSetFourByteTag('X', 'Y', 'Z', ' '); +static constexpr uint32_t kACSP_Signature = SkSetFourByteTag('a', 'c', 's', 'p'); + +struct ICCProfileHeader { + uint32_t fSize; + + // No reason to care about the preferred color management module (ex: Adobe, Apple, etc.). + // We're always going to use this one. + uint32_t fCMMType_ignored; + + uint32_t fVersion; + uint32_t fProfileClass; + uint32_t fInputColorSpace; + uint32_t fPCS; + uint32_t fDateTime_ignored[3]; + uint32_t fSignature; + + // Indicates the platform that this profile was created for (ex: Apple, Microsoft). This + // doesn't really matter to us. + uint32_t fPlatformTarget_ignored; + + // Flags can indicate: + // (1) Whether this profile was embedded in a file. This flag is consistently wrong. + // Ex: The profile came from a file but indicates that it did not. + // (2) Whether we are allowed to use the profile independently of the color data. If set, + // this may allow us to use the embedded profile for testing separate from the original + // image. + uint32_t fFlags_ignored; + + // We support many output devices. It doesn't make sense to think about the attributes of + // the device in the context of the image profile. + uint32_t fDeviceManufacturer_ignored; + uint32_t fDeviceModel_ignored; + uint32_t fDeviceAttributes_ignored[2]; + + uint32_t fRenderingIntent; + int32_t fIlluminantXYZ[3]; + + // We don't care who created the profile. + uint32_t fCreator_ignored; + + // This is an MD5 checksum. Could be useful for checking if profiles are equal. + uint32_t fProfileId_ignored[4]; + + // Reserved for future use. + uint32_t fReserved_ignored[7]; + + uint32_t fTagCount; + + void init(const uint8_t* src, size_t len) { + SkASSERT(kICCHeaderSize == sizeof(*this)); + + uint32_t* dst = (uint32_t*) this; + for (uint32_t i = 0; i < kICCHeaderSize / 4; i++, src+=4) { + dst[i] = read_big_endian_u32(src); + } + } + + bool valid() const { + return_if_false(fSize >= kICCHeaderSize, "Size is too small"); + + uint8_t majorVersion = fVersion >> 24; + return_if_false(majorVersion <= 4, "Unsupported version"); + + // These are the four basic classes of profiles that we might expect to see embedded + // in images. Additional classes exist, but they generally are used as a convenient + // way for CMMs to store calculated transforms. + return_if_false(fProfileClass == kDisplay_Profile || + fProfileClass == kInput_Profile || + fProfileClass == kOutput_Profile || + fProfileClass == kColorSpace_Profile, + "Unsupported profile"); + + // TODO (msarett): + // All the profiles we've tested so far use RGB as the input color space. + return_if_false(fInputColorSpace == kRGB_ColorSpace, "Unsupported color space"); + + // TODO (msarett): + // All the profiles we've tested so far use XYZ as the profile connection space. + return_if_false(fPCS == kXYZ_PCSSpace, "Unsupported PCS space"); + + return_if_false(fSignature == kACSP_Signature, "Bad signature"); + + // TODO (msarett): + // Should we treat different rendering intents differently? + // Valid rendering intents include kPerceptual (0), kRelative (1), + // kSaturation (2), and kAbsolute (3). + if (fRenderingIntent > 3) { + // Warn rather than fail here. Occasionally, we see perfectly + // normal profiles with wacky rendering intents. + SkColorSpacePrintf("Warning, bad rendering intent.\n"); + } + + return_if_false(color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[0]), 0.96420f) && + color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[1]), 1.00000f) && + color_space_almost_equal(SkFixedToFloat(fIlluminantXYZ[2]), 0.82491f), + "Illuminant must be D50"); + + return_if_false(fTagCount <= 100, "Too many tags"); + + return true; + } +}; + +template +static bool safe_add(T arg1, T arg2, size_t* result) { + SkASSERT(arg1 >= 0); + SkASSERT(arg2 >= 0); + if (arg1 >= 0 && arg2 <= std::numeric_limits::max() - arg1) { + T sum = arg1 + arg2; + if (sum <= std::numeric_limits::max()) { + *result = static_cast(sum); + return true; + } + } + return false; +} + +static bool safe_mul(uint32_t arg1, uint32_t arg2, uint32_t* result) { + uint64_t product64 = (uint64_t) arg1 * (uint64_t) arg2; + uint32_t product32 = (uint32_t) product64; + if (product32 != product64) { + return false; + } + + *result = product32; + return true; +} + +struct ICCTag { + uint32_t fSignature; + uint32_t fOffset; + uint32_t fLength; + + const uint8_t* init(const uint8_t* src) { + fSignature = read_big_endian_u32(src); + fOffset = read_big_endian_u32(src + 4); + fLength = read_big_endian_u32(src + 8); + return src + 12; + } + + bool valid(size_t len) { + size_t tagEnd; + return_if_false(safe_add(fOffset, fLength, &tagEnd), + "Tag too large, overflows integer addition"); + return_if_false(tagEnd <= len, "Tag too large for ICC profile"); + return true; + } + + const uint8_t* addr(const uint8_t* src) const { + return src + fOffset; + } + + static const ICCTag* Find(const ICCTag tags[], int count, uint32_t signature) { + for (int i = 0; i < count; ++i) { + if (tags[i].fSignature == signature) { + return &tags[i]; + } + } + return nullptr; + } +}; + +static constexpr uint32_t kTAG_rXYZ = SkSetFourByteTag('r', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_gXYZ = SkSetFourByteTag('g', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_bXYZ = SkSetFourByteTag('b', 'X', 'Y', 'Z'); +static constexpr uint32_t kTAG_rTRC = SkSetFourByteTag('r', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_gTRC = SkSetFourByteTag('g', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_bTRC = SkSetFourByteTag('b', 'T', 'R', 'C'); +static constexpr uint32_t kTAG_A2B0 = SkSetFourByteTag('A', '2', 'B', '0'); + +static bool load_xyz(float dst[3], const uint8_t* src, size_t len) { + if (len < 20) { + SkColorSpacePrintf("XYZ tag is too small (%d bytes)", len); + return false; + } + + dst[0] = SkFixedToFloat(read_big_endian_i32(src + 8)); + dst[1] = SkFixedToFloat(read_big_endian_i32(src + 12)); + dst[2] = SkFixedToFloat(read_big_endian_i32(src + 16)); + SkColorSpacePrintf("XYZ %g %g %g\n", dst[0], dst[1], dst[2]); + return true; +} + +static constexpr uint32_t kTAG_CurveType = SkSetFourByteTag('c', 'u', 'r', 'v'); +static constexpr uint32_t kTAG_ParaCurveType = SkSetFourByteTag('p', 'a', 'r', 'a'); + +static SkGammas::Type set_gamma_value(SkGammas::Data* data, float value) { + if (color_space_almost_equal(2.2f, value)) { + data->fNamed = k2Dot2Curve_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + if (color_space_almost_equal(1.0f, value)) { + data->fNamed = kLinear_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + if (color_space_almost_equal(0.0f, value)) { + return SkGammas::Type::kNone_Type; + } + + data->fValue = value; + return SkGammas::Type::kValue_Type; +} + +static float read_big_endian_16_dot_16(const uint8_t buf[4]) { + // It just so happens that SkFixed is also 16.16! + return SkFixedToFloat(read_big_endian_i32(buf)); +} + +/** + * @param outData Set to the appropriate value on success. If we have table or + * parametric gamma, it is the responsibility of the caller to set + * fOffset. + * @param outParams If this is a parametric gamma, this is set to the appropriate + * parameters on success. + * @param outTagBytes Will be set to the length of the tag on success. + * @src Pointer to tag data. + * @len Length of tag data in bytes. + * + * @return kNone_Type on failure, otherwise the type of the gamma tag. + */ +static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* outParams, + size_t* outTagBytes, const uint8_t* src, size_t len) { + if (len < 12) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + + // In the case of consecutive gamma tags, we need to count the number of bytes in the + // tag, so that we can move on to the next tag. + size_t tagBytes; + + uint32_t type = read_big_endian_u32(src); + // Bytes 4-7 are reserved and should be set to zero. + switch (type) { + case kTAG_CurveType: { + uint32_t count = read_big_endian_u32(src + 8); + + // tagBytes = 12 + 2 * count + // We need to do safe addition here to avoid integer overflow. + if (!safe_add(count, count, &tagBytes) || + !safe_add((size_t) 12, tagBytes, &tagBytes)) + { + SkColorSpacePrintf("Invalid gamma count"); + return SkGammas::Type::kNone_Type; + } + + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + *outTagBytes = tagBytes; + + if (0 == count) { + // Some tags require a gamma curve, but the author doesn't actually want + // to transform the data. In this case, it is common to see a curve with + // a count of 0. + outData->fNamed = kLinear_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + const uint16_t* table = (const uint16_t*) (src + 12); + if (1 == count) { + // The table entry is the gamma (with a bias of 256). + float value = (read_big_endian_u16((const uint8_t*) table)) / 256.0f; + SkColorSpacePrintf("gamma %g\n", value); + + return set_gamma_value(outData, value); + } + + // Check for frequently occurring sRGB curves. + // We do this by sampling a few values and see if they match our expectation. + // A more robust solution would be to compare each value in this curve against + // an sRGB curve to see if we remain below an error threshold. At this time, + // we haven't seen any images in the wild that make this kind of + // calculation necessary. We encounter identical gamma curves over and + // over again, but relatively few variations. + if (1024 == count) { + // The magic values were chosen because they match both the very common + // HP sRGB gamma table and the less common Canon sRGB gamma table (which use + // different rounding rules). + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 3366 == read_big_endian_u16((const uint8_t*) &table[257]) && + 14116 == read_big_endian_u16((const uint8_t*) &table[513]) && + 34318 == read_big_endian_u16((const uint8_t*) &table[768]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[1023])) { + outData->fNamed = kSRGB_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + } + + if (26 == count) { + // The magic values were chosen because they match a very common LCMS sRGB + // gamma table. + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 3062 == read_big_endian_u16((const uint8_t*) &table[6]) && + 12824 == read_big_endian_u16((const uint8_t*) &table[12]) && + 31237 == read_big_endian_u16((const uint8_t*) &table[18]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[25])) { + outData->fNamed = kSRGB_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + } + + if (4096 == count) { + // The magic values were chosen because they match Nikon, Epson, and + // LCMS sRGB gamma tables (all of which use different rounding rules). + if (0 == read_big_endian_u16((const uint8_t*) &table[0]) && + 950 == read_big_endian_u16((const uint8_t*) &table[515]) && + 3342 == read_big_endian_u16((const uint8_t*) &table[1025]) && + 14079 == read_big_endian_u16((const uint8_t*) &table[2051]) && + 65535 == read_big_endian_u16((const uint8_t*) &table[4095])) { + outData->fNamed = kSRGB_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + } + + // Otherwise, we will represent gamma with a table. + outData->fTable.fSize = count; + return SkGammas::Type::kTable_Type; + } + case kTAG_ParaCurveType: { + enum ParaCurveType { + kExponential_ParaCurveType = 0, + kGAB_ParaCurveType = 1, + kGABC_ParaCurveType = 2, + kGABDE_ParaCurveType = 3, + kGABCDEF_ParaCurveType = 4, + }; + + // Determine the format of the parametric curve tag. + uint16_t format = read_big_endian_u16(src + 8); + if (format > kGABCDEF_ParaCurveType) { + SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); + return SkGammas::Type::kNone_Type; + } + + if (kExponential_ParaCurveType == format) { + tagBytes = 12 + 4; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + + // Y = X^g + float g = read_big_endian_16_dot_16(src + 12); + + *outTagBytes = tagBytes; + return set_gamma_value(outData, g); + } + + // Here's where the real parametric gammas start. There are many + // permutations of the same equations. + // + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + // + // We will fill in with zeros as necessary to always match the above form. + if (len < 24) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + float g = read_big_endian_16_dot_16(src + 12); + float a = read_big_endian_16_dot_16(src + 16); + float b = read_big_endian_16_dot_16(src + 20); + float c = 0.0f, d = 0.0f, e = 0.0f, f = 0.0f; + switch(format) { + case kGAB_ParaCurveType: + tagBytes = 12 + 12; + + // Y = (aX + b)^g for X >= -b/a + // Y = 0 otherwise + d = -b / a; + break; + case kGABC_ParaCurveType: + tagBytes = 12 + 16; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + + // Y = (aX + b)^g + c for X >= -b/a + // Y = c otherwise + c = read_big_endian_16_dot_16(src + 24); + d = -b / a; + f = c; + break; + case kGABDE_ParaCurveType: + tagBytes = 12 + 20; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + + // Y = (aX + b)^g for X >= d + // Y = eX otherwise + d = read_big_endian_16_dot_16(src + 28); + + // Not a bug! We define |e| to always be the coefficient on X in the + // second equation. The spec calls this |c| in this particular equation. + // We don't follow their convention because then |c| would have a + // different meaning in each of our cases. + e = read_big_endian_16_dot_16(src + 24); + break; + case kGABCDEF_ParaCurveType: + tagBytes = 12 + 28; + if (len < tagBytes) { + SkColorSpacePrintf("gamma tag is too small (%d bytes)", len); + return SkGammas::Type::kNone_Type; + } + + // Y = (aX + b)^g + c for X >= d + // Y = eX + f otherwise + // NOTE: The ICC spec writes "cX" in place of "eX" but I think + // it's a typo. + c = read_big_endian_16_dot_16(src + 24); + d = read_big_endian_16_dot_16(src + 28); + e = read_big_endian_16_dot_16(src + 32); + f = read_big_endian_16_dot_16(src + 36); + break; + default: + SkASSERT(false); + return SkGammas::Type::kNone_Type; + } + + // Recognize and simplify a very common parametric representation of sRGB gamma. + if (color_space_almost_equal(0.9479f, a) && + color_space_almost_equal(0.0521f, b) && + color_space_almost_equal(0.0000f, c) && + color_space_almost_equal(0.0405f, d) && + color_space_almost_equal(0.0774f, e) && + color_space_almost_equal(0.0000f, f) && + color_space_almost_equal(2.4000f, g)) { + outData->fNamed = kSRGB_SkGammaNamed; + return SkGammas::Type::kNamed_Type; + } + + // Fail on invalid gammas. + if (SkScalarIsNaN(d)) { + return SkGammas::Type::kNone_Type; + } + + if (d <= 0.0f) { + // Y = (aX + b)^g + c for always + if (0.0f == a || 0.0f == g) { + SkColorSpacePrintf("A or G is zero, constant gamma function " + "is nonsense"); + return SkGammas::Type::kNone_Type; + } + } + + if (d >= 1.0f) { + // Y = eX + f for always + if (0.0f == e) { + SkColorSpacePrintf("E is zero, constant gamma function is " + "nonsense"); + return SkGammas::Type::kNone_Type; + } + } + + if ((0.0f == a || 0.0f == g) && 0.0f == e) { + SkColorSpacePrintf("A or G, and E are zero, constant gamma function " + "is nonsense"); + return SkGammas::Type::kNone_Type; + } + + *outTagBytes = tagBytes; + + outParams->fG = g; + outParams->fA = a; + outParams->fB = b; + outParams->fC = c; + outParams->fD = d; + outParams->fE = e; + outParams->fF = f; + return SkGammas::Type::kParam_Type; + } + default: + SkColorSpacePrintf("Unsupported gamma tag type %d\n", type); + return SkGammas::Type::kNone_Type; + } +} + +/** + * Returns the additional size in bytes needed to store the gamma tag. + */ +static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data) { + switch (type) { + case SkGammas::Type::kNamed_Type: + case SkGammas::Type::kValue_Type: + return 0; + case SkGammas::Type::kTable_Type: + return sizeof(float) * data.fTable.fSize; + case SkGammas::Type::kParam_Type: + return sizeof(SkGammas::Params); + default: + SkASSERT(false); + return 0; + } +} + +/** + * Sets invalid gamma to the default value. + */ +static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) { + if (SkGammas::Type::kNone_Type == *type) { + *type = SkGammas::Type::kNamed_Type; + + // Guess sRGB in the case of a malformed transfer function. + data->fNamed = kSRGB_SkGammaNamed; + } +} + +/** + * Finish loading the gammas, now that we have allocated memory for the SkGammas struct. + * + * There's nothing to do for the simple cases, but for table gammas we need to actually + * read the table into heap memory. And for parametric gammas, we need to copy over the + * parameter values. + * + * @param memory Pointer to start of the SkGammas memory block + * @param offset Bytes of memory (after the SkGammas struct) that are already in use. + * @param data In-out variable. Will fill in the offset to the table or parameters + * if necessary. + * @param params Parameters for gamma curve. Only initialized/used when we have a + * parametric gamma. + * @param src Pointer to start of the gamma tag. + * + * @return Additional bytes of memory that are being used by this gamma curve. + */ +static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type, + SkGammas::Data* data, const SkGammas::Params& params, + const uint8_t* src) { + void* storage = SkTAddOffset(memory, offset + sizeof(SkGammas)); + + switch (type) { + case SkGammas::Type::kNamed_Type: + case SkGammas::Type::kValue_Type: + // Nothing to do here. + return 0; + case SkGammas::Type::kTable_Type: { + data->fTable.fOffset = offset; + + float* outTable = (float*) storage; + const uint16_t* inTable = (const uint16_t*) (src + 12); + for (int i = 0; i < data->fTable.fSize; i++) { + outTable[i] = (read_big_endian_u16((const uint8_t*) &inTable[i])) / 65535.0f; + } + + return sizeof(float) * data->fTable.fSize; + } + case SkGammas::Type::kParam_Type: + data->fTable.fOffset = offset; + memcpy(storage, ¶ms, sizeof(SkGammas::Params)); + return sizeof(SkGammas::Params); + default: + SkASSERT(false); + return 0; + } +} + +static constexpr uint32_t kTAG_AtoBType = SkSetFourByteTag('m', 'A', 'B', ' '); + +static bool load_color_lut(sk_sp* colorLUT, uint32_t inputChannels, + const uint8_t* src, size_t len) { + // 16 bytes reserved for grid points, 2 for precision, 2 for padding. + // The color LUT data follows after this header. + static constexpr uint32_t kColorLUTHeaderSize = 20; + if (len < kColorLUTHeaderSize) { + SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); + return false; + } + size_t dataLen = len - kColorLUTHeaderSize; + + SkASSERT(3 == inputChannels); + uint8_t gridPoints[3]; + uint32_t numEntries = 1; + for (uint32_t i = 0; i < inputChannels; i++) { + gridPoints[i] = src[i]; + if (0 == src[i]) { + SkColorSpacePrintf("Each input channel must have at least one grid point."); + return false; + } + + if (!safe_mul(numEntries, src[i], &numEntries)) { + SkColorSpacePrintf("Too many entries in Color LUT."); + return false; + } + } + + if (!safe_mul(numEntries, SkColorLookUpTable::kOutputChannels, &numEntries)) { + SkColorSpacePrintf("Too many entries in Color LUT."); + return false; + } + + // Space is provided for a maximum of the 16 input channels. Now we determine the precision + // of the table values. + uint8_t precision = src[16]; + switch (precision) { + case 1: // 8-bit data + case 2: // 16-bit data + break; + default: + SkColorSpacePrintf("Color LUT precision must be 8-bit or 16-bit.\n"); + return false; + } + + uint32_t clutBytes; + if (!safe_mul(numEntries, precision, &clutBytes)) { + SkColorSpacePrintf("Too many entries in Color LUT."); + return false; + } + + if (dataLen < clutBytes) { + SkColorSpacePrintf("Color LUT tag is too small (%d bytes).", len); + return false; + } + + // Movable struct colorLUT has ownership of fTable. + void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries); + *colorLUT = sk_sp(new (memory) SkColorLookUpTable(inputChannels, + gridPoints)); + + float* table = SkTAddOffset(memory, sizeof(SkColorLookUpTable)); + const uint8_t* ptr = src + kColorLUTHeaderSize; + for (uint32_t i = 0; i < numEntries; i++, ptr += precision) { + if (1 == precision) { + table[i] = ((float) ptr[i]) / 255.0f; + } else { + table[i] = ((float) read_big_endian_u16(ptr)) / 65535.0f; + } + } + + return true; +} + +static bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { + if (len < 48) { + SkColorSpacePrintf("Matrix tag is too small (%d bytes).", len); + return false; + } + + // For this matrix to behave like our "to XYZ D50" matrices, it needs to be scaled. + constexpr float scale = 65535.0 / 32768.0; + float array[16]; + array[ 0] = scale * SkFixedToFloat(read_big_endian_i32(src)); + array[ 1] = scale * SkFixedToFloat(read_big_endian_i32(src + 4)); + array[ 2] = scale * SkFixedToFloat(read_big_endian_i32(src + 8)); + array[ 3] = scale * SkFixedToFloat(read_big_endian_i32(src + 36)); // translate R + array[ 4] = scale * SkFixedToFloat(read_big_endian_i32(src + 12)); + array[ 5] = scale * SkFixedToFloat(read_big_endian_i32(src + 16)); + array[ 6] = scale * SkFixedToFloat(read_big_endian_i32(src + 20)); + array[ 7] = scale * SkFixedToFloat(read_big_endian_i32(src + 40)); // translate G + array[ 8] = scale * SkFixedToFloat(read_big_endian_i32(src + 24)); + array[ 9] = scale * SkFixedToFloat(read_big_endian_i32(src + 28)); + array[10] = scale * SkFixedToFloat(read_big_endian_i32(src + 32)); + array[11] = scale * SkFixedToFloat(read_big_endian_i32(src + 44)); // translate B + array[12] = 0.0f; + array[13] = 0.0f; + array[14] = 0.0f; + array[15] = 1.0f; + toXYZ->setRowMajorf(array); + return true; +} + +static inline SkGammaNamed is_named(const sk_sp& gammas) { + if (gammas->isNamed(0) && gammas->isNamed(1) && gammas->isNamed(2) && + gammas->fRedData.fNamed == gammas->fGreenData.fNamed && + gammas->fRedData.fNamed == gammas->fBlueData.fNamed) + { + return gammas->fRedData.fNamed; + } + + return kNonStandard_SkGammaNamed; +} + + +static bool load_a2b0(sk_sp* colorLUT, SkGammaNamed* gammaNamed, + sk_sp* gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { + if (len < 32) { + SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); + return false; + } + + uint32_t type = read_big_endian_u32(src); + if (kTAG_AtoBType != type) { + // FIXME (msarett): Need to support lut8Type and lut16Type. + SkColorSpacePrintf("Unsupported A to B tag type.\n"); + return false; + } + + // Read the number of channels. The four bytes that we skipped are reserved and + // must be zero. + uint8_t inputChannels = src[8]; + uint8_t outputChannels = src[9]; + if (3 != inputChannels || SkColorLookUpTable::kOutputChannels != outputChannels) { + // We only handle (supposedly) RGB inputs and RGB outputs. The numbers of input + // channels and output channels both must be 3. + // TODO (msarett): + // Support different numbers of input channels. Ex: CMYK (4). + SkColorSpacePrintf("Input and output channels must equal 3 in A to B tag.\n"); + return false; + } + + // Read the offsets of each element in the A to B tag. With the exception of A curves and + // B curves (which we do not yet support), we will handle these elements in the order in + // which they should be applied (rather than the order in which they occur in the tag). + // If the offset is non-zero it indicates that the element is present. + uint32_t offsetToACurves = read_big_endian_i32(src + 28); + uint32_t offsetToBCurves = read_big_endian_i32(src + 12); + if ((0 != offsetToACurves) || (0 != offsetToBCurves)) { + // FIXME (msarett): Handle A and B curves. + // Note that the A curve is technically required in order to have a color LUT. + // However, all the A curves I have seen so far have are just placeholders that + // don't actually transform the data. + SkColorSpacePrintf("Ignoring A and/or B curve. Output may be wrong.\n"); + } + + uint32_t offsetToColorLUT = read_big_endian_i32(src + 24); + if (0 != offsetToColorLUT && offsetToColorLUT < len) { + if (!load_color_lut(colorLUT, inputChannels, src + offsetToColorLUT, + len - offsetToColorLUT)) { + SkColorSpacePrintf("Failed to read color LUT from A to B tag.\n"); + } + } + + uint32_t offsetToMCurves = read_big_endian_i32(src + 20); + if (0 != offsetToMCurves && offsetToMCurves < len) { + const uint8_t* rTagPtr = src + offsetToMCurves; + size_t tagLen = len - offsetToMCurves; + + SkGammas::Data rData; + SkGammas::Params rParams; + + // On an invalid first gamma, tagBytes remains set as zero. This causes the two + // subsequent to be treated as identical (which is what we want). + size_t tagBytes = 0; + SkGammas::Type rType = parse_gamma(&rData, &rParams, &tagBytes, rTagPtr, tagLen); + handle_invalid_gamma(&rType, &rData); + size_t alignedTagBytes = SkAlign4(tagBytes); + + if ((3 * alignedTagBytes <= tagLen) && + !memcmp(rTagPtr, rTagPtr + 1 * alignedTagBytes, tagBytes) && + !memcmp(rTagPtr, rTagPtr + 2 * alignedTagBytes, tagBytes)) + { + if (SkGammas::Type::kNamed_Type == rType) { + *gammaNamed = rData.fNamed; + } else { + size_t allocSize = sizeof(SkGammas); + return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize), + "SkGammas struct is too large to allocate"); + void* memory = sk_malloc_throw(allocSize); + *gammas = sk_sp(new (memory) SkGammas()); + load_gammas(memory, 0, rType, &rData, rParams, rTagPtr); + + (*gammas)->fRedType = rType; + (*gammas)->fGreenType = rType; + (*gammas)->fBlueType = rType; + + (*gammas)->fRedData = rData; + (*gammas)->fGreenData = rData; + (*gammas)->fBlueData = rData; + } + } else { + const uint8_t* gTagPtr = rTagPtr + alignedTagBytes; + tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; + SkGammas::Data gData; + SkGammas::Params gParams; + tagBytes = 0; + SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTagPtr, + tagLen); + handle_invalid_gamma(&gType, &gData); + + alignedTagBytes = SkAlign4(tagBytes); + const uint8_t* bTagPtr = gTagPtr + alignedTagBytes; + tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0; + SkGammas::Data bData; + SkGammas::Params bParams; + SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTagPtr, + tagLen); + handle_invalid_gamma(&bType, &bData); + + size_t allocSize = sizeof(SkGammas); + return_if_false(safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize), + "SkGammas struct is too large to allocate"); + return_if_false(safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize), + "SkGammas struct is too large to allocate"); + return_if_false(safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize), + "SkGammas struct is too large to allocate"); + void* memory = sk_malloc_throw(allocSize); + *gammas = sk_sp(new (memory) SkGammas()); + + uint32_t offset = 0; + (*gammas)->fRedType = rType; + offset += load_gammas(memory, offset, rType, &rData, rParams, rTagPtr); + + (*gammas)->fGreenType = gType; + offset += load_gammas(memory, offset, gType, &gData, gParams, gTagPtr); + + (*gammas)->fBlueType = bType; + load_gammas(memory, offset, bType, &bData, bParams, bTagPtr); + + (*gammas)->fRedData = rData; + (*gammas)->fGreenData = gData; + (*gammas)->fBlueData = bData; + } + } else { + // Guess sRGB if the chunk is missing a transfer function. + *gammaNamed = kSRGB_SkGammaNamed; + } + + if (kNonStandard_SkGammaNamed == *gammaNamed) { + *gammaNamed = is_named(*gammas); + if (kNonStandard_SkGammaNamed != *gammaNamed) { + // No need to keep the gammas struct, the enum is enough. + *gammas = nullptr; + } + } + + uint32_t offsetToMatrix = read_big_endian_i32(src + 16); + if (0 != offsetToMatrix && offsetToMatrix < len) { + if (!load_matrix(toXYZ, src + offsetToMatrix, len - offsetToMatrix)) { + SkColorSpacePrintf("Failed to read matrix from A to B tag.\n"); + toXYZ->setIdentity(); + } + } + + return true; +} + +static bool tag_equals(const ICCTag* a, const ICCTag* b, const uint8_t* base) { + if (!a || !b) { + return a == b; + } + + if (a->fLength != b->fLength) { + return false; + } + + if (a->fOffset == b->fOffset) { + return true; + } + + return !memcmp(a->addr(base), b->addr(base), a->fLength); +} + +sk_sp SkColorSpace::NewICC(const void* input, size_t len) { + if (!input || len < kICCHeaderSize) { + return_null("Data is null or not large enough to contain an ICC profile"); + } + + // Create our own copy of the input. + void* memory = sk_malloc_throw(len); + memcpy(memory, input, len); + sk_sp data = SkData::MakeFromMalloc(memory, len); + const uint8_t* base = data->bytes(); + const uint8_t* ptr = base; + + // Read the ICC profile header and check to make sure that it is valid. + ICCProfileHeader header; + header.init(ptr, len); + if (!header.valid()) { + return nullptr; + } + + // Adjust ptr and len before reading the tags. + if (len < header.fSize) { + SkColorSpacePrintf("ICC profile might be truncated.\n"); + } else if (len > header.fSize) { + SkColorSpacePrintf("Caller provided extra data beyond the end of the ICC profile.\n"); + len = header.fSize; + } + ptr += kICCHeaderSize; + len -= kICCHeaderSize; + + // Parse tag headers. + uint32_t tagCount = header.fTagCount; + SkColorSpacePrintf("ICC profile contains %d tags.\n", tagCount); + if (len < kICCTagTableEntrySize * tagCount) { + return_null("Not enough input data to read tag table entries"); + } + + SkAutoTArray tags(tagCount); + for (uint32_t i = 0; i < tagCount; i++) { + ptr = tags[i].init(ptr); + SkColorSpacePrintf("[%d] %c%c%c%c %d %d\n", i, (tags[i].fSignature >> 24) & 0xFF, + (tags[i].fSignature >> 16) & 0xFF, (tags[i].fSignature >> 8) & 0xFF, + (tags[i].fSignature >> 0) & 0xFF, tags[i].fOffset, tags[i].fLength); + + if (!tags[i].valid(kICCHeaderSize + len)) { + return_null("Tag is too large to fit in ICC profile"); + } + } + + switch (header.fInputColorSpace) { + case kRGB_ColorSpace: { + // Recognize the rXYZ, gXYZ, and bXYZ tags. + const ICCTag* r = ICCTag::Find(tags.get(), tagCount, kTAG_rXYZ); + const ICCTag* g = ICCTag::Find(tags.get(), tagCount, kTAG_gXYZ); + const ICCTag* b = ICCTag::Find(tags.get(), tagCount, kTAG_bXYZ); + if (r && g && b) { + float toXYZ[9]; + if (!load_xyz(&toXYZ[0], r->addr(base), r->fLength) || + !load_xyz(&toXYZ[3], g->addr(base), g->fLength) || + !load_xyz(&toXYZ[6], b->addr(base), b->fLength)) + { + return_null("Need valid rgb tags for XYZ space"); + } + SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); + mat.set3x3(toXYZ[0], toXYZ[1], toXYZ[2], + toXYZ[3], toXYZ[4], toXYZ[5], + toXYZ[6], toXYZ[7], toXYZ[8]); + + r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); + g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); + b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); + + // If some, but not all, of the gamma tags are missing, assume that all + // gammas are meant to be the same. This behavior is an arbitrary guess, + // but it simplifies the code below. + if ((!r || !g || !b) && (r || g || b)) { + if (!r) { + r = g ? g : b; + } + + if (!g) { + g = r ? r : b; + } + + if (!b) { + b = r ? r : g; + } + } + + SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; + sk_sp gammas = nullptr; + size_t tagBytes; + if (r && g && b) { + if (tag_equals(r, g, base) && tag_equals(g, b, base)) { + SkGammas::Data data; + SkGammas::Params params; + SkGammas::Type type = + parse_gamma(&data, ¶ms, &tagBytes, r->addr(base), r->fLength); + handle_invalid_gamma(&type, &data); + + if (SkGammas::Type::kNamed_Type == type) { + gammaNamed = data.fNamed; + } else { + size_t allocSize = sizeof(SkGammas); + if (!safe_add(allocSize, gamma_alloc_size(type, data), &allocSize)) { + return_null("SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + gammas = sk_sp(new (memory) SkGammas()); + load_gammas(memory, 0, type, &data, params, r->addr(base)); + + gammas->fRedType = type; + gammas->fGreenType = type; + gammas->fBlueType = type; + + gammas->fRedData = data; + gammas->fGreenData = data; + gammas->fBlueData = data; + } + } else { + SkGammas::Data rData; + SkGammas::Params rParams; + SkGammas::Type rType = + parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength); + handle_invalid_gamma(&rType, &rData); + + SkGammas::Data gData; + SkGammas::Params gParams; + SkGammas::Type gType = + parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength); + handle_invalid_gamma(&gType, &gData); + + SkGammas::Data bData; + SkGammas::Params bParams; + SkGammas::Type bType = + parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength); + handle_invalid_gamma(&bType, &bData); + + size_t allocSize = sizeof(SkGammas); + if (!safe_add(allocSize, gamma_alloc_size(rType, rData), &allocSize) || + !safe_add(allocSize, gamma_alloc_size(gType, gData), &allocSize) || + !safe_add(allocSize, gamma_alloc_size(bType, bData), &allocSize)) + { + return_null("SkGammas struct is too large to allocate"); + } + void* memory = sk_malloc_throw(allocSize); + gammas = sk_sp(new (memory) SkGammas()); + + uint32_t offset = 0; + gammas->fRedType = rType; + offset += load_gammas(memory, offset, rType, &rData, rParams, + r->addr(base)); + + gammas->fGreenType = gType; + offset += load_gammas(memory, offset, gType, &gData, gParams, + g->addr(base)); + + gammas->fBlueType = bType; + load_gammas(memory, offset, bType, &bData, bParams, b->addr(base)); + + gammas->fRedData = rData; + gammas->fGreenData = gData; + gammas->fBlueData = bData; + } + } else { + // Guess sRGB if the profile is missing transfer functions. + gammaNamed = kSRGB_SkGammaNamed; + } + + if (kNonStandard_SkGammaNamed == gammaNamed) { + // It's possible that we'll initially detect non-matching gammas, only for + // them to evaluate to the same named gamma curve. + gammaNamed = is_named(gammas); + if (kNonStandard_SkGammaNamed == gammaNamed) { + return sk_sp(new SkColorSpace_Base(nullptr, gammaNamed, + std::move(gammas), mat, + std::move(data))); + } + } + + return SkColorSpace_Base::NewRGB(gammaNamed, mat); + } + + // Recognize color profile specified by A2B0 tag. + const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); + if (a2b0) { + SkGammaNamed gammaNamed = kNonStandard_SkGammaNamed; + sk_sp gammas = nullptr; + sk_sp colorLUT = nullptr; + SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); + if (!load_a2b0(&colorLUT, &gammaNamed, &gammas, &toXYZ, a2b0->addr(base), + a2b0->fLength)) { + return_null("Failed to parse A2B0 tag"); + } + + if (colorLUT || kNonStandard_SkGammaNamed == gammaNamed) { + return sk_sp(new SkColorSpace_Base(std::move(colorLUT), + gammaNamed, std::move(gammas), + toXYZ, std::move(data))); + } + + return SkColorSpace_Base::NewRGB(gammaNamed, toXYZ); + } + } + default: + break; + } + + return_null("ICC profile contains unsupported colorspace"); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// We will write a profile with the minimum nine required tags. +static constexpr uint32_t kICCNumEntries = 9; + +static constexpr uint32_t kTAG_desc = SkSetFourByteTag('d', 'e', 's', 'c'); +static constexpr uint32_t kTAG_desc_Bytes = 12; +static constexpr uint32_t kTAG_desc_Offset = kICCHeaderSize + kICCNumEntries*kICCTagTableEntrySize; + +static constexpr uint32_t kTAG_XYZ_Bytes = 20; +static constexpr uint32_t kTAG_rXYZ_Offset = kTAG_desc_Offset + kTAG_desc_Bytes; +static constexpr uint32_t kTAG_gXYZ_Offset = kTAG_rXYZ_Offset + kTAG_XYZ_Bytes; +static constexpr uint32_t kTAG_bXYZ_Offset = kTAG_gXYZ_Offset + kTAG_XYZ_Bytes; + +static constexpr uint32_t kTAG_TRC_Bytes = 14; +static constexpr uint32_t kTAG_rTRC_Offset = kTAG_bXYZ_Offset + kTAG_XYZ_Bytes; +static constexpr uint32_t kTAG_gTRC_Offset = kTAG_rTRC_Offset + SkAlign4(kTAG_TRC_Bytes); +static constexpr uint32_t kTAG_bTRC_Offset = kTAG_gTRC_Offset + SkAlign4(kTAG_TRC_Bytes); + +static constexpr uint32_t kTAG_wtpt = SkSetFourByteTag('w', 't', 'p', 't'); +static constexpr uint32_t kTAG_wtpt_Offset = kTAG_bTRC_Offset + SkAlign4(kTAG_TRC_Bytes); + +static constexpr uint32_t kTAG_cprt = SkSetFourByteTag('c', 'p', 'r', 't'); +static constexpr uint32_t kTAG_cprt_Bytes = 12; +static constexpr uint32_t kTAG_cprt_Offset = kTAG_wtpt_Offset + kTAG_XYZ_Bytes; + +static constexpr uint32_t kICCProfileSize = kTAG_cprt_Offset + kTAG_cprt_Bytes; + +static constexpr uint32_t gICCHeader[kICCHeaderSize / 4] { + SkEndian_SwapBE32(kICCProfileSize), // Size of the profile + 0, // Preferred CMM type (ignored) + SkEndian_SwapBE32(0x02100000), // Version 2.1 + SkEndian_SwapBE32(kDisplay_Profile), // Display device profile + SkEndian_SwapBE32(kRGB_ColorSpace), // RGB input color space + SkEndian_SwapBE32(kXYZ_PCSSpace), // XYZ profile connection space + 0, 0, 0, // Date and time (ignored) + SkEndian_SwapBE32(kACSP_Signature), // Profile signature + 0, // Platform target (ignored) + 0x00000000, // Flags: not embedded, can be used independently + 0, // Device manufacturer (ignored) + 0, // Device model (ignored) + 0, 0, // Device attributes (ignored) + SkEndian_SwapBE32(1), // Relative colorimetric rendering intent + SkEndian_SwapBE32(0x0000f6d6), // D50 standard illuminant (X) + SkEndian_SwapBE32(0x00010000), // D50 standard illuminant (Y) + SkEndian_SwapBE32(0x0000d32d), // D50 standard illuminant (Z) + 0, // Profile creator (ignored) + 0, 0, 0, 0, // Profile id checksum (ignored) + 0, 0, 0, 0, 0, 0, 0, // Reserved (ignored) + SkEndian_SwapBE32(kICCNumEntries), // Number of tags +}; + +static constexpr uint32_t gICCTagTable[3 * kICCNumEntries] { + // Profile description + SkEndian_SwapBE32(kTAG_desc), + SkEndian_SwapBE32(kTAG_desc_Offset), + SkEndian_SwapBE32(kTAG_desc_Bytes), + + // rXYZ + SkEndian_SwapBE32(kTAG_rXYZ), + SkEndian_SwapBE32(kTAG_rXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // gXYZ + SkEndian_SwapBE32(kTAG_gXYZ), + SkEndian_SwapBE32(kTAG_gXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // bXYZ + SkEndian_SwapBE32(kTAG_bXYZ), + SkEndian_SwapBE32(kTAG_bXYZ_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // rTRC + SkEndian_SwapBE32(kTAG_rTRC), + SkEndian_SwapBE32(kTAG_rTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // gTRC + SkEndian_SwapBE32(kTAG_gTRC), + SkEndian_SwapBE32(kTAG_gTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // bTRC + SkEndian_SwapBE32(kTAG_bTRC), + SkEndian_SwapBE32(kTAG_bTRC_Offset), + SkEndian_SwapBE32(kTAG_TRC_Bytes), + + // White point + SkEndian_SwapBE32(kTAG_wtpt), + SkEndian_SwapBE32(kTAG_wtpt_Offset), + SkEndian_SwapBE32(kTAG_XYZ_Bytes), + + // Copyright + SkEndian_SwapBE32(kTAG_cprt), + SkEndian_SwapBE32(kTAG_cprt_Offset), + SkEndian_SwapBE32(kTAG_cprt_Bytes), +}; + +static constexpr uint32_t kTAG_TextType = SkSetFourByteTag('m', 'l', 'u', 'c'); +static constexpr uint32_t gEmptyTextTag[3] { + SkEndian_SwapBE32(kTAG_TextType), // Type signature + 0, // Reserved + 0, // Zero records +}; + +static void write_xyz_tag(uint32_t* ptr, const SkMatrix44& toXYZ, int col) { + ptr[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); + ptr[1] = 0; + ptr[2] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(0, col))); + ptr[3] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(1, col))); + ptr[4] = SkEndian_SwapBE32(SkFloatToFixed(toXYZ.getFloat(2, col))); +} + +static void write_trc_tag(uint32_t* ptr, float value) { + ptr[0] = SkEndian_SwapBE32(kTAG_CurveType); + ptr[1] = 0; + + // Gamma will be specified with a single value. + ptr[2] = SkEndian_SwapBE32(1); + + // Convert gamma to 16-bit fixed point. + uint16_t* ptr16 = (uint16_t*) (ptr + 3); + ptr16[0] = SkEndian_SwapBE16((uint16_t) (value * 256.0f)); + + // Pad tag with zero. + ptr16[1] = 0; +} + +sk_sp SkColorSpace_Base::writeToICC() const { + // Return if this object was created from a profile, or if we have already serialized + // the profile. + if (fProfileData) { + return fProfileData; + } + + // The client may create an SkColorSpace using an SkMatrix44, but currently we only + // support writing profiles with 3x3 matrices. + // TODO (msarett): Fix this! + if (0.0f != fToXYZD50.getFloat(3, 0) || 0.0f != fToXYZD50.getFloat(3, 1) || + 0.0f != fToXYZD50.getFloat(3, 2) || 0.0f != fToXYZD50.getFloat(0, 3) || + 0.0f != fToXYZD50.getFloat(1, 3) || 0.0f != fToXYZD50.getFloat(2, 3)) + { + return nullptr; + } + + SkAutoMalloc profile(kICCProfileSize); + uint8_t* ptr = (uint8_t*) profile.get(); + + // Write profile header + memcpy(ptr, gICCHeader, sizeof(gICCHeader)); + ptr += sizeof(gICCHeader); + + // Write tag table + memcpy(ptr, gICCTagTable, sizeof(gICCTagTable)); + ptr += sizeof(gICCTagTable); + + // Write profile description tag + memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); + ptr += sizeof(gEmptyTextTag); + + // Write XYZ tags + write_xyz_tag((uint32_t*) ptr, fToXYZD50, 0); + ptr += kTAG_XYZ_Bytes; + write_xyz_tag((uint32_t*) ptr, fToXYZD50, 1); + ptr += kTAG_XYZ_Bytes; + write_xyz_tag((uint32_t*) ptr, fToXYZD50, 2); + ptr += kTAG_XYZ_Bytes; + + // Write TRC tags + SkGammaNamed gammaNamed = this->gammaNamed(); + if (kNonStandard_SkGammaNamed == gammaNamed) { + // FIXME (msarett): + // Write the correct gamma representation rather than 2.2f. + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + } else { + switch (gammaNamed) { + case kSRGB_SkGammaNamed: + // FIXME (msarett): + // kSRGB cannot be represented by a value. Here we fall through to 2.2f, + // which is a close guess. To be more accurate, we need to represent sRGB + // gamma with a parametric curve. + case k2Dot2Curve_SkGammaNamed: + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 2.2f); + ptr += SkAlign4(kTAG_TRC_Bytes); + break; + case kLinear_SkGammaNamed: + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + write_trc_tag((uint32_t*) ptr, 1.0f); + ptr += SkAlign4(kTAG_TRC_Bytes); + break; + default: + SkASSERT(false); + break; + } + } + + // Write white point tag + uint32_t* ptr32 = (uint32_t*) ptr; + ptr32[0] = SkEndian_SwapBE32(kXYZ_PCSSpace); + ptr32[1] = 0; + // TODO (msarett): These values correspond to the D65 white point. This may not always be + // correct. + ptr32[2] = SkEndian_SwapBE32(0x0000f351); + ptr32[3] = SkEndian_SwapBE32(0x00010000); + ptr32[4] = SkEndian_SwapBE32(0x000116cc); + ptr += kTAG_XYZ_Bytes; + + // Write copyright tag + memcpy(ptr, gEmptyTextTag, sizeof(gEmptyTextTag)); + + // TODO (msarett): Should we try to hold onto the data so we can return immediately if + // the client calls again? + return SkData::MakeFromMalloc(profile.release(), kICCProfileSize); +} diff --git a/gfx/skia/skia/src/core/SkColorTable.cpp b/gfx/skia/skia/src/core/SkColorTable.cpp index d7253e1d8c12..296b31c369e4 100644 --- a/gfx/skia/skia/src/core/SkColorTable.cpp +++ b/gfx/skia/skia/src/core/SkColorTable.cpp @@ -41,19 +41,19 @@ SkColorTable::SkColorTable(SkPMColor* colors, int count, AllocatedWithMalloc) SkColorTable::~SkColorTable() { sk_free(fColors); - // f16BitCache frees itself + sk_free(f16BitCache); } #include "SkColorPriv.h" const uint16_t* SkColorTable::read16BitCache() const { - return f16BitCache.get([&]{ - auto cache = new uint16_t[fCount]; + f16BitCacheOnce([this] { + f16BitCache = (uint16_t*)sk_malloc_throw(fCount * sizeof(uint16_t)); for (int i = 0; i < fCount; i++) { - cache[i] = SkPixel32ToPixel16_ToU16(fColors[i]); + f16BitCache[i] = SkPixel32ToPixel16_ToU16(fColors[i]); } - return cache; }); + return f16BitCache; } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkComposeShader.cpp b/gfx/skia/skia/src/core/SkComposeShader.cpp index 46b772494467..7696e1632e73 100644 --- a/gfx/skia/skia/src/core/SkComposeShader.cpp +++ b/gfx/skia/skia/src/core/SkComposeShader.cpp @@ -183,10 +183,7 @@ void SkComposeShader::ComposeShaderContext::shadeSpan(int x, int y, SkPMColor re ///////////////////////////////////////////////////////////////////// -const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* context, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality fq) const { +sk_sp SkComposeShader::asFragmentProcessor(const AsFPArgs& args) const { // Fragment processor will only support SkXfermode::Mode modes currently. SkXfermode::Mode mode; if (!(SkXfermode::AsMode(fMode, &mode))) { @@ -195,27 +192,26 @@ const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* conte switch (mode) { case SkXfermode::kClear_Mode: - return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK, - GrConstColorProcessor::kIgnore_InputMode); + return GrConstColorProcessor::Make(GrColor_TRANSPARENT_BLACK, + GrConstColorProcessor::kIgnore_InputMode); break; case SkXfermode::kSrc_Mode: - return fShaderB->asFragmentProcessor(context, viewM, localMatrix, fq); + return fShaderB->asFragmentProcessor(args); break; case SkXfermode::kDst_Mode: - return fShaderA->asFragmentProcessor(context, viewM, localMatrix, fq); + return fShaderA->asFragmentProcessor(args); break; default: - SkAutoTUnref fpA(fShaderA->asFragmentProcessor(context, - viewM, localMatrix, fq)); - if (!fpA.get()) { + sk_sp fpA(fShaderA->asFragmentProcessor(args)); + if (!fpA) { return nullptr; } - SkAutoTUnref fpB(fShaderB->asFragmentProcessor(context, - viewM, localMatrix, fq)); - if (!fpB.get()) { + sk_sp fpB(fShaderB->asFragmentProcessor(args)); + if (!fpB) { return nullptr; } - return GrXfermodeFragmentProcessor::CreateFromTwoProcessors(fpB, fpA, mode); + return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(fpB), + std::move(fpA), mode); } } #endif diff --git a/gfx/skia/skia/src/core/SkComposeShader.h b/gfx/skia/skia/src/core/SkComposeShader.h index 4d561faac76b..d1b095ec3fd0 100644 --- a/gfx/skia/skia/src/core/SkComposeShader.h +++ b/gfx/skia/skia/src/core/SkComposeShader.h @@ -35,10 +35,7 @@ public: {} #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality) const override; + sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif class ComposeShaderContext : public SkShader::Context { diff --git a/gfx/skia/skia/src/core/SkConfig8888.cpp b/gfx/skia/skia/src/core/SkConfig8888.cpp index 5bac16a2728e..7c3f0214e34a 100644 --- a/gfx/skia/skia/src/core/SkConfig8888.cpp +++ b/gfx/skia/skia/src/core/SkConfig8888.cpp @@ -167,6 +167,64 @@ static void copy_32_to_g8(void* dst, size_t dstRB, const void* src, size_t srcRB } } +static bool extract_alpha(void* dst, size_t dstRB, const void* src, size_t srcRB, + const SkImageInfo& srcInfo, SkColorTable* ctable) { + uint8_t* SK_RESTRICT dst8 = (uint8_t*)dst; + + const int w = srcInfo.width(); + const int h = srcInfo.height(); + if (srcInfo.isOpaque()) { + // src is opaque, so just fill alpha with 0xFF + for (int y = 0; y < h; ++y) { + memset(dst8, 0xFF, w); + dst8 += dstRB; + } + return true; + } + switch (srcInfo.colorType()) { + case kN32_SkColorType: { + const SkPMColor* SK_RESTRICT src32 = (const SkPMColor*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkGetPackedA32(src32[x]); + } + dst8 += dstRB; + src32 = (const SkPMColor*)((const char*)src32 + srcRB); + } + break; + } + case kARGB_4444_SkColorType: { + const SkPMColor16* SK_RESTRICT src16 = (const SkPMColor16*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkPacked4444ToA32(src16[x]); + } + dst8 += dstRB; + src16 = (const SkPMColor16*)((const char*)src16 + srcRB); + } + break; + } + case kIndex_8_SkColorType: { + if (nullptr == ctable) { + return false; + } + const SkPMColor* SK_RESTRICT table = ctable->readColors(); + const uint8_t* SK_RESTRICT src8 = (const uint8_t*)src; + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + dst8[x] = SkGetPackedA32(table[src8[x]]); + } + dst8 += dstRB; + src8 += srcRB; + } + break; + } + default: + return false; + } + return true; +} + bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, SkColorTable* ctable) { @@ -215,6 +273,7 @@ bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t break; case kIndex_8_SkColorType: case kARGB_4444_SkColorType: + case kRGBA_F16_SkColorType: if (srcInfo.alphaType() != dstInfo.alphaType()) { return false; } @@ -240,6 +299,11 @@ bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t return true; } + if (kAlpha_8_SkColorType == dstInfo.colorType() && + extract_alpha(dstPixels, dstRB, srcPixels, srcRB, srcInfo, ctable)) { + return true; + } + // Can no longer draw directly into 4444, but we can manually whack it for a few combinations if (kARGB_4444_SkColorType == dstInfo.colorType() && (kN32_SkColorType == srcInfo.colorType() || kIndex_8_SkColorType == srcInfo.colorType())) { diff --git a/gfx/skia/skia/src/core/SkCoreBlitters.h b/gfx/skia/skia/src/core/SkCoreBlitters.h index ec9ee203eff5..46b2b7ee943a 100644 --- a/gfx/skia/skia/src/core/SkCoreBlitters.h +++ b/gfx/skia/skia/src/core/SkCoreBlitters.h @@ -185,13 +185,11 @@ private: typedef SkShaderBlitter INHERITED; }; -SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint& paint, - SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator); +SkBlitter* SkBlitter_ARGB32_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*, + SkTBlitterAllocator*); -SkBlitter* SkBlitter_ARGB64_Create(const SkPixmap& device, const SkPaint& paint, - SkShader::Context* shaderContext, - SkTBlitterAllocator* allocator); +SkBlitter* SkBlitter_F16_Create(const SkPixmap& device, const SkPaint&, SkShader::Context*, + SkTBlitterAllocator*); /////////////////////////////////////////////////////////////////////////////// @@ -212,4 +210,8 @@ SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint, SkShader::Context* shaderContext, SkTBlitterAllocator* allocator); + +// Returns nullptr if no SkRasterPipeline blitter can be constructed for this paint. +SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, SkTBlitterAllocator*); + #endif diff --git a/gfx/skia/skia/src/core/SkCpu.cpp b/gfx/skia/skia/src/core/SkCpu.cpp new file mode 100644 index 000000000000..9c827f3ef94a --- /dev/null +++ b/gfx/skia/skia/src/core/SkCpu.cpp @@ -0,0 +1,114 @@ +/* + * 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 "SkCpu.h" +#include "SkOnce.h" + +#if defined(SK_CPU_X86) + #if defined(SK_BUILD_FOR_WIN32) + #include + static void cpuid (uint32_t abcd[4]) { __cpuid ((int*)abcd, 1); } + static void cpuid7(uint32_t abcd[4]) { __cpuidex((int*)abcd, 7, 0); } + static uint64_t xgetbv(uint32_t xcr) { return _xgetbv(xcr); } + #else + #include + #if !defined(__cpuid_count) // Old Mac Clang doesn't have this defined. + #define __cpuid_count(eax, ecx, a, b, c, d) \ + __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eax), "2"(ecx)) + #endif + static void cpuid (uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); } + static void cpuid7(uint32_t abcd[4]) { + __cpuid_count(7, 0, abcd[0], abcd[1], abcd[2], abcd[3]); + } + static uint64_t xgetbv(uint32_t xcr) { + uint32_t eax, edx; + __asm__ __volatile__ ( "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); + return (uint64_t)(edx) << 32 | eax; + } + #endif + + static uint32_t read_cpu_features() { + uint32_t features = 0; + uint32_t abcd[4] = {0,0,0,0}; + + // You might want to refer to http://www.sandpile.org/x86/cpuid.htm + + cpuid(abcd); + if (abcd[3] & (1<<25)) { features |= SkCpu:: SSE1; } + if (abcd[3] & (1<<26)) { features |= SkCpu:: SSE2; } + if (abcd[2] & (1<< 0)) { features |= SkCpu:: SSE3; } + if (abcd[2] & (1<< 9)) { features |= SkCpu::SSSE3; } + if (abcd[2] & (1<<19)) { features |= SkCpu::SSE41; } + if (abcd[2] & (1<<20)) { features |= SkCpu::SSE42; } + + if ((abcd[2] & (3<<26)) == (3<<26) && (xgetbv(0) & 6) == 6) { // XSAVE + OSXSAVE + if (abcd[2] & (1<<28)) { features |= SkCpu:: AVX; } + if (abcd[2] & (1<<29)) { features |= SkCpu::F16C; } + if (abcd[2] & (1<<12)) { features |= SkCpu:: FMA; } + + cpuid7(abcd); + if (abcd[1] & (1<<5)) { features |= SkCpu::AVX2; } + if (abcd[1] & (1<<3)) { features |= SkCpu::BMI1; } + if (abcd[1] & (1<<8)) { features |= SkCpu::BMI2; } + } + return features; + } + +#elif defined(SK_CPU_ARM32) && \ + defined(SK_BUILD_FOR_ANDROID) && \ + !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) + #ifdef MOZ_SKIA + #include "mozilla/arm.h" + static uint32_t read_cpu_features() { + uint32_t features = 0; + if (mozilla::supports_neon()) { features |= SkCpu::NEON; } + return features; + } + #else + #include "cpu-features.h" + + static uint32_t read_cpu_features() { + uint32_t features = 0; + + uint64_t android_features = android_getCpuFeatures(); + if (android_features & ANDROID_CPU_ARM_FEATURE_NEON ) { features |= SkCpu::NEON ; } + if (android_features & ANDROID_CPU_ARM_FEATURE_NEON_FMA) { features |= SkCpu::NEON_FMA; } + if (android_features & ANDROID_CPU_ARM_FEATURE_VFP_FP16) { features |= SkCpu::VFP_FP16; } + return features; + } + #endif +#elif defined(SK_CPU_ARM64) && \ + defined(SK_BUILD_FOR_ANDROID) && \ + !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) + #ifdef MOZ_SKIA + static uint32_t read_cpu_features() { + return 0; + } + #else + #include "cpu-features.h" + + static uint32_t read_cpu_features() { + uint32_t features = 0; + + uint64_t android_features = android_getCpuFeatures(); + if (android_features & ANDROID_CPU_ARM64_FEATURE_CRC32) { features |= SkCpu::CRC32; } + return features; + } + #endif +#else + static uint32_t read_cpu_features() { + return 0; + } + +#endif + +uint32_t SkCpu::gCachedFeatures = 0; + +void SkCpu::CacheRuntimeFeatures() { + static SkOnce once; + once([] { gCachedFeatures = read_cpu_features(); }); +} diff --git a/gfx/skia/skia/src/core/SkCpu.h b/gfx/skia/skia/src/core/SkCpu.h new file mode 100644 index 000000000000..34c19d25401a --- /dev/null +++ b/gfx/skia/skia/src/core/SkCpu.h @@ -0,0 +1,96 @@ +/* + * 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 SkCpu_DEFINED +#define SkCpu_DEFINED + +#include "SkTypes.h" + +struct SkCpu { + enum { + SSE1 = 1 << 0, + SSE2 = 1 << 1, + SSE3 = 1 << 2, + SSSE3 = 1 << 3, + SSE41 = 1 << 4, + SSE42 = 1 << 5, + AVX = 1 << 6, + F16C = 1 << 7, + FMA = 1 << 8, + AVX2 = 1 << 9, + BMI1 = 1 << 10, + BMI2 = 1 << 11, + + // Handy alias for all the cool Haswell+ instructions. + HSW = AVX2 | BMI1 | BMI2 | F16C | FMA, + }; + enum { + NEON = 1 << 0, + NEON_FMA = 1 << 1, + VFP_FP16 = 1 << 2, + CRC32 = 1 << 3, + }; + + static void CacheRuntimeFeatures(); + static bool Supports(uint32_t); +private: + static uint32_t gCachedFeatures; +}; + +inline bool SkCpu::Supports(uint32_t mask) { + uint32_t features = gCachedFeatures; + + // If we mask in compile-time known lower limits, the compiler can + // often compile away this entire function. +#if SK_CPU_X86 + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 + features |= SSE1; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + features |= SSE2; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE3 + features |= SSE3; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + features |= SSSE3; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 + features |= SSE41; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE42 + features |= SSE42; + #endif + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX + features |= AVX; + #endif + // F16C goes here if we add SK_CPU_SSE_LEVEL_F16C + #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 + features |= AVX2; + #endif + // FMA doesn't fit neatly into this total ordering. + // It's available on Haswell+ just like AVX2, but it's technically a different bit. + // TODO: circle back on this if we find ourselves limited by lack of compile-time FMA + +#else + #if defined(SK_ARM_HAS_NEON) + features |= NEON; + #endif + + #if defined(SK_CPU_ARM64) + features |= NEON|NEON_FMA|VFP_FP16; + #endif + + #if defined(SK_ARM_HAS_CRC32) + features |= CRC32; + #endif + +#endif + return (features & mask) == mask; +} + +#endif//SkCpu_DEFINED diff --git a/gfx/skia/skia/src/core/SkCubicClipper.h b/gfx/skia/skia/src/core/SkCubicClipper.h index 617086edb9c8..f00c09ab5f9c 100644 --- a/gfx/skia/skia/src/core/SkCubicClipper.h +++ b/gfx/skia/skia/src/core/SkCubicClipper.h @@ -24,9 +24,9 @@ public: void setClip(const SkIRect& clip); - bool clipCubic(const SkPoint src[4], SkPoint dst[4]); + bool SK_WARN_UNUSED_RESULT clipCubic(const SkPoint src[4], SkPoint dst[4]); - static bool ChopMonoAtY(const SkPoint pts[4], SkScalar y, SkScalar* t); + static bool SK_WARN_UNUSED_RESULT ChopMonoAtY(const SkPoint pts[4], SkScalar y, SkScalar* t); private: SkRect fClip; }; diff --git a/gfx/skia/skia/src/core/SkData.cpp b/gfx/skia/skia/src/core/SkData.cpp index 995a30a54247..ec619d99e5a1 100644 --- a/gfx/skia/skia/src/core/SkData.cpp +++ b/gfx/skia/skia/src/core/SkData.cpp @@ -7,7 +7,7 @@ #include "SkData.h" #include "SkOSFile.h" -#include "SkOncePtr.h" +#include "SkOnce.h" #include "SkReadBuffer.h" #include "SkStream.h" #include "SkWriteBuffer.h" @@ -78,12 +78,16 @@ sk_sp SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) { return sk_sp(data); } +void SkData::DummyReleaseProc(const void*, void*) {} + /////////////////////////////////////////////////////////////////////////////// -SK_DECLARE_STATIC_ONCE_PTR(SkData, gEmpty); sk_sp SkData::MakeEmpty() { - SkData* data = SkRef(gEmpty.get([]{return new SkData(nullptr, 0, nullptr, nullptr); })); - return sk_sp(data); + static SkOnce once; + static SkData* empty; + + once([]{ empty = new SkData(nullptr, 0, nullptr, nullptr); }); + return sk_ref_sp(empty); } // assumes fPtr was allocated via sk_malloc diff --git a/gfx/skia/skia/src/core/SkDataTable.cpp b/gfx/skia/skia/src/core/SkDataTable.cpp index 32e30af64df6..ea2b91b90323 100644 --- a/gfx/skia/skia/src/core/SkDataTable.cpp +++ b/gfx/skia/skia/src/core/SkDataTable.cpp @@ -7,6 +7,7 @@ #include "SkData.h" #include "SkDataTable.h" +#include "SkOnce.h" static void malloc_freeproc(void* context) { sk_free(context); @@ -76,19 +77,17 @@ const void* SkDataTable::at(int index, size_t* size) const { /////////////////////////////////////////////////////////////////////////////// -SkDataTable* SkDataTable::NewEmpty() { - static SkDataTable* gEmpty; - if (nullptr == gEmpty) { - gEmpty = new SkDataTable; - } - gEmpty->ref(); - return gEmpty; +sk_sp SkDataTable::MakeEmpty() { + static SkDataTable* singleton; + static SkOnce once; + once([]{ singleton = new SkDataTable(); }); + return sk_ref_sp(singleton); } -SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, - const size_t sizes[], int count) { +sk_sp SkDataTable::MakeCopyArrays(const void * const * ptrs, + const size_t sizes[], int count) { if (count <= 0) { - return SkDataTable::NewEmpty(); + return SkDataTable::MakeEmpty(); } size_t dataSize = 0; @@ -108,28 +107,27 @@ SkDataTable* SkDataTable::NewCopyArrays(const void * const * ptrs, elem += sizes[i]; } - return new SkDataTable(dir, count, malloc_freeproc, buffer); + return sk_sp(new SkDataTable(dir, count, malloc_freeproc, buffer)); } -SkDataTable* SkDataTable::NewCopyArray(const void* array, size_t elemSize, - int count) { +sk_sp SkDataTable::MakeCopyArray(const void* array, size_t elemSize, int count) { if (count <= 0) { - return SkDataTable::NewEmpty(); + return SkDataTable::MakeEmpty(); } size_t bufferSize = elemSize * count; void* buffer = sk_malloc_throw(bufferSize); memcpy(buffer, array, bufferSize); - return new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer); + return sk_sp(new SkDataTable(buffer, elemSize, count, malloc_freeproc, buffer)); } -SkDataTable* SkDataTable::NewArrayProc(const void* array, size_t elemSize, - int count, FreeProc proc, void* ctx) { +sk_sp SkDataTable::MakeArrayProc(const void* array, size_t elemSize, int count, + FreeProc proc, void* ctx) { if (count <= 0) { - return SkDataTable::NewEmpty(); + return SkDataTable::MakeEmpty(); } - return new SkDataTable(array, elemSize, count, proc, ctx); + return sk_sp(new SkDataTable(array, elemSize, count, proc, ctx)); } /////////////////////////////////////////////////////////////////////////////// @@ -164,18 +162,18 @@ void SkDataTableBuilder::append(const void* src, size_t size) { dir->fSize = size; } -SkDataTable* SkDataTableBuilder::detachDataTable() { +sk_sp SkDataTableBuilder::detachDataTable() { const int count = fDir.count(); if (0 == count) { - return SkDataTable::NewEmpty(); + return SkDataTable::MakeEmpty(); } // Copy the dir into the heap; - void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), - SkChunkAlloc::kThrow_AllocFailType); + void* dir = fHeap->alloc(count * sizeof(SkDataTable::Dir), SkChunkAlloc::kThrow_AllocFailType); memcpy(dir, fDir.begin(), count * sizeof(SkDataTable::Dir)); - SkDataTable* table = new SkDataTable((SkDataTable::Dir*)dir, count, chunkalloc_freeproc, fHeap); + sk_sp table( + new SkDataTable((SkDataTable::Dir*)dir, count, chunkalloc_freeproc, fHeap)); // we have to detach our fHeap, since we are giving that to the table fHeap = nullptr; fDir.reset(); diff --git a/gfx/skia/skia/src/core/SkDeduper.h b/gfx/skia/skia/src/core/SkDeduper.h new file mode 100644 index 000000000000..f82f4fd8c268 --- /dev/null +++ b/gfx/skia/skia/src/core/SkDeduper.h @@ -0,0 +1,39 @@ +/* + * 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 SkDeduper_DEFINED +#define SkDeduper_DEFINED + +#include "SkTypes.h" + +class SkImage; +class SkPicture; +class SkTypeface; + +class SkDeduper { +public: + virtual ~SkDeduper() {} + + // These return 0 on failure + + virtual int findOrDefineImage(SkImage*) = 0; + virtual int findOrDefinePicture(SkPicture*) = 0; + virtual int findOrDefineTypeface(SkTypeface*) = 0; + virtual int findOrDefineFactory(SkFlattenable*) = 0; +}; + +class SkInflator { +public: + virtual ~SkInflator() {} + + virtual SkImage* getImage(int) = 0; + virtual SkPicture* getPicture(int) = 0; + virtual SkTypeface* getTypeface(int) = 0; + virtual SkFlattenable::Factory getFactory(int) = 0; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkDescriptor.h b/gfx/skia/skia/src/core/SkDescriptor.h index 0f13acde97ca..efa02783be50 100644 --- a/gfx/skia/skia/src/core/SkDescriptor.h +++ b/gfx/skia/skia/src/core/SkDescriptor.h @@ -9,7 +9,7 @@ #ifndef SkDescriptor_DEFINED #define SkDescriptor_DEFINED -#include "SkChecksum.h" +#include "SkOpts.h" #include "SkTypes.h" class SkDescriptor : SkNoncopyable { @@ -85,7 +85,7 @@ public: return desc; } - bool equals(const SkDescriptor& other) const { + bool operator==(const SkDescriptor& other) const { // probe to see if we have a good checksum algo // SkASSERT(a.fChecksum != b.fChecksum || memcmp(&a, &b, a.fLength) == 0); @@ -102,6 +102,7 @@ public: } while (aa < stop); return true; } + bool operator!=(const SkDescriptor& other) const { return !(*this == other); } uint32_t getChecksum() const { return fChecksum; } @@ -122,7 +123,7 @@ private: static uint32_t ComputeChecksum(const SkDescriptor* desc) { const uint32_t* ptr = (const uint32_t*)desc + 1; // skip the checksum field size_t len = desc->fLength - sizeof(uint32_t); - return SkChecksum::Murmur3(ptr, len); + return SkOpts::hash(ptr, len); } // private so no one can create one except our factories diff --git a/gfx/skia/skia/src/core/SkDevice.cpp b/gfx/skia/skia/src/core/SkDevice.cpp index 1b228565283c..70eabab7367e 100644 --- a/gfx/skia/skia/src/core/SkDevice.cpp +++ b/gfx/skia/skia/src/core/SkDevice.cpp @@ -10,9 +10,13 @@ #include "SkDraw.h" #include "SkDrawFilter.h" #include "SkImage_Base.h" +#include "SkImageFilter.h" +#include "SkImageFilterCache.h" +#include "SkImagePriv.h" +#include "SkLatticeIter.h" #include "SkMetaData.h" -#include "SkNinePatchIter.h" #include "SkPatchUtils.h" +#include "SkPathPriv.h" #include "SkPathMeasure.h" #include "SkRasterClip.h" #include "SkRSXform.h" @@ -21,11 +25,9 @@ #include "SkTextBlobRunIterator.h" #include "SkTextToPathIter.h" -SkBaseDevice::SkBaseDevice(const SkSurfaceProps& surfaceProps) - : fSurfaceProps(surfaceProps) -#ifdef SK_DEBUG - , fAttachedToCanvas(false) -#endif +SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfaceProps) + : fInfo(info) + , fSurfaceProps(surfaceProps) { fOrigin.setZero(); fMetaData = nullptr; @@ -42,10 +44,7 @@ SkMetaData& SkBaseDevice::getMetaData() { return *fMetaData; } -SkImageInfo SkBaseDevice::imageInfo() const { - return SkImageInfo::MakeUnknown(); -} - +#ifdef SK_SUPPORT_LEGACY_ACCESSBITMAP const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { const SkBitmap& bitmap = this->onAccessBitmap(); if (changePixels) { @@ -53,6 +52,7 @@ const SkBitmap& SkBaseDevice::accessBitmap(bool changePixels) { } return bitmap; } +#endif SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info, TileUsage tileUsage, @@ -73,12 +73,45 @@ SkPixelGeometry SkBaseDevice::CreateInfo::AdjustGeometry(const SkImageInfo& info return geo; } +static inline bool is_int(float x) { + return x == (float) sk_float_round2int(x); +} + +void SkBaseDevice::drawRegion(const SkDraw& draw, const SkRegion& region, const SkPaint& paint) { + bool isNonTranslate = draw.fMatrix->getType() & ~(SkMatrix::kTranslate_Mask); + bool complexPaint = paint.getStyle() != SkPaint::kFill_Style || paint.getMaskFilter() || + paint.getPathEffect(); + bool antiAlias = paint.isAntiAlias() && (!is_int(draw.fMatrix->getTranslateX()) || + !is_int(draw.fMatrix->getTranslateY())); + if (isNonTranslate || complexPaint || antiAlias) { + SkPath path; + region.getBoundaryPath(&path); + return this->drawPath(draw, path, paint, nullptr, false); + } + + SkRegion::Iterator it(region); + while (!it.done()) { + this->drawRect(draw, SkRect::Make(it.rect()), paint); + it.next(); + } +} + +void SkBaseDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle, + SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { + SkPath path; + bool isFillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect(); + SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, + isFillNoPathEffect); + this->drawPath(draw, path, paint); +} + void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { SkPath path; path.addRRect(outer); path.addRRect(inner); path.setFillType(SkPath::kEvenOdd_FillType); + path.setIsVolatile(true); const SkMatrix* preMatrix = nullptr; const bool pathIsMutable = true; @@ -165,7 +198,7 @@ void SkBaseDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { - SkNinePatchIter iter(image->width(), image->height(), center, dst); + SkLatticeIter iter(image->width(), image->height(), center, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { @@ -175,7 +208,29 @@ void SkBaseDevice::drawImageNine(const SkDraw& draw, const SkImage* image, const void SkBaseDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint& paint) { - SkNinePatchIter iter(bitmap.width(), bitmap.height(), center, dst); + SkLatticeIter iter(bitmap.width(), bitmap.height(), center, dst); + + SkRect srcR, dstR; + while (iter.next(&srcR, &dstR)) { + this->drawBitmapRect(draw, bitmap, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + } +} + +void SkBaseDevice::drawImageLattice(const SkDraw& draw, const SkImage* image, + const SkCanvas::Lattice& lattice, const SkRect& dst, + const SkPaint& paint) { + SkLatticeIter iter(lattice, dst); + + SkRect srcR, dstR; + while (iter.next(&srcR, &dstR)) { + this->drawImageRect(draw, image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint); + } +} + +void SkBaseDevice::drawBitmapLattice(const SkDraw& draw, const SkBitmap& bitmap, + const SkCanvas::Lattice& lattice, const SkRect& dst, + const SkPaint& paint) { + SkLatticeIter iter(lattice, dst); SkRect srcR, dstR; while (iter.next(&srcR, &dstR)) { @@ -219,6 +274,13 @@ void SkBaseDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkR /////////////////////////////////////////////////////////////////////////////////////////////////// +void SkBaseDevice::drawSpecial(const SkDraw&, SkSpecialImage*, int x, int y, const SkPaint&) {} +sk_sp SkBaseDevice::makeSpecial(const SkBitmap&) { return nullptr; } +sk_sp SkBaseDevice::makeSpecial(const SkImage*) { return nullptr; } +sk_sp SkBaseDevice::snapSpecial() { return nullptr; } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { #ifdef SK_DEBUG SkASSERT(info.width() > 0 && info.height() > 0); @@ -256,12 +318,6 @@ bool SkBaseDevice::onReadPixels(const SkImageInfo&, void*, size_t, int x, int y) return false; } -bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*, - const SkPaint*) { - // The base class doesn't perform any accelerated picture rendering - return false; -} - bool SkBaseDevice::accessPixels(SkPixmap* pmap) { SkPixmap tempStorage; if (nullptr == pmap) { @@ -401,44 +457,49 @@ void SkBaseDevice::drawTextOnPath(const SkDraw& draw, const void* text, size_t b } } -////////////////////////////////////////////////////////////////////////////////////////// +#include "SkUtils.h" +typedef int (*CountTextProc)(const char* text); +static int count_utf16(const char* text) { + const uint16_t* prev = (uint16_t*)text; + (void)SkUTF16_NextUnichar(&prev); + return SkToInt((const char*)prev - text); +} +static int return_4(const char* text) { return 4; } +static int return_2(const char* text) { return 2; } -void SkBaseDevice::drawSpriteWithFilter(const SkDraw& draw, const SkBitmap& bitmap, - int x, int y, - const SkPaint& paint) { - SkImageFilter* filter = paint.getImageFilter(); - SkASSERT(filter); +void SkBaseDevice::drawTextRSXform(const SkDraw& draw, const void* text, size_t len, + const SkRSXform xform[], const SkPaint& paint) { + CountTextProc proc = nullptr; + switch (paint.getTextEncoding()) { + case SkPaint::kUTF8_TextEncoding: + proc = SkUTF8_CountUTF8Bytes; + break; + case SkPaint::kUTF16_TextEncoding: + proc = count_utf16; + break; + case SkPaint::kUTF32_TextEncoding: + proc = return_4; + break; + case SkPaint::kGlyphID_TextEncoding: + proc = return_2; + break; + } - if (!this->canHandleImageFilter(filter)) { - SkImageFilter::DeviceProxy proxy(this); - SkIPoint offset = SkIPoint::Make(0, 0); - SkMatrix matrix = *draw.fMatrix; - matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); - const SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y); - SkAutoTUnref cache(this->getImageFilterCache()); - SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); - - sk_sp srcImg(SkSpecialImage::internal_fromBM(&proxy, bitmap, - &this->surfaceProps())); - if (!srcImg) { - return; // something disastrous happened - } - - sk_sp resultImg(filter->filterImage(srcImg.get(), ctx, &offset)); - if (resultImg) { - SkPaint tmpUnfiltered(paint); - tmpUnfiltered.setImageFilter(nullptr); - SkBitmap resultBM; - if (resultImg->internal_getBM(&resultBM)) { - // TODO: add drawSprite(SkSpecialImage) to SkDevice? (see skbug.com/5073) - this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); - } - } - } else { - this->drawSprite(draw, bitmap, x, y, paint); + SkDraw localD(draw); + SkMatrix localM, currM; + const void* stopText = (const char*)text + len; + while ((const char*)text < (const char*)stopText) { + localM.setRSXform(*xform++); + currM.setConcat(*draw.fMatrix, localM); + localD.fMatrix = &currM; + int subLen = proc((const char*)text); + this->drawText(localD, text, subLen, 0, 0, paint); + text = (const char*)text + subLen; } } +////////////////////////////////////////////////////////////////////////////////////////// + uint32_t SkBaseDevice::filterTextFlags(const SkPaint& paint) const { uint32_t flags = paint.getFlags(); @@ -459,3 +520,58 @@ uint32_t SkBaseDevice::filterTextFlags(const SkPaint& paint) const { sk_sp SkBaseDevice::makeSurface(SkImageInfo const&, SkSurfaceProps const&) { return nullptr; } + +////////////////////////////////////////////////////////////////////////////////////////// + +void SkBaseDevice::LogDrawScaleFactor(const SkMatrix& matrix, SkFilterQuality filterQuality) { +#if SK_HISTOGRAMS_ENABLED + enum ScaleFactor { + kUpscale_ScaleFactor, + kNoScale_ScaleFactor, + kDownscale_ScaleFactor, + kLargeDownscale_ScaleFactor, + + kLast_ScaleFactor = kLargeDownscale_ScaleFactor + }; + + float rawScaleFactor = matrix.getMinScale(); + + ScaleFactor scaleFactor; + if (rawScaleFactor < 0.5f) { + scaleFactor = kLargeDownscale_ScaleFactor; + } else if (rawScaleFactor < 1.0f) { + scaleFactor = kDownscale_ScaleFactor; + } else if (rawScaleFactor > 1.0f) { + scaleFactor = kUpscale_ScaleFactor; + } else { + scaleFactor = kNoScale_ScaleFactor; + } + + switch (filterQuality) { + case kNone_SkFilterQuality: + SK_HISTOGRAM_ENUMERATION("DrawScaleFactor.NoneFilterQuality", scaleFactor, + kLast_ScaleFactor + 1); + break; + case kLow_SkFilterQuality: + SK_HISTOGRAM_ENUMERATION("DrawScaleFactor.LowFilterQuality", scaleFactor, + kLast_ScaleFactor + 1); + break; + case kMedium_SkFilterQuality: + SK_HISTOGRAM_ENUMERATION("DrawScaleFactor.MediumFilterQuality", scaleFactor, + kLast_ScaleFactor + 1); + break; + case kHigh_SkFilterQuality: + SK_HISTOGRAM_ENUMERATION("DrawScaleFactor.HighFilterQuality", scaleFactor, + kLast_ScaleFactor + 1); + break; + } + + // Also log filter quality independent scale factor. + SK_HISTOGRAM_ENUMERATION("DrawScaleFactor.AnyFilterQuality", scaleFactor, + kLast_ScaleFactor + 1); + + // Also log an overall histogram of filter quality. + SK_HISTOGRAM_ENUMERATION("FilterQuality", filterQuality, kLast_SkFilterQuality + 1); +#endif +} + diff --git a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp index 187a5bf166dc..7e4675bbc1d0 100755 --- a/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp +++ b/gfx/skia/skia/src/core/SkDistanceFieldGen.cpp @@ -242,9 +242,8 @@ static void F1(DFData* curr, int width) { static void F2(DFData* curr, int width) { // right DFData* check = curr + 1; - float distSq = check->fDistSq; SkPoint distVec = check->fDistVector; - distSq = check->fDistSq + 2.0f*distVec.fX + 1.0f; + float distSq = check->fDistSq + 2.0f*distVec.fX + 1.0f; if (distSq < curr->fDistSq) { distVec.fX += 1.0f; curr->fDistSq = distSq; diff --git a/gfx/skia/skia/src/core/SkDocument.cpp b/gfx/skia/skia/src/core/SkDocument.cpp index fa25e44f8645..29db7f05e1fe 100644 --- a/gfx/skia/skia/src/core/SkDocument.cpp +++ b/gfx/skia/skia/src/core/SkDocument.cpp @@ -58,12 +58,12 @@ void SkDocument::endPage() { } } -bool SkDocument::close() { +void SkDocument::close() { for (;;) { switch (fState) { case kBetweenPages_State: { fState = kClosed_State; - bool success = this->onClose(fStream); + this->onClose(fStream); if (fDoneProc) { fDoneProc(fStream, false); @@ -71,13 +71,13 @@ bool SkDocument::close() { // we don't own the stream, but we mark it nullptr since we can // no longer write to it. fStream = nullptr; - return success; + return; } case kInPage_State: this->endPage(); break; case kClosed_State: - return false; + return; } } } diff --git a/gfx/skia/skia/src/core/SkDraw.cpp b/gfx/skia/skia/src/core/SkDraw.cpp index 304a0fc3d05d..72b292d308b2 100644 --- a/gfx/skia/skia/src/core/SkDraw.cpp +++ b/gfx/skia/skia/src/core/SkDraw.cpp @@ -7,6 +7,7 @@ #define __STDC_LIMIT_MACROS #include "SkDraw.h" +#include "SkBlendModePriv.h" #include "SkBlitter.h" #include "SkCanvas.h" #include "SkColorPriv.h" @@ -83,7 +84,9 @@ public: const SkMatrix* localMatrix = nullptr) : fPaint(paint) /* makes a copy of the paint */ { fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, localMatrix, &fAllocator)); + SkShader::kClamp_TileMode, localMatrix, + kNever_SkCopyPixelsMode, + &fAllocator)); // we deliberately left the shader with an owner-count of 2 fPaint.getShader()->ref(); SkASSERT(2 == fPaint.getShader()->getRefCnt()); @@ -114,10 +117,6 @@ SkDraw::SkDraw() { sk_bzero(this, sizeof(*this)); } -SkDraw::SkDraw(const SkDraw& src) { - memcpy(this, &src, sizeof(*this)); -} - bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { if (fRC->isEmpty()) { return false; @@ -165,31 +164,27 @@ static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& p return nullptr; } - SkXfermode::Mode mode; - if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { - return nullptr; - } - + SkBlendMode mode = paint.getBlendMode(); SkColor color = paint.getColor(); // collaps modes based on color... - if (SkXfermode::kSrcOver_Mode == mode) { + if (SkBlendMode::kSrcOver == mode) { unsigned alpha = SkColorGetA(color); if (0 == alpha) { - mode = SkXfermode::kDst_Mode; + mode = SkBlendMode::kDst; } else if (0xFF == alpha) { - mode = SkXfermode::kSrc_Mode; + mode = SkBlendMode::kSrc; } } switch (mode) { - case SkXfermode::kClear_Mode: + case SkBlendMode::kClear: // SkDebugf("--- D_Clear_BitmapXferProc\n"); return D_Clear_BitmapXferProc; // ignore data - case SkXfermode::kDst_Mode: + case SkBlendMode::kDst: // SkDebugf("--- D_Dst_BitmapXferProc\n"); return D_Dst_BitmapXferProc; // ignore data - case SkXfermode::kSrc_Mode: { + case SkBlendMode::kSrc: { /* should I worry about dithering for the lower depths? */ @@ -992,8 +987,7 @@ void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { SkRRect devRRect; if (rrect.transform(*fMatrix, &devRRect)) { SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); - if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get(), - SkPaint::kFill_Style)) { + if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) { return; // filterRRect() called the blitter, so we're done } } @@ -1020,6 +1014,89 @@ SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) { return 1; } +void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage, + SkBlitter* customBlitter, bool doFill) const { + // Do a conservative quick-reject test, since a looper or other modifier may have moved us + // out of range. + if (!devPath.isInverseFillType()) { + // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't + // appear empty to the intersects call. This also gives us slop in case we're antialiasing + SkRect pathBounds = devPath.getBounds().makeOutset(1, 1); + + if (paint.getMaskFilter()) { + paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds); + + // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed + // we can remove this hack. See skbug.com/5542 + pathBounds.outset(7, 7); + } + + // Now compare against the clip's bounds + if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) { + return; + } + } + + SkBlitter* blitter = nullptr; + SkAutoBlitterChoose blitterStorage; + if (nullptr == customBlitter) { + blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage); + blitter = blitterStorage.get(); + } else { + blitter = customBlitter; + } + + if (paint.getMaskFilter()) { + SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle + : SkStrokeRec::kHairline_InitStyle; + if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { + return; // filterPath() called the blitter, so we're done + } + } + + void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); + if (doFill) { + if (paint.isAntiAlias()) { + proc = SkScan::AntiFillPath; + } else { + proc = SkScan::FillPath; + } + } else { // hairline + if (paint.isAntiAlias()) { + switch (paint.getStrokeCap()) { + case SkPaint::kButt_Cap: + proc = SkScan::AntiHairPath; + break; + case SkPaint::kSquare_Cap: + proc = SkScan::AntiHairSquarePath; + break; + case SkPaint::kRound_Cap: + proc = SkScan::AntiHairRoundPath; + break; + default: + proc SK_INIT_TO_AVOID_WARNING; + SkDEBUGFAIL("unknown paint cap type"); + } + } else { + switch (paint.getStrokeCap()) { + case SkPaint::kButt_Cap: + proc = SkScan::HairPath; + break; + case SkPaint::kSquare_Cap: + proc = SkScan::HairSquarePath; + break; + case SkPaint::kRound_Cap: + proc = SkScan::HairRoundPath; + break; + default: + proc SK_INIT_TO_AVOID_WARNING; + SkDEBUGFAIL("unknown paint cap type"); + } + } + } + proc(devPath, *fRC, blitter); +} + void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, const SkMatrix* prePathMatrix, bool pathIsMutable, bool drawCoverage, SkBlitter* customBlitter) const { @@ -1063,7 +1140,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { if (SK_Scalar1 == coverage) { paint.writable()->setStrokeWidth(0); - } else if (SkXfermode::SupportsCoverageAsAlpha(origPaint.getXfermode())) { + } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) { U8CPU newAlpha; #if 0 newAlpha = SkToU8(SkScalarRoundToInt(coverage * @@ -1110,68 +1187,10 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, // transform the path into device space pathPtr->transform(*matrix, devPathPtr); - SkBlitter* blitter = nullptr; - SkAutoBlitterChoose blitterStorage; - if (nullptr == customBlitter) { - blitterStorage.choose(fDst, *fMatrix, *paint, drawCoverage); - blitter = blitterStorage.get(); - } else { - blitter = customBlitter; - } - - if (paint->getMaskFilter()) { - SkPaint::Style style = doFill ? SkPaint::kFill_Style : - SkPaint::kStroke_Style; - if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, blitter, style)) { - return; // filterPath() called the blitter, so we're done - } - } - - void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); - if (doFill) { - if (paint->isAntiAlias()) { - proc = SkScan::AntiFillPath; - } else { - proc = SkScan::FillPath; - } - } else { // hairline - if (paint->isAntiAlias()) { - switch (paint->getStrokeCap()) { - case SkPaint::kButt_Cap: - proc = SkScan::AntiHairPath; - break; - case SkPaint::kSquare_Cap: - proc = SkScan::AntiHairSquarePath; - break; - case SkPaint::kRound_Cap: - proc = SkScan::AntiHairRoundPath; - break; - default: - proc SK_INIT_TO_AVOID_WARNING; - SkDEBUGFAIL("unknown paint cap type"); - } - } else { - switch (paint->getStrokeCap()) { - case SkPaint::kButt_Cap: - proc = SkScan::HairPath; - break; - case SkPaint::kSquare_Cap: - proc = SkScan::HairSquarePath; - break; - case SkPaint::kRound_Cap: - proc = SkScan::HairRoundPath; - break; - default: - proc SK_INIT_TO_AVOID_WARNING; - SkDEBUGFAIL("unknown paint cap type"); - } - } - } - proc(*devPathPtr, *fRC, blitter); + this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill); } -void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, - const SkPaint& paint) const { +void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { @@ -1240,6 +1259,7 @@ void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, // we manually build a shader and draw that into our new mask SkPaint tmpPaint; tmpPaint.setFlags(paint.getFlags()); + tmpPaint.setFilterQuality(paint.getFilterQuality()); SkAutoBitmapShaderInstall install(bitmap, tmpPaint); SkRect rr; rr.set(0, 0, SkIntToScalar(bitmap.width()), @@ -1279,8 +1299,10 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, return; } - SkPaint paint(origPaint); - paint.setStyle(SkPaint::kFill_Style); + SkTCopyOnFirstWrite paint(origPaint); + if (origPaint.getStyle() != SkPaint::kFill_Style) { + paint.writable()->setStyle(SkPaint::kFill_Style); + } SkMatrix matrix; matrix.setConcat(*fMatrix, prematrix); @@ -1290,7 +1312,7 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, } if (bitmap.colorType() != kAlpha_8_SkColorType - && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) { + && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) { // // It is safe to call lock pixels now, since we know the matrix is // (more or less) identity. @@ -1305,7 +1327,7 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, if (clipHandlesSprite(*fRC, ix, iy, pmap)) { SkTBlitterAllocator allocator; // blitter will be owned by the allocator. - SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, ix, iy, &allocator); + SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator); if (blitter) { SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()), *fRC, blitter); @@ -1321,9 +1343,9 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, draw.fMatrix = &matrix; if (bitmap.colorType() == kAlpha_8_SkColorType) { - draw.drawBitmapAsMask(bitmap, paint); + draw.drawBitmapAsMask(bitmap, *paint); } else { - SkAutoBitmapShaderInstall install(bitmap, paint); + SkAutoBitmapShaderInstall install(bitmap, *paint); const SkPaint& paintWithShader = install.paintWithShader(); const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); if (dstBounds) { @@ -1465,10 +1487,13 @@ public: void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { position += rounding; // Prevent glyphs from being drawn outside of or straddling the edge of device space. - if (position.fX > INT_MAX - (INT16_MAX + UINT16_MAX) || - position.fX < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || - position.fY > INT_MAX - (INT16_MAX + UINT16_MAX) || - position.fY < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) { + // Comparisons written a little weirdly so that NaN coordinates are treated safely. + auto gt = [](float a, int b) { return !(a <= (float)b); }; + auto lt = [](float a, int b) { return !(a >= (float)b); }; + if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) || + lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) || + gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) || + lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) { return; } @@ -1484,6 +1509,7 @@ public: SkMask mask; mask.fBounds.set(left, top, right, bottom); + SkASSERT(!mask.fBounds.isEmpty()); if (fUseRegionToDraw) { SkRegion::Cliperator clipper(*fClip, mask.fBounds); @@ -1563,8 +1589,12 @@ private: //////////////////////////////////////////////////////////////////////////////////////////////////// -SkPaint::FakeGamma SkDraw::fakeGamma() const { - return fDevice->imageInfo().isLinear() ? SkPaint::FakeGamma::On : SkPaint::FakeGamma::Off; +uint32_t SkDraw::scalerContextFlags() const { + uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag; + if (!SkImageInfoIsGammaCorrect(fDevice->imageInfo())) { + flags |= SkPaint::kFakeGamma_ScalerContextFlag; + } + return flags; } void SkDraw::drawText(const char text[], size_t byteLength, @@ -1585,7 +1615,7 @@ void SkDraw::drawText(const char text[], size_t byteLength, return; } - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix); + SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); @@ -1613,8 +1643,10 @@ void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, paint.setStyle(SkPaint::kFill_Style); paint.setPathEffect(nullptr); - SkPaint::GlyphCacheProc glyphCacheProc = paint.getGlyphCacheProc(true); - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), nullptr); + SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), + paint.isDevKernText(), + true); + SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), nullptr); const char* stop = text + byteLength; SkTextAlignProc alignProc(paint.getTextAlign()); @@ -1665,7 +1697,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, return; } - SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix); + SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->scalerContextFlags(), fMatrix); // The Blitter Choose needs to be live while using the blitter below. SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); @@ -1905,7 +1937,6 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, if (nullptr == textures) { // just colors (no texture) p.setShader(triShader); - shader = p.getShader(); } else { // colors * texture SkASSERT(shader); @@ -1969,7 +2000,6 @@ void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, void SkDraw::validate() const { SkASSERT(fMatrix != nullptr); - SkASSERT(fClip != nullptr); SkASSERT(fRC != nullptr); const SkIRect& cr = fRC->getBounds(); @@ -2030,7 +2060,8 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, return true; } -static void draw_into_mask(const SkMask& mask, const SkPath& devPath, SkPaint::Style style) { +static void draw_into_mask(const SkMask& mask, const SkPath& devPath, + SkStrokeRec::InitStyle style) { SkDraw draw; if (!draw.fDst.reset(mask)) { return; @@ -2045,17 +2076,25 @@ static void draw_into_mask(const SkMask& mask, const SkPath& devPath, SkPaint::S -SkIntToScalar(mask.fBounds.fTop)); draw.fRC = &clip; - draw.fClip = &clip.bwRgn(); draw.fMatrix = &matrix; paint.setAntiAlias(true); - paint.setStyle(style); + switch (style) { + case SkStrokeRec::kHairline_InitStyle: + SkASSERT(!paint.getStrokeWidth()); + paint.setStyle(SkPaint::kStroke_Style); + break; + case SkStrokeRec::kFill_InitStyle: + SkASSERT(paint.getStyle() == SkPaint::kFill_Style); + break; + + } draw.drawPath(devPath, paint); } bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, const SkMaskFilter* filter, const SkMatrix* filterMatrix, SkMask* mask, SkMask::CreateMode mode, - SkPaint::Style style) { + SkStrokeRec::InitStyle style) { if (SkMask::kJustRenderImage_CreateMode != mode) { if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) return false; diff --git a/gfx/skia/skia/src/core/SkEdge.cpp b/gfx/skia/skia/src/core/SkEdge.cpp index 49df95b568dd..d91c3e6bce8f 100644 --- a/gfx/skia/skia/src/core/SkEdge.cpp +++ b/gfx/skia/skia/src/core/SkEdge.cpp @@ -8,7 +8,7 @@ #include "SkEdge.h" #include "SkFDot6.h" -#include "SkMath.h" +#include "SkMathPriv.h" /* In setLine, setQuadratic, setCubic, the first thing we do is to convert diff --git a/gfx/skia/skia/src/core/SkEdgeClipper.cpp b/gfx/skia/skia/src/core/SkEdgeClipper.cpp index 85c519d3644a..b5ac27ae5908 100644 --- a/gfx/skia/skia/src/core/SkEdgeClipper.cpp +++ b/gfx/skia/skia/src/core/SkEdgeClipper.cpp @@ -263,9 +263,25 @@ static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) { if (pts[0].fY < clip.fTop) { SkPoint tmp[7]; chop_mono_cubic_at_y(pts, clip.fTop, tmp); + + /* + * For a large range in the points, we can do a poor job of chopping, such that the t + * we computed resulted in the lower cubic still being partly above the clip. + * + * If just the first or first 2 Y values are above the fTop, we can just smash them + * down. If the first 3 Ys are above fTop, we can't smash all 3, as that can really + * distort the cubic. In this case, we take the first output (tmp[3..6] and treat it as + * a guess, and re-chop against fTop. Then we fall through to checking if we need to + * smash the first 1 or 2 Y values. + */ + if (tmp[3].fY < clip.fTop && tmp[4].fY < clip.fTop && tmp[5].fY < clip.fTop) { + SkPoint tmp2[4]; + memcpy(tmp2, &tmp[3].fX, 4 * sizeof(SkPoint)); + chop_mono_cubic_at_y(tmp2, clip.fTop, tmp); + } + // tmp[3, 4].fY should all be to the below clip.fTop. - // Since we can't trust the numerics of - // the chopper, we force those conditions now + // Since we can't trust the numerics of the chopper, we force those conditions now tmp[3].fY = clip.fTop; clamp_ge(tmp[4].fY, clip.fTop); diff --git a/gfx/skia/skia/src/core/SkEndian.h b/gfx/skia/skia/src/core/SkEndian.h index 954afb046d91..39e5dd8fb437 100644 --- a/gfx/skia/skia/src/core/SkEndian.h +++ b/gfx/skia/skia/src/core/SkEndian.h @@ -50,7 +50,7 @@ static inline void SkEndianSwap16s(uint16_t array[], int count) { /** Reverse all 4 bytes in a 32bit value. e.g. 0x12345678 -> 0x78563412 */ -static inline uint32_t SkEndianSwap32(uint32_t value) { +static constexpr uint32_t SkEndianSwap32(uint32_t value) { return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | diff --git a/gfx/skia/skia/src/core/SkExchange.h b/gfx/skia/skia/src/core/SkExchange.h new file mode 100644 index 000000000000..50e2fe983d89 --- /dev/null +++ b/gfx/skia/skia/src/core/SkExchange.h @@ -0,0 +1,25 @@ +/* + * 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 SkExchange_DEFINED +#define SkExchange_DEFINED + +#include + +namespace skstd { + +// std::exchange is in C++14 +template +inline static T exchange(T& obj, U&& new_val) { + T old_val = std::move(obj); + obj = std::forward(new_val); + return old_val; +} + +} + +#endif // SkExchange_DEFINED diff --git a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h index 48cc0fa144a8..257528cd0386 100644 --- a/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h +++ b/gfx/skia/skia/src/core/SkFindAndPlaceGlyph.h @@ -405,7 +405,7 @@ private: template class GlyphFindAndPlaceInterface : SkNoncopyable { public: - virtual ~GlyphFindAndPlaceInterface() { }; + virtual ~GlyphFindAndPlaceInterface() { } // findAndPositionGlyph calculates the position of the glyph, finds the glyph, and // returns the position of where the next glyph will be using the glyph's advance and @@ -419,7 +419,7 @@ private: const char** text, SkPoint position, ProcessOneGlyph&& processOneGlyph) { SkFAIL("Should never get here."); return {0.0f, 0.0f}; - }; + } }; // GlyphFindAndPlaceSubpixel handles finding and placing glyphs when sub-pixel positioning is diff --git a/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp b/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp index e9ce09ff1f7f..704526673da9 100644 --- a/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp +++ b/gfx/skia/skia/src/core/SkFlattenableSerialization.cpp @@ -12,7 +12,7 @@ #include "SkWriteBuffer.h" SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) { - SkWriteBuffer writer(SkWriteBuffer::kValidation_Flag); + SkBinaryWriteBuffer writer; writer.writeFlattenable(flattenable); size_t size = writer.bytesWritten(); auto data = SkData::MakeUninitialized(size); diff --git a/gfx/skia/skia/src/core/SkFloatBits.cpp b/gfx/skia/skia/src/core/SkFloatBits.cpp deleted file mode 100644 index ea705513ac18..000000000000 --- a/gfx/skia/skia/src/core/SkFloatBits.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "SkFloatBits.h" -#include "SkMathPriv.h" - -/****************************************************************************** - SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they - do right before they return ... >> exp; - Floor - adds nothing - Round - adds 1 << (exp - 1) - Ceil - adds (1 << exp) - 1 - - Floor and Cast are very similar, but Cast applies its sign after all other - computations on value. Also, Cast does not need to check for negative zero, - as that value (0x80000000) "does the right thing" for Ceil. Note that it - doesn't for Floor/Round/Ceil, hence the explicit check. -******************************************************************************/ - -#define EXP_BIAS (127+23) -#define MATISSA_MAGIC_BIG (1 << 23) - -static inline int unpack_exp(uint32_t packed) { - return (packed << 1 >> 24); -} - -#if 0 -// the ARM compiler generates an extra BIC, so I use the dirty version instead -static inline int unpack_matissa(uint32_t packed) { - // we could mask with 0x7FFFFF, but that is harder for ARM to encode - return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG; -} -#endif - -// returns the low 24-bits, so we need to OR in the magic_bit afterwards -static inline int unpack_matissa_dirty(uint32_t packed) { - return packed & ~0xFF000000; -} - -// same as (int)float -int32_t SkFloatBits_toIntCast(int32_t packed) { - int exp = unpack_exp(packed) - EXP_BIAS; - int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; - - if (exp >= 0) { - if (exp > 7) { // overflow - value = SK_MaxS32; - } else { - value <<= exp; - } - } else { - exp = -exp; - if (exp > 25) { // underflow - exp = 25; - } - value >>= exp; - } - return SkApplySign(value, SkExtractSign(packed)); -} - -// same as (int)floor(float) -int32_t SkFloatBits_toIntFloor(int32_t packed) { - // curse you negative 0 - if (SkLeftShift(packed, 1) == 0) { - return 0; - } - - int exp = unpack_exp(packed) - EXP_BIAS; - int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; - - if (exp >= 0) { - if (exp > 7) { // overflow - value = SK_MaxS32; - } else { - value <<= exp; - } - // apply the sign after we check for overflow - return SkApplySign(value, SkExtractSign(packed)); - } else { - // apply the sign before we right-shift - value = SkApplySign(value, SkExtractSign(packed)); - exp = -exp; - if (exp > 25) { // underflow -#ifdef SK_CPU_FLUSH_TO_ZERO - // The iOS ARM processor discards small denormalized numbers to go faster. - // The comparision below empirically causes the result to agree with the - // tests in MathTest test_float_floor - if (exp > 149) { - return 0; - } -#else - exp = 25; -#endif - } - // int add = 0; - return value >> exp; - } -} - -// same as (int)floor(float + 0.5) -int32_t SkFloatBits_toIntRound(int32_t packed) { - // curse you negative 0 - if (SkLeftShift(packed, 1) == 0) { - return 0; - } - - int exp = unpack_exp(packed) - EXP_BIAS; - int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; - - if (exp >= 0) { - if (exp > 7) { // overflow - value = SK_MaxS32; - } else { - value <<= exp; - } - // apply the sign after we check for overflow - return SkApplySign(value, SkExtractSign(packed)); - } else { - // apply the sign before we right-shift - value = SkApplySign(value, SkExtractSign(packed)); - exp = -exp; - if (exp > 25) { // underflow - exp = 25; - } - int add = 1 << (exp - 1); - return (value + add) >> exp; - } -} - -// same as (int)ceil(float) -int32_t SkFloatBits_toIntCeil(int32_t packed) { - // curse you negative 0 - if (SkLeftShift(packed, 1) == 0) { - return 0; - } - - int exp = unpack_exp(packed) - EXP_BIAS; - int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; - - if (exp >= 0) { - if (exp > 7) { // overflow - value = SK_MaxS32; - } else { - value <<= exp; - } - // apply the sign after we check for overflow - return SkApplySign(value, SkExtractSign(packed)); - } else { - // apply the sign before we right-shift - value = SkApplySign(value, SkExtractSign(packed)); - exp = -exp; - if (exp > 25) { // underflow -#ifdef SK_CPU_FLUSH_TO_ZERO - // The iOS ARM processor discards small denormalized numbers to go faster. - // The comparision below empirically causes the result to agree with the - // tests in MathTest test_float_ceil - if (exp > 149) { - return 0; - } - return 0 < value; -#else - exp = 25; -#endif - } - int add = (1 << exp) - 1; - return (value + add) >> exp; - } -} - -float SkIntToFloatCast(int32_t value) { - if (0 == value) { - return 0; - } - - int shift = EXP_BIAS; - - // record the sign and make value positive - int sign = SkExtractSign(value); - value = SkApplySign(value, sign); - - if (value >> 24) { // value is too big (has more than 24 bits set) - int bias = 8 - SkCLZ(value); - SkDebugf("value = %d, bias = %d\n", value, bias); - SkASSERT(bias > 0 && bias < 8); - value >>= bias; // need to round? - shift += bias; - } else { - int zeros = SkCLZ(value << 8); - SkASSERT(zeros >= 0 && zeros <= 23); - value <<= zeros; - shift -= zeros; - } - - // now value is left-aligned to 24 bits - SkASSERT((value >> 23) == 1); - SkASSERT(shift >= 0 && shift <= 255); - - SkFloatIntUnion data; - data.fSignBitInt = SkLeftShift(sign, 31) | SkLeftShift(shift, 23) | (value & ~MATISSA_MAGIC_BIG); - return data.fFloat; -} diff --git a/gfx/skia/skia/src/core/SkFont.cpp b/gfx/skia/skia/src/core/SkFont.cpp index c39cc185d3d5..aa7fe366c8dd 100644 --- a/gfx/skia/skia/src/core/SkFont.cpp +++ b/gfx/skia/skia/src/core/SkFont.cpp @@ -9,13 +9,9 @@ #include "SkTypeface.h" #include "SkUtils.h" -static SkTypeface* ref_or_default(SkTypeface* face) { - return face ? SkRef(face) : SkTypeface::RefDefault(); -} - -SkFont::SkFont(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType mt, +SkFont::SkFont(sk_sp face, SkScalar size, SkScalar scaleX, SkScalar skewX, MaskType mt, uint32_t flags) - : fTypeface(ref_or_default(face)) + : fTypeface(face ? std::move(face) : SkTypeface::MakeDefault()) , fSize(size) , fScaleX(scaleX) , fSkewX(skewX) @@ -28,8 +24,8 @@ SkFont::SkFont(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScalar skewX, SkASSERT(0 == (flags & ~kAllFlags)); } -SkFont* SkFont::Create(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScalar skewX, - MaskType mt, uint32_t flags) { +sk_sp SkFont::Make(sk_sp face, SkScalar size, SkScalar scaleX, SkScalar skewX, + MaskType mt, uint32_t flags) { if (size <= 0 || !SkScalarIsFinite(size)) { return nullptr; } @@ -40,24 +36,24 @@ SkFont* SkFont::Create(SkTypeface* face, SkScalar size, SkScalar scaleX, SkScala return nullptr; } flags &= kAllFlags; - return new SkFont(face, size, scaleX, skewX, mt, flags); + return sk_sp(new SkFont(std::move(face), size, scaleX, skewX, mt, flags)); } -SkFont* SkFont::Create(SkTypeface* face, SkScalar size, MaskType mt, uint32_t flags) { - return SkFont::Create(face, size, 1, 0, mt, flags); +sk_sp SkFont::Make(sk_sp face, SkScalar size, MaskType mt, uint32_t flags) { + return SkFont::Make(std::move(face), size, 1, 0, mt, flags); } -SkFont* SkFont::cloneWithSize(SkScalar newSize) const { - return SkFont::Create(this->getTypeface(), newSize, this->getScaleX(), this->getSkewX(), - this->getMaskType(), this->getFlags()); +sk_sp SkFont::makeWithSize(SkScalar newSize) const { + return SkFont::Make(sk_ref_sp(this->getTypeface()), newSize, this->getScaleX(), + this->getSkewX(), this->getMaskType(), this->getFlags()); } +sk_sp SkFont::makeWithFlags(uint32_t newFlags) const { + return SkFont::Make(sk_ref_sp(this->getTypeface()), this->getSize(), this->getScaleX(), + this->getSkewX(), this->getMaskType(), newFlags); +} /////////////////////////////////////////////////////////////////////////////////////////////////// -SkFont::~SkFont() { - SkSafeUnref(fTypeface); -} - int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding, uint16_t glyphs[], int maxGlyphCount) const { if (0 == byteLength) { @@ -82,21 +78,21 @@ int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding enc count = SkToInt(byteLength >> 1); break; } - if (nullptr == glyphs) { + if (!glyphs) { return count; } // TODO: unify/eliminate SkTypeface::Encoding with SkTextEncoding - SkTypeface::Encoding typeface_encoding; + SkTypeface::Encoding typefaceEncoding; switch (encoding) { case kUTF8_SkTextEncoding: - typeface_encoding = SkTypeface::kUTF8_Encoding; + typefaceEncoding = SkTypeface::kUTF8_Encoding; break; case kUTF16_SkTextEncoding: - typeface_encoding = SkTypeface::kUTF16_Encoding; + typefaceEncoding = SkTypeface::kUTF16_Encoding; break; case kUTF32_SkTextEncoding: - typeface_encoding = SkTypeface::kUTF32_Encoding; + typefaceEncoding = SkTypeface::kUTF32_Encoding; break; default: SkASSERT(kGlyphID_SkTextEncoding == encoding); @@ -105,7 +101,7 @@ int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding enc return count; } - (void)fTypeface->charsToGlyphs(text, typeface_encoding, glyphs, count); + (void)fTypeface->charsToGlyphs(text, typefaceEncoding, glyphs, count); return count; } @@ -118,7 +114,7 @@ SkScalar SkFont::measureText(const void* text, size_t byteLength, SkTextEncoding #include "SkPaint.h" -SkFont* SkFont::Testing_CreateFromPaint(const SkPaint& paint) { +sk_sp SkFont::Testing_CreateFromPaint(const SkPaint& paint) { uint32_t flags = 0; if (paint.isVerticalText()) { flags |= kVertical_Flag; @@ -150,7 +146,6 @@ SkFont* SkFont::Testing_CreateFromPaint(const SkPaint& paint) { maskType = paint.isLCDRenderText() ? kLCD_MaskType : kA8_MaskType; } - return Create(paint.getTypeface(), - paint.getTextSize(), paint.getTextScaleX(), paint.getTextSkewX(), - maskType, flags); + return Make(sk_ref_sp(paint.getTypeface()), paint.getTextSize(), paint.getTextScaleX(), + paint.getTextSkewX(), maskType, flags); } diff --git a/gfx/skia/skia/src/core/SkFontDescriptor.cpp b/gfx/skia/skia/src/core/SkFontDescriptor.cpp index 69fdc1543269..73ea2058ce79 100644 --- a/gfx/skia/skia/src/core/SkFontDescriptor.cpp +++ b/gfx/skia/skia/src/core/SkFontDescriptor.cpp @@ -6,6 +6,7 @@ */ #include "SkFontDescriptor.h" +#include "SkMakeUnique.h" #include "SkStream.h" #include "SkData.h" @@ -23,7 +24,7 @@ enum { kSentinel = 0xFF, }; -SkFontDescriptor::SkFontDescriptor(SkTypeface::Style style) : fStyle(style) { } +SkFontDescriptor::SkFontDescriptor() { } static void read_string(SkStream* stream, SkString* string) { const uint32_t length = SkToU32(stream->readPackedUInt()); @@ -59,7 +60,15 @@ static void write_uint(SkWStream* stream, size_t n, uint32_t id) { } bool SkFontDescriptor::Deserialize(SkStream* stream, SkFontDescriptor* result) { - result->fStyle = (SkTypeface::Style)stream->readPackedUInt(); + size_t styleBits = stream->readPackedUInt(); + if (styleBits <= 2) { + // Remove this branch when MIN_PICTURE_VERSION > 45 + result->fStyle = SkFontStyle::FromOldStyle(styleBits); + } else { + result->fStyle = SkFontStyle((styleBits >> 16) & 0xFFFF, + (styleBits >> 8 ) & 0xFF, + static_cast(styleBits & 0xFF)); + } SkAutoSTMalloc<4, SkFixed> axis; size_t axisCount = 0; @@ -98,8 +107,8 @@ bool SkFontDescriptor::Deserialize(SkStream* stream, SkFontDescriptor* result) { if (length > 0) { sk_sp data(SkData::MakeUninitialized(length)); if (stream->read(data->writable_data(), length) == length) { - result->fFontData.reset(new SkFontData(new SkMemoryStream(data), - index, axis, axisCount)); + result->fFontData = skstd::make_unique( + skstd::make_unique(data), index, axis, axisCount); } else { SkDEBUGFAIL("Could not read font data"); return false; @@ -109,7 +118,8 @@ bool SkFontDescriptor::Deserialize(SkStream* stream, SkFontDescriptor* result) { } void SkFontDescriptor::serialize(SkWStream* stream) { - stream->writePackedUInt(fStyle); + uint32_t styleBits = (fStyle.weight() << 16) | (fStyle.width() << 8) | (fStyle.slant()); + stream->writePackedUInt(styleBits); write_string(stream, fFamilyName, kFontFamilyName); write_string(stream, fFullName, kFullName); @@ -129,10 +139,10 @@ void SkFontDescriptor::serialize(SkWStream* stream) { stream->writePackedUInt(kSentinel); if (fFontData.get() && fFontData->hasStream()) { - SkAutoTDelete fontData(fFontData->detachStream()); - size_t length = fontData->getLength(); + std::unique_ptr fontStream = fFontData->detachStream(); + size_t length = fontStream->getLength(); stream->writePackedUInt(length); - stream->writeStream(fontData, length); + stream->writeStream(fontStream.get(), length); } else { stream->writePackedUInt(0); } diff --git a/gfx/skia/skia/src/core/SkFontDescriptor.h b/gfx/skia/skia/src/core/SkFontDescriptor.h index 9b87365ed5b3..de1462177bc9 100644 --- a/gfx/skia/skia/src/core/SkFontDescriptor.h +++ b/gfx/skia/skia/src/core/SkFontDescriptor.h @@ -15,9 +15,9 @@ class SkFontData { public: - /** This takes ownership of 'stream'. Makes a copy of the data in 'axis'. */ - SkFontData(SkStreamAsset* stream, int index, const SkFixed axis[], int axisCount) - : fStream(stream), fIndex(index), fAxisCount(axisCount), fAxis(axisCount) + /** Makes a copy of the data in 'axis'. */ + SkFontData(std::unique_ptr stream, int index, const SkFixed axis[],int axisCount) + : fStream(std::move(stream)), fIndex(index), fAxisCount(axisCount), fAxis(axisCount) { for (int i = 0; i < axisCount; ++i) { fAxis[i] = axis[i]; @@ -34,15 +34,15 @@ public: } } bool hasStream() const { return fStream.get() != nullptr; } - SkStreamAsset* duplicateStream() const { return fStream->duplicate(); } - SkStreamAsset* detachStream() { return fStream.release(); } + std::unique_ptr detachStream() { return std::move(fStream); } SkStreamAsset* getStream() { return fStream.get(); } + SkStreamAsset const* getStream() const { return fStream.get(); } int getIndex() const { return fIndex; } int getAxisCount() const { return fAxisCount; } const SkFixed* getAxis() const { return fAxis.get(); } private: - SkAutoTDelete fStream; + std::unique_ptr fStream; int fIndex; int fAxisCount; SkAutoSTMalloc<4, SkFixed> fAxis; @@ -50,35 +50,34 @@ private: class SkFontDescriptor : SkNoncopyable { public: - SkFontDescriptor(SkTypeface::Style = SkTypeface::kNormal); + SkFontDescriptor(); // Does not affect ownership of SkStream. static bool Deserialize(SkStream*, SkFontDescriptor* result); void serialize(SkWStream*); - SkTypeface::Style getStyle() { return fStyle; } - void setStyle(SkTypeface::Style style) { fStyle = style; } + SkFontStyle getStyle() { return fStyle; } + void setStyle(SkFontStyle style) { fStyle = style; } const char* getFamilyName() const { return fFamilyName.c_str(); } const char* getFullName() const { return fFullName.c_str(); } const char* getPostscriptName() const { return fPostscriptName.c_str(); } bool hasFontData() const { return fFontData.get() != nullptr; } - SkFontData* detachFontData() { return fFontData.release(); } + std::unique_ptr detachFontData() { return std::move(fFontData); } void setFamilyName(const char* name) { fFamilyName.set(name); } void setFullName(const char* name) { fFullName.set(name); } void setPostscriptName(const char* name) { fPostscriptName.set(name); } - /** Set the font data only if it is necessary for serialization. - * This method takes ownership of the font data. */ - void setFontData(SkFontData* data) { fFontData.reset(data); } + /** Set the font data only if it is necessary for serialization. */ + void setFontData(std::unique_ptr data) { fFontData = std::move(data); } private: SkString fFamilyName; SkString fFullName; SkString fPostscriptName; - SkAutoTDelete fFontData; + std::unique_ptr fFontData; - SkTypeface::Style fStyle; + SkFontStyle fStyle; }; #endif // SkFontDescriptor_DEFINED diff --git a/gfx/skia/skia/src/core/SkFontHost.cpp b/gfx/skia/skia/src/core/SkFontLCDConfig.cpp similarity index 50% rename from gfx/skia/skia/src/core/SkFontHost.cpp rename to gfx/skia/skia/src/core/SkFontLCDConfig.cpp index 4f0dc8637d57..3d1f35b58c22 100644 --- a/gfx/skia/skia/src/core/SkFontHost.cpp +++ b/gfx/skia/skia/src/core/SkFontLCDConfig.cpp @@ -25,24 +25,3 @@ SkFontLCDConfig::LCDOrder SkFontLCDConfig::GetSubpixelOrder() { void SkFontLCDConfig::SetSubpixelOrder(LCDOrder order) { gLCDOrder = order; } - -/////////////////////////////////////////////////////////////////////////////// -// Legacy wrappers : remove from SkFontHost when webkit switches to new API - -#include "SkFontHost.h" - -SkFontHost::LCDOrientation SkFontHost::GetSubpixelOrientation() { - return (SkFontHost::LCDOrientation)SkFontLCDConfig::GetSubpixelOrientation(); -} - -void SkFontHost::SetSubpixelOrientation(LCDOrientation orientation) { - SkFontLCDConfig::SetSubpixelOrientation((SkFontLCDConfig::LCDOrientation)orientation); -} - -SkFontHost::LCDOrder SkFontHost::GetSubpixelOrder() { - return (SkFontHost::LCDOrder)SkFontLCDConfig::GetSubpixelOrder(); -} - -void SkFontHost::SetSubpixelOrder(LCDOrder order) { - SkFontLCDConfig::SetSubpixelOrder((SkFontLCDConfig::LCDOrder)order); -} diff --git a/gfx/skia/skia/src/core/SkFontMgr.cpp b/gfx/skia/skia/src/core/SkFontMgr.cpp index ab04250c0343..57f82b03ba28 100644 --- a/gfx/skia/skia/src/core/SkFontMgr.cpp +++ b/gfx/skia/skia/src/core/SkFontMgr.cpp @@ -7,7 +7,7 @@ #include "SkFontDescriptor.h" #include "SkFontMgr.h" -#include "SkOncePtr.h" +#include "SkOnce.h" #include "SkStream.h" #include "SkTypes.h" @@ -74,7 +74,7 @@ protected: SkTypeface* onCreateFromFile(const char[], int) const override { return nullptr; } - SkTypeface* onLegacyCreateTypeface(const char [], unsigned) const override { + SkTypeface* onLegacyCreateTypeface(const char [], SkFontStyle) const override { return nullptr; } }; @@ -139,11 +139,11 @@ SkTypeface* SkFontMgr::createFromStream(SkStreamAsset* stream, const FontParamet return this->onCreateFromStream(stream, params); } -SkTypeface* SkFontMgr::createFromFontData(SkFontData* data) const { +SkTypeface* SkFontMgr::createFromFontData(std::unique_ptr data) const { if (nullptr == data) { return nullptr; } - return this->onCreateFromFontData(data); + return this->onCreateFromFontData(std::move(data)); } // This implementation is temporary until it can be made pure virtual. @@ -152,10 +152,8 @@ SkTypeface* SkFontMgr::onCreateFromStream(SkStreamAsset* stream, const FontParam } // This implementation is temporary until it can be made pure virtual. -SkTypeface* SkFontMgr::onCreateFromFontData(SkFontData* data) const { - SkTypeface* ret = this->createFromStream(data->detachStream(), data->getIndex()); - delete data; - return ret; +SkTypeface* SkFontMgr::onCreateFromFontData(std::unique_ptr data) const { + return this->createFromStream(data->detachStream().release(), data->getIndex()); } SkTypeface* SkFontMgr::createFromFile(const char path[], int ttcIndex) const { @@ -165,17 +163,19 @@ SkTypeface* SkFontMgr::createFromFile(const char path[], int ttcIndex) const { return this->onCreateFromFile(path, ttcIndex); } -SkTypeface* SkFontMgr::legacyCreateTypeface(const char familyName[], - unsigned styleBits) const { - return this->onLegacyCreateTypeface(familyName, styleBits); +SkTypeface* SkFontMgr::legacyCreateTypeface(const char familyName[], SkFontStyle style) const { + return this->onLegacyCreateTypeface(familyName, style); } -SK_DECLARE_STATIC_ONCE_PTR(SkFontMgr, singleton); SkFontMgr* SkFontMgr::RefDefault() { - return SkRef(singleton.get([]{ + static SkOnce once; + static SkFontMgr* singleton; + + once([]{ SkFontMgr* fm = SkFontMgr::Factory(); - return fm ? fm : new SkEmptyFontMgr; - })); + singleton = fm ? fm : new SkEmptyFontMgr; + }); + return SkRef(singleton); } /** @@ -212,6 +212,9 @@ SkTypeface* SkFontStyleSet::matchStyleCSS3(const SkFontStyle& pattern) { struct Score { int score; int index; + Score& operator +=(int rhs) { this->score += rhs; return *this; } + Score& operator <<=(int rhs) { this->score <<= rhs; return *this; } + bool operator <(const Score& that) { return this->score < that.score; } }; Score maxScore = { 0, 0 }; @@ -220,58 +223,70 @@ SkTypeface* SkFontStyleSet::matchStyleCSS3(const SkFontStyle& pattern) { this->getStyle(i, ¤t, nullptr); Score currentScore = { 0, i }; - // CSS stretch. (This is the width.) - // This has the highest priority. + // CSS stretch / SkFontStyle::Width + // Takes priority over everything else. if (pattern.width() <= SkFontStyle::kNormal_Width) { if (current.width() <= pattern.width()) { - currentScore.score += 10 - pattern.width() + current.width(); + currentScore += 10 - pattern.width() + current.width(); } else { - currentScore.score += 10 - current.width(); + currentScore += 10 - current.width(); } } else { if (current.width() > pattern.width()) { - currentScore.score += 10 + pattern.width() - current.width(); + currentScore += 10 + pattern.width() - current.width(); } else { - currentScore.score += current.width(); + currentScore += current.width(); } } - currentScore.score *= 1002; + currentScore <<= 8; - // CSS style (italic/oblique) - // Being italic trumps all valid weights which are not italic. - // Note that newer specs differentiate between italic and oblique. - if (pattern.isItalic() == current.isItalic()) { - currentScore.score += 1001; - } + // CSS style (normal, italic, oblique) / SkFontStyle::Slant (upright, italic, oblique) + // Takes priority over all valid weights. + static_assert(SkFontStyle::kUpright_Slant == 0 && + SkFontStyle::kItalic_Slant == 1 && + SkFontStyle::kOblique_Slant == 2, + "SkFontStyle::Slant values not as required."); + SkASSERT(0 <= pattern.slant() && pattern.slant() <= 2 && + 0 <= current.slant() && current.slant() <= 2); + static const int score[3][3] = { + /* Upright Italic Oblique [current]*/ + /* Upright */ { 3 , 1 , 2 }, + /* Italic */ { 1 , 3 , 2 }, + /* Oblique */ { 1 , 2 , 3 }, + /* [pattern] */ + }; + currentScore += score[pattern.slant()][current.slant()]; + currentScore <<= 8; - // Synthetics (weight/style) [no stretch synthetic?] + // Synthetics (weight, style) [no stretch synthetic?] + // CSS weight / SkFontStyle::Weight // The 'closer' to the target weight, the higher the score. // 1000 is the 'heaviest' recognized weight if (pattern.weight() == current.weight()) { - currentScore.score += 1000; + currentScore += 1000; } else if (pattern.weight() <= 500) { if (400 <= pattern.weight() && pattern.weight() < 450) { if (450 <= current.weight() && current.weight() <= 500) { // Artificially boost the 500 weight. // TODO: determine correct number to use. - currentScore.score += 500; + currentScore += 500; } } if (current.weight() <= pattern.weight()) { - currentScore.score += 1000 - pattern.weight() + current.weight(); + currentScore += 1000 - pattern.weight() + current.weight(); } else { - currentScore.score += 1000 - current.weight(); + currentScore += 1000 - current.weight(); } } else if (pattern.weight() > 500) { if (current.weight() > pattern.weight()) { - currentScore.score += 1000 + pattern.weight() - current.weight(); + currentScore += 1000 + pattern.weight() - current.weight(); } else { - currentScore.score += current.weight(); + currentScore += current.weight(); } } - if (currentScore.score > maxScore.score) { + if (maxScore < currentScore) { maxScore = currentScore; } } diff --git a/gfx/skia/skia/src/core/SkFontStyle.cpp b/gfx/skia/skia/src/core/SkFontStyle.cpp index badf9d7a9d88..a24e7cde2e7d 100644 --- a/gfx/skia/skia/src/core/SkFontStyle.cpp +++ b/gfx/skia/skia/src/core/SkFontStyle.cpp @@ -18,16 +18,15 @@ SkFontStyle::SkFontStyle() { SkFontStyle::SkFontStyle(int weight, int width, Slant slant) { fUnion.fU32 = 0; - fUnion.fR.fWeight = SkTPin(weight, kThin_Weight, kBlack_Weight); - fUnion.fR.fWidth = SkTPin(width, kUltraCondensed_Width, kUltaExpanded_Width); - fUnion.fR.fSlant = SkTPin(slant, kUpright_Slant, kItalic_Slant); + fUnion.fR.fWeight = SkTPin(weight, kInvisible_Weight, kExtraBlack_Weight); + fUnion.fR.fWidth = SkTPin(width, kUltraCondensed_Width, kUltraExpanded_Width); + fUnion.fR.fSlant = SkTPin(slant, kUpright_Slant, kOblique_Slant); } -SkFontStyle::SkFontStyle(unsigned oldStyle) { - fUnion.fU32 = 0; - fUnion.fR.fWeight = (oldStyle & SkTypeface::kBold) ? SkFontStyle::kBold_Weight - : SkFontStyle::kNormal_Weight; - fUnion.fR.fWidth = SkFontStyle::kNormal_Width; - fUnion.fR.fSlant = (oldStyle & SkTypeface::kItalic) ? SkFontStyle::kItalic_Slant - : SkFontStyle::kUpright_Slant; +/*static*/SkFontStyle SkFontStyle::FromOldStyle(unsigned oldStyle) { + return SkFontStyle((oldStyle & SkTypeface::kBold) ? SkFontStyle::kBold_Weight + : SkFontStyle::kNormal_Weight, + SkFontStyle::kNormal_Width, + (oldStyle & SkTypeface::kItalic) ? SkFontStyle::kItalic_Slant + : SkFontStyle::kUpright_Slant); } diff --git a/gfx/skia/skia/src/core/SkFuzzLogging.h b/gfx/skia/skia/src/core/SkFuzzLogging.h new file mode 100644 index 000000000000..8e546e3a0652 --- /dev/null +++ b/gfx/skia/skia/src/core/SkFuzzLogging.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 SkFuzzLogging_DEFINED +#define SkFuzzLogging_DEFINED + +// Utilities for Skia's fuzzer + +// When SK_FUZZ_LOGGING is defined SkDebugfs relevant to image filter fuzzing +// will be enabled. This allows the filter fuzzing code to white list fuzzer +// failures based on the output logs. +// Define this flag in your SkUserConfig.h or in your Make/Build system. +#ifdef SK_FUZZ_LOGGING + #define SkFUZZF(args) SkDebugf("SkFUZZ: "); SkDebugf args +#else + #define SkFUZZF(args) +#endif + +#endif diff --git a/gfx/skia/skia/src/core/SkGeometry.cpp b/gfx/skia/skia/src/core/SkGeometry.cpp index 2c026c6ced1b..58b45140e226 100644 --- a/gfx/skia/skia/src/core/SkGeometry.cpp +++ b/gfx/skia/skia/src/core/SkGeometry.cpp @@ -743,7 +743,8 @@ static int solve_cubic_poly(const SkScalar coeff[4], SkScalar tValues[3]) { SkScalar r; if (R2MinusQ3 < 0) { // we have 3 real roots - SkScalar theta = SkScalarACos(R / SkScalarSqrt(Q3)); + // the divide/root can, due to finite precisions, be slightly outside of -1...1 + SkScalar theta = SkScalarACos(SkScalarPin(R / SkScalarSqrt(Q3), -1, 1)); SkScalar neg2RootQ = -2 * SkScalarSqrt(Q); r = neg2RootQ * SkScalarCos(theta/3) - adiv3; @@ -974,7 +975,8 @@ static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) { dst[2].set(src[2].fX * 1, src[2].fY * 1, 1); } -void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { +// return false if infinity or NaN is generated; caller must check +bool SkConic::chopAt(SkScalar t, SkConic dst[2]) const { SkP3D tmp[3], tmp2[3]; ratquad_mapTo3D(fPts, fW, tmp); @@ -1000,18 +1002,23 @@ void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { SkScalar root = SkScalarSqrt(tmp2[1].fZ); dst[0].fW = tmp2[0].fZ / root; dst[1].fW = tmp2[2].fZ / root; + SkASSERT(sizeof(dst[0]) == sizeof(SkScalar) * 7); + SkASSERT(0 == offsetof(SkConic, fPts[0].fX)); + return SkScalarsAreFinite(&dst[0].fPts[0].fX, 7 * 2); } void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const { if (0 == t1 || 1 == t2) { if (0 == t1 && 1 == t2) { *dst = *this; + return; } else { SkConic pair[2]; - this->chopAt(t1 ? t1 : t2, pair); - *dst = pair[SkToBool(t1)]; + if (this->chopAt(t1 ? t1 : t2, pair)) { + *dst = pair[SkToBool(t1)]; + return; + } } - return; } SkConicCoeff coeff(*this); Sk2s tt1(t1); @@ -1152,6 +1159,12 @@ int SkConic::computeQuadPOW2(SkScalar tol) const { return pow2; } +// This was originally developed and tested for pathops: see SkOpTypes.h +// returns true if (a <= b <= c) || (a >= b >= c) +static bool between(SkScalar a, SkScalar b, SkScalar c) { + return (a - b) * (c - b) <= 0; +} + static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) { SkASSERT(level >= 0); @@ -1161,6 +1174,32 @@ static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) { } else { SkConic dst[2]; src.chop(dst); + const SkScalar startY = src.fPts[0].fY; + const SkScalar endY = src.fPts[2].fY; + if (between(startY, src.fPts[1].fY, endY)) { + // If the input is monotonic and the output is not, the scan converter hangs. + // Ensure that the chopped conics maintain their y-order. + SkScalar midY = dst[0].fPts[2].fY; + if (!between(startY, midY, endY)) { + // If the computed midpoint is outside the ends, move it to the closer one. + SkScalar closerY = SkTAbs(midY - startY) < SkTAbs(midY - endY) ? startY : endY; + dst[0].fPts[2].fY = dst[1].fPts[0].fY = closerY; + } + if (!between(startY, dst[0].fPts[1].fY, dst[0].fPts[2].fY)) { + // If the 1st control is not between the start and end, put it at the start. + // This also reduces the quad to a line. + dst[0].fPts[1].fY = startY; + } + if (!between(dst[1].fPts[0].fY, dst[1].fPts[1].fY, endY)) { + // If the 2nd control is not between the start and end, put it at the end. + // This also reduces the quad to a line. + dst[1].fPts[1].fY = endY; + } + // Verify that all five points are in order. + SkASSERT(between(startY, dst[0].fPts[1].fY, dst[0].fPts[2].fY)); + SkASSERT(between(dst[0].fPts[1].fY, dst[0].fPts[2].fY, dst[1].fPts[1].fY)); + SkASSERT(between(dst[0].fPts[2].fY, dst[1].fPts[1].fY, endY)); + } --level; pts = subdivide(dst[0], pts, level); return subdivide(dst[1], pts, level); @@ -1170,8 +1209,32 @@ static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) { int SkConic::chopIntoQuadsPOW2(SkPoint pts[], int pow2) const { SkASSERT(pow2 >= 0); *pts = fPts[0]; - SkDEBUGCODE(SkPoint* endPts =) subdivide(*this, pts + 1, pow2); - SkASSERT(endPts - pts == (2 * (1 << pow2) + 1)); + SkDEBUGCODE(SkPoint* endPts); + if (pow2 == kMaxConicToQuadPOW2) { // If an extreme weight generates many quads ... + SkConic dst[2]; + this->chop(dst); + // check to see if the first chop generates a pair of lines + if (dst[0].fPts[1].equalsWithinTolerance(dst[0].fPts[2]) + && dst[1].fPts[0].equalsWithinTolerance(dst[1].fPts[1])) { + pts[1] = pts[2] = pts[3] = dst[0].fPts[1]; // set ctrl == end to make lines + pts[4] = dst[1].fPts[2]; + pow2 = 1; + SkDEBUGCODE(endPts = &pts[5]); + goto commonFinitePtCheck; + } + } + SkDEBUGCODE(endPts = ) subdivide(*this, pts + 1, pow2); +commonFinitePtCheck: + const int quadCount = 1 << pow2; + const int ptCount = 2 * quadCount + 1; + SkASSERT(endPts - pts == ptCount); + if (!SkPointsAreFinite(pts, ptCount)) { + // if we generated a non-finite, pin ourselves to the middle of the hull, + // as our first and last are already on the first/last pts of the hull. + for (int i = 1; i < ptCount - 1; ++i) { + pts[i] = fPts[1]; + } + } return 1 << pow2; } @@ -1186,7 +1249,10 @@ bool SkConic::findYExtrema(SkScalar* t) const { bool SkConic::chopAtXExtrema(SkConic dst[2]) const { SkScalar t; if (this->findXExtrema(&t)) { - this->chopAt(t, dst); + if (!this->chopAt(t, dst)) { + // if chop can't return finite values, don't chop + return false; + } // now clean-up the middle, since we know t was meant to be at // an X-extrema SkScalar value = dst[0].fPts[2].fX; @@ -1201,7 +1267,10 @@ bool SkConic::chopAtXExtrema(SkConic dst[2]) const { bool SkConic::chopAtYExtrema(SkConic dst[2]) const { SkScalar t; if (this->findYExtrema(&t)) { - this->chopAt(t, dst); + if (!this->chopAt(t, dst)) { + // if chop can't return finite values, don't chop + return false; + } // now clean-up the middle, since we know t was meant to be at // an Y-extrema SkScalar value = dst[0].fPts[2].fY; @@ -1330,8 +1399,10 @@ int SkConic::BuildUnitArc(const SkVector& uStart, const SkVector& uStop, SkRotat // const SkScalar cosThetaOver2 = SkScalarSqrt((1 + dot) / 2); offCurve.setLength(SkScalarInvert(cosThetaOver2)); - dst[conicCount].set(lastQ, offCurve, finalP, cosThetaOver2); - conicCount += 1; + if (!lastQ.equalsWithinTolerance(offCurve)) { + dst[conicCount].set(lastQ, offCurve, finalP, cosThetaOver2); + conicCount += 1; + } } // now handle counter-clockwise and the initial unitStart rotation diff --git a/gfx/skia/skia/src/core/SkGeometry.h b/gfx/skia/skia/src/core/SkGeometry.h index 15f1e55195a9..55d763b967c5 100644 --- a/gfx/skia/skia/src/core/SkGeometry.h +++ b/gfx/skia/skia/src/core/SkGeometry.h @@ -215,7 +215,7 @@ struct SkConic { * be used. */ void evalAt(SkScalar t, SkPoint* pos, SkVector* tangent = nullptr) const; - void chopAt(SkScalar t, SkConic dst[2]) const; + bool SK_WARN_UNUSED_RESULT chopAt(SkScalar t, SkConic dst[2]) const; void chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const; void chop(SkConic dst[2]) const; @@ -235,7 +235,7 @@ struct SkConic { * Chop this conic into N quads, stored continguously in pts[], where * N = 1 << pow2. The amount of storage needed is (1 + 2 * N) */ - int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const; + int SK_WARN_UNUSED_RESULT chopIntoQuadsPOW2(SkPoint pts[], int pow2) const; bool findXExtrema(SkScalar* t) const; bool findYExtrema(SkScalar* t) const; @@ -384,7 +384,7 @@ public: int pow2 = conic.computeQuadPOW2(tol); fQuadCount = 1 << pow2; SkPoint* pts = fStorage.reset(1 + 2 * fQuadCount); - conic.chopIntoQuadsPOW2(pts, pow2); + fQuadCount = conic.chopIntoQuadsPOW2(pts, pow2); return pts; } diff --git a/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp index ac37073eb311..21c4d16c4af7 100644 --- a/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp +++ b/gfx/skia/skia/src/core/SkGlobalInitialization_core.cpp @@ -14,10 +14,11 @@ #include "SkFlattenable.h" #include "SkImageShader.h" #include "SkLocalMatrixShader.h" +#include "SkMatrixImageFilter.h" #include "SkOnce.h" #include "SkPathEffect.h" #include "SkPictureShader.h" -#include "SkMatrixImageFilter.h" +#include "SkRecordedDrawable.h" #include "SkXfermode.h" /* @@ -28,12 +29,11 @@ */ void SkFlattenable::PrivateInitializer::InitCore() { // Shader - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBitmapProcShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorFilterShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColorShader) + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkColor4Shader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkComposeShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmptyShader) - SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLocalMatrixShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPictureShader) @@ -46,14 +46,19 @@ void SkFlattenable::PrivateInitializer::InitCore() { // ColorFilter SkColorFilter::InitializeFlattenables(); + SkShader::InitializeFlattenables(); + // Xfermode SkXfermode::InitializeFlattenables(); + // Drawable + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRecordedDrawable) + // Now initialize any optional/additional effects (implemented in src/ports) InitEffects(); }; -SK_DECLARE_STATIC_ONCE(once); void SkFlattenable::InitializeFlattenablesIfNeeded() { - SkOnce(&once, SkFlattenable::PrivateInitializer::InitCore); + static SkOnce once; + once(SkFlattenable::PrivateInitializer::InitCore); } diff --git a/gfx/skia/skia/src/core/SkGlyphCache.cpp b/gfx/skia/skia/src/core/SkGlyphCache.cpp index 241854eb5a60..a8eaa667a58a 100644 --- a/gfx/skia/skia/src/core/SkGlyphCache.cpp +++ b/gfx/skia/skia/src/core/SkGlyphCache.cpp @@ -8,7 +8,7 @@ #include "SkGlyphCache.h" #include "SkGlyphCache_Globals.h" #include "SkGraphics.h" -#include "SkOncePtr.h" +#include "SkOnce.h" #include "SkPath.h" #include "SkTemplates.h" #include "SkTraceMemoryDump.h" @@ -23,9 +23,12 @@ const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache"; } // namespace // Returns the shared globals -SK_DECLARE_STATIC_ONCE_PTR(SkGlyphCache_Globals, globals); static SkGlyphCache_Globals& get_globals() { - return *globals.get([]{ return new SkGlyphCache_Globals; }); + static SkOnce once; + static SkGlyphCache_Globals* globals; + + once([]{ globals = new SkGlyphCache_Globals; }); + return *globals; } /////////////////////////////////////////////////////////////////////////////// @@ -88,12 +91,17 @@ SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(PackedUnicharID packed uint16_t SkGlyphCache::unicharToGlyph(SkUnichar charCode) { VALIDATE(); PackedUnicharID packedUnicharID = SkGlyph::MakeID(charCode); - const CharGlyphRec& rec = *this->getCharGlyphRec(packedUnicharID); + CharGlyphRec* rec = this->getCharGlyphRec(packedUnicharID); - if (rec.fPackedUnicharID == packedUnicharID) { - return SkGlyph::ID2Code(rec.fPackedGlyphID); + if (rec->fPackedUnicharID == packedUnicharID) { + // The glyph exists in the unichar to glyph mapping cache. Return it. + return SkGlyph::ID2Code(rec->fPackedGlyphID); } else { - return fScalerContext->charToGlyphID(charCode); + // The glyph is not in the unichar to glyph mapping cache. Insert it. + rec->fPackedUnicharID = packedUnicharID; + uint16_t glyphID = fScalerContext->charToGlyphID(charCode); + rec->fPackedGlyphID = SkGlyph::MakeID(glyphID); + return glyphID; } } @@ -467,7 +475,20 @@ void SkGlyphCache::invokeAndRemoveAuxProcs() { /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -typedef SkAutoTExclusive Exclusive; +size_t SkGlyphCache_Globals::getTotalMemoryUsed() const { + SkAutoExclusive ac(fLock); + return fTotalMemoryUsed; +} + +int SkGlyphCache_Globals::getCacheCountUsed() const { + SkAutoExclusive ac(fLock); + return fCacheCount; +} + +int SkGlyphCache_Globals::getCacheCountLimit() const { + SkAutoExclusive ac(fLock); + return fCacheCountLimit; +} size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { static const size_t minLimit = 256 * 1024; @@ -475,7 +496,7 @@ size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { newLimit = minLimit; } - Exclusive ac(fLock); + SkAutoExclusive ac(fLock); size_t prevLimit = fCacheSizeLimit; fCacheSizeLimit = newLimit; @@ -483,12 +504,17 @@ size_t SkGlyphCache_Globals::setCacheSizeLimit(size_t newLimit) { return prevLimit; } +size_t SkGlyphCache_Globals::getCacheSizeLimit() const { + SkAutoExclusive ac(fLock); + return fCacheSizeLimit; +} + int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { if (newCount < 0) { newCount = 0; } - Exclusive ac(fLock); + SkAutoExclusive ac(fLock); int prevCount = fCacheCountLimit; fCacheCountLimit = newCount; @@ -497,7 +523,7 @@ int SkGlyphCache_Globals::setCacheCountLimit(int newCount) { } void SkGlyphCache_Globals::purgeAll() { - Exclusive ac(fLock); + SkAutoExclusive ac(fLock); this->internalPurge(fTotalMemoryUsed); } @@ -508,24 +534,35 @@ void SkGlyphCache_Globals::purgeAll() { - call a fontscaler (which might call into the cache) */ SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, - const SkDescriptor* desc, - bool (*proc)(const SkGlyphCache*, void*), - void* context) { + const SkScalerContextEffects& effects, + const SkDescriptor* desc, + bool (*proc)(const SkGlyphCache*, void*), + void* context) { if (!typeface) { typeface = SkTypeface::GetDefaultTypeface(); } SkASSERT(desc); + // Precondition: the typeface id must be the fFontID in the descriptor + SkDEBUGCODE( + uint32_t length = 0; + const SkScalerContext::Rec* rec = static_cast( + desc->findEntry(kRec_SkDescriptorTag, &length)); + SkASSERT(rec); + SkASSERT(length == sizeof(*rec)); + SkASSERT(typeface->uniqueID() == rec->fFontID); + ) + SkGlyphCache_Globals& globals = get_globals(); SkGlyphCache* cache; { - Exclusive ac(globals.fLock); + SkAutoExclusive ac(globals.fLock); globals.validate(); for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) { - if (cache->fDesc->equals(*desc)) { + if (*cache->fDesc == *desc) { globals.internalDetachCache(cache); if (!proc(cache, context)) { globals.internalAttachCacheToHead(cache); @@ -542,10 +579,10 @@ SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface, { // pass true the first time, to notice if the scalercontext failed, // so we can try the purge. - SkScalerContext* ctx = typeface->createScalerContext(desc, true); + SkScalerContext* ctx = typeface->createScalerContext(effects, desc, true); if (!ctx) { get_globals().purgeAll(); - ctx = typeface->createScalerContext(desc, false); + ctx = typeface->createScalerContext(effects, desc, false); SkASSERT(ctx); } cache = new SkGlyphCache(typeface, desc, ctx); @@ -633,7 +670,7 @@ void SkGlyphCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) { void SkGlyphCache::VisitAll(Visitor visitor, void* context) { SkGlyphCache_Globals& globals = get_globals(); - Exclusive ac(globals.fLock); + SkAutoExclusive ac(globals.fLock); SkGlyphCache* cache; globals.validate(); @@ -646,7 +683,7 @@ void SkGlyphCache::VisitAll(Visitor visitor, void* context) { /////////////////////////////////////////////////////////////////////////////// void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) { - Exclusive ac(fLock); + SkAutoExclusive ac(fLock); this->validate(); cache->validate(); diff --git a/gfx/skia/skia/src/core/SkGlyphCache.h b/gfx/skia/skia/src/core/SkGlyphCache.h index 2b5262ba5eb9..84a32eb3ef0b 100644 --- a/gfx/skia/skia/src/core/SkGlyphCache.h +++ b/gfx/skia/skia/src/core/SkGlyphCache.h @@ -129,7 +129,7 @@ public: If the proc() returns true, detach the cache and return it, otherwise leave it and return nullptr. */ - static SkGlyphCache* VisitCache(SkTypeface*, const SkDescriptor* desc, + static SkGlyphCache* VisitCache(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*, bool (*proc)(const SkGlyphCache*, void*), void* context); @@ -146,8 +146,9 @@ public: more than 1 strike for the same descriptor, but that will eventually get purged, and the win is that different thread will never block each other while a strike is being used. */ - static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkDescriptor* desc) { - return VisitCache(typeface, desc, DetachProc, nullptr); + static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkScalerContextEffects& effects, + const SkDescriptor* desc) { + return VisitCache(typeface, effects, desc, DetachProc, nullptr); } static void Dump(); @@ -226,8 +227,7 @@ private: SkGlyph* lookupByChar(SkUnichar id, MetricsType type, SkFixed x = 0, SkFixed y = 0); // Return a new SkGlyph for the glyph ID and subpixel position id. Limit the amount - // of work - // using type. + // of work using type. SkGlyph* allocateNewGlyph(PackedGlyphID packedGlyphID, MetricsType type); static bool DetachProc(const SkGlyphCache*, void*) { return true; } @@ -237,8 +237,6 @@ private: void invokeAndRemoveAuxProcs(); - inline static SkGlyphCache* FindTail(SkGlyphCache* head); - static void OffsetResults(const SkGlyph::Intercept* intercept, SkScalar scale, SkScalar xPos, SkScalar* array, int* count); static void AddInterval(SkScalar val, SkGlyph::Intercept* intercept); @@ -276,22 +274,25 @@ class SkAutoGlyphCache : public std::unique_ptrget(); } - + SkAutoGlyphCache() = default; SkAutoGlyphCache(SkGlyphCache* cache) : INHERITED(cache) {} - SkAutoGlyphCache(SkTypeface* typeface, const SkDescriptor* desc) - : INHERITED(SkGlyphCache::DetachCache(typeface, desc)) + SkAutoGlyphCache(SkTypeface* typeface, const SkScalerContextEffects& effects, + const SkDescriptor* desc) + : INHERITED(SkGlyphCache::DetachCache(typeface, effects, desc)) {} /** deprecated: always enables fake gamma */ SkAutoGlyphCache(const SkPaint& paint, const SkSurfaceProps* surfaceProps, const SkMatrix* matrix) - : INHERITED(paint.detachCache(surfaceProps, SkPaint::FakeGamma::On, matrix)) + : INHERITED(paint.detachCache(surfaceProps, + SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags, + matrix)) {} SkAutoGlyphCache(const SkPaint& paint, const SkSurfaceProps* surfaceProps, - SkPaint::FakeGamma fakeGamma, + uint32_t scalerContextFlags, const SkMatrix* matrix) - : INHERITED(paint.detachCache(surfaceProps, fakeGamma, matrix)) + : INHERITED(paint.detachCache(surfaceProps, scalerContextFlags, matrix)) {} private: using INHERITED = std::unique_ptr; @@ -302,7 +303,7 @@ public: SkAutoGlyphCacheNoGamma(const SkPaint& paint, const SkSurfaceProps* surfaceProps, const SkMatrix* matrix) - : SkAutoGlyphCache(paint, surfaceProps, SkPaint::FakeGamma::Off, matrix) + : SkAutoGlyphCache(paint, surfaceProps, SkPaint::kNone_ScalerContextFlags, matrix) {} }; #define SkAutoGlyphCache(...) SK_REQUIRE_LOCAL_VAR(SkAutoGlyphCache) diff --git a/gfx/skia/skia/src/core/SkGlyphCache_Globals.h b/gfx/skia/skia/src/core/SkGlyphCache_Globals.h index e1825a2f0f90..4d7fe22d807d 100644 --- a/gfx/skia/skia/src/core/SkGlyphCache_Globals.h +++ b/gfx/skia/skia/src/core/SkGlyphCache_Globals.h @@ -42,13 +42,13 @@ public: } } - SkSpinlock fLock; + mutable SkSpinlock fLock; SkGlyphCache* internalGetHead() const { return fHead; } SkGlyphCache* internalGetTail() const; - size_t getTotalMemoryUsed() const { return fTotalMemoryUsed; } - int getCacheCountUsed() const { return fCacheCount; } + size_t getTotalMemoryUsed() const; + int getCacheCountUsed() const; #ifdef SK_DEBUG void validate() const; @@ -56,19 +56,12 @@ public: void validate() const {} #endif - int getCacheCountLimit() const { return fCacheCountLimit; } + int getCacheCountLimit() const; int setCacheCountLimit(int limit); - size_t getCacheSizeLimit() const { return fCacheSizeLimit; } + size_t getCacheSizeLimit() const; size_t setCacheSizeLimit(size_t limit); - // returns true if this cache is over-budget either due to size limit - // or count limit. - bool isOverBudget() const { - return fCacheCount > fCacheCountLimit || - fTotalMemoryUsed > fCacheSizeLimit; - } - void purgeAll(); // does not change budget // call when a glyphcache is available for caching (i.e. not in use) diff --git a/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp b/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp new file mode 100644 index 000000000000..ec3b0a99091a --- /dev/null +++ b/gfx/skia/skia/src/core/SkGpuBlurUtils.cpp @@ -0,0 +1,383 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkGpuBlurUtils.h" + +#include "SkRect.h" + +#if SK_SUPPORT_GPU +#include "effects/GrConvolutionEffect.h" +#include "effects/GrMatrixConvolutionEffect.h" +#include "GrContext.h" +#include "GrCaps.h" +#include "GrDrawContext.h" +#include "GrFixedClip.h" + +#define MAX_BLUR_SIGMA 4.0f + +static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) { + rect->fLeft = SkScalarFloorToInt(SkScalarMul(rect->fLeft, xScale)); + rect->fTop = SkScalarFloorToInt(SkScalarMul(rect->fTop, yScale)); + rect->fRight = SkScalarCeilToInt(SkScalarMul(rect->fRight, xScale)); + rect->fBottom = SkScalarCeilToInt(SkScalarMul(rect->fBottom, yScale)); +} + +static void scale_irect(SkIRect* rect, int xScale, int yScale) { + rect->fLeft *= xScale; + rect->fTop *= yScale; + rect->fRight *= xScale; + rect->fBottom *= yScale; +} + +#ifdef SK_DEBUG +static inline int is_even(int x) { return !(x & 1); } +#endif + +static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) { + if (xAxis) { + SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight)); + rect->fLeft /= 2; + rect->fRight /= 2; + } + if (yAxis) { + SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom)); + rect->fTop /= 2; + rect->fBottom /= 2; + } +} + +static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) { + *scaleFactor = 1; + while (sigma > MAX_BLUR_SIGMA) { + *scaleFactor *= 2; + sigma *= 0.5f; + if (*scaleFactor > maxTextureSize) { + *scaleFactor = maxTextureSize; + sigma = MAX_BLUR_SIGMA; + } + } + *radius = static_cast(ceilf(sigma * 3.0f)); + SkASSERT(*radius <= GrConvolutionEffect::kMaxKernelRadius); + return sigma; +} + +static void convolve_gaussian_1d(GrDrawContext* drawContext, + const GrClip& clip, + const SkIRect& dstRect, + const SkIPoint& srcOffset, + GrTexture* texture, + Gr1DKernelEffect::Direction direction, + int radius, + float sigma, + bool useBounds, + float bounds[2]) { + GrPaint paint; + paint.setGammaCorrect(drawContext->isGammaCorrect()); + sk_sp conv(GrConvolutionEffect::MakeGaussian( + texture, direction, radius, sigma, useBounds, bounds)); + paint.addColorFragmentProcessor(std::move(conv)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), + -SkIntToScalar(srcOffset.y())); + drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), + SkRect::Make(dstRect), localMatrix); +} + +static void convolve_gaussian_2d(GrDrawContext* drawContext, + const GrClip& clip, + const SkIRect& dstRect, + const SkIPoint& srcOffset, + GrTexture* texture, + int radiusX, + int radiusY, + SkScalar sigmaX, + SkScalar sigmaY, + const SkIRect* srcBounds) { + SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), + -SkIntToScalar(srcOffset.y())); + SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); + SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); + GrPaint paint; + paint.setGammaCorrect(drawContext->isGammaCorrect()); + SkIRect bounds = srcBounds ? *srcBounds : SkIRect::EmptyIRect(); + + sk_sp conv(GrMatrixConvolutionEffect::MakeGaussian( + texture, bounds, size, 1.0, 0.0, kernelOffset, + srcBounds ? GrTextureDomain::kDecal_Mode : GrTextureDomain::kIgnore_Mode, + true, sigmaX, sigmaY)); + paint.addColorFragmentProcessor(std::move(conv)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), + SkRect::Make(dstRect), localMatrix); +} + +static void convolve_gaussian(GrDrawContext* drawContext, + const GrClip& clip, + const SkIRect& srcRect, + GrTexture* texture, + Gr1DKernelEffect::Direction direction, + int radius, + float sigma, + const SkIRect* srcBounds, + const SkIPoint& srcOffset) { + float bounds[2] = { 0.0f, 1.0f }; + SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); + if (!srcBounds) { + convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, + direction, radius, sigma, false, bounds); + return; + } + SkIRect midRect = *srcBounds, leftRect, rightRect; + midRect.offset(srcOffset); + SkIRect topRect, bottomRect; + if (direction == Gr1DKernelEffect::kX_Direction) { + bounds[0] = SkIntToFloat(srcBounds->left()) / texture->width(); + bounds[1] = SkIntToFloat(srcBounds->right()) / texture->width(); + topRect = SkIRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()); + bottomRect = SkIRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom()); + midRect.inset(radius, 0); + leftRect = SkIRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bottom()); + rightRect = + SkIRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), midRect.bottom()); + dstRect.fTop = midRect.top(); + dstRect.fBottom = midRect.bottom(); + } else { + bounds[0] = SkIntToFloat(srcBounds->top()) / texture->height(); + bounds[1] = SkIntToFloat(srcBounds->bottom()) / texture->height(); + topRect = SkIRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()); + bottomRect = SkIRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom()); + midRect.inset(0, radius); + leftRect = SkIRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.top()); + rightRect = + SkIRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height()); + dstRect.fLeft = midRect.left(); + dstRect.fRight = midRect.right(); + } + if (!topRect.isEmpty()) { + drawContext->clear(&topRect, 0, false); + } + + if (!bottomRect.isEmpty()) { + drawContext->clear(&bottomRect, 0, false); + } + if (midRect.isEmpty()) { + // Blur radius covers srcBounds; use bounds over entire draw + convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture, + direction, radius, sigma, true, bounds); + } else { + // Draw right and left margins with bounds; middle without. + convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture, + direction, radius, sigma, true, bounds); + convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture, + direction, radius, sigma, true, bounds); + convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture, + direction, radius, sigma, false, bounds); + } +} + +namespace SkGpuBlurUtils { + +sk_sp GaussianBlur(GrContext* context, + GrTexture* origSrc, + sk_sp colorSpace, + const SkIRect& dstBounds, + const SkIRect* srcBounds, + float sigmaX, + float sigmaY, + SkBackingFit fit) { + SkASSERT(context); + SkIRect clearRect; + int scaleFactorX, radiusX; + int scaleFactorY, radiusY; + int maxTextureSize = context->caps()->maxTextureSize(); + sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); + sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); + SkASSERT(sigmaX || sigmaY); + + SkIPoint srcOffset = SkIPoint::Make(-dstBounds.x(), -dstBounds.y()); + SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height()); + SkIRect localSrcBounds; + SkIRect srcRect; + if (srcBounds) { + srcRect = localSrcBounds = *srcBounds; + srcRect.offset(srcOffset); + srcBounds = &localSrcBounds; + } else { + srcRect = localDstBounds; + } + + scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); + scale_irect(&srcRect, scaleFactorX, scaleFactorY); + + // setup new clip + GrFixedClip clip(localDstBounds); + + sk_sp srcTexture(sk_ref_sp(origSrc)); + + SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || + kRGBA_8888_GrPixelConfig == srcTexture->config() || + kSRGBA_8888_GrPixelConfig == srcTexture->config() || + kSBGRA_8888_GrPixelConfig == srcTexture->config() || + kRGBA_half_GrPixelConfig == srcTexture->config() || + kAlpha_8_GrPixelConfig == srcTexture->config()); + + const int width = dstBounds.width(); + const int height = dstBounds.height(); + const GrPixelConfig config = srcTexture->config(); + + sk_sp dstDrawContext(context->makeDrawContext(fit, + width, height, config, colorSpace, + 0, kDefault_GrSurfaceOrigin)); + if (!dstDrawContext) { + return nullptr; + } + + // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just + // launch a single non separable kernel vs two launches + if (sigmaX > 0.0f && sigmaY > 0.0f && + (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) { + // We shouldn't be scaling because this is a small size blur + SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); + + convolve_gaussian_2d(dstDrawContext.get(), clip, localDstBounds, srcOffset, + srcTexture.get(), radiusX, radiusY, sigmaX, sigmaY, srcBounds); + + return dstDrawContext; + } + + sk_sp tmpDrawContext(context->makeDrawContext(fit, + width, height, config, colorSpace, + 0, kDefault_GrSurfaceOrigin)); + if (!tmpDrawContext) { + return nullptr; + } + + sk_sp srcDrawContext; + + SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); + + for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { + GrPaint paint; + paint.setGammaCorrect(dstDrawContext->isGammaCorrect()); + SkMatrix matrix; + matrix.setIDiv(srcTexture->width(), srcTexture->height()); + SkIRect dstRect(srcRect); + if (srcBounds && i == 1) { + SkRect domain; + matrix.mapRect(&domain, SkRect::Make(*srcBounds)); + domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f, + (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f); + sk_sp fp(GrTextureDomainEffect::Make( + srcTexture.get(), + nullptr, + matrix, + domain, + GrTextureDomain::kDecal_Mode, + GrTextureParams::kBilerp_FilterMode)); + paint.addColorFragmentProcessor(std::move(fp)); + srcRect.offset(-srcOffset); + srcOffset.set(0, 0); + } else { + GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); + paint.addColorTextureProcessor(srcTexture.get(), nullptr, matrix, params); + } + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); + + dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); + + srcDrawContext = dstDrawContext; + srcRect = dstRect; + srcTexture = srcDrawContext->asTexture(); + dstDrawContext.swap(tmpDrawContext); + localSrcBounds = srcRect; + } + + srcRect = localDstBounds; + scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); + if (sigmaX > 0.0f) { + if (scaleFactorX > 1) { + SkASSERT(srcDrawContext); + + // Clear out a radius to the right of the srcRect to prevent the + // X convolution from reading garbage. + clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, + radiusX, srcRect.height()); + srcDrawContext->clear(&clearRect, 0x0, false); + } + + convolve_gaussian(dstDrawContext.get(), clip, srcRect, + srcTexture.get(), Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, + srcBounds, srcOffset); + srcDrawContext = dstDrawContext; + srcTexture = srcDrawContext->asTexture(); + srcRect.offsetTo(0, 0); + dstDrawContext.swap(tmpDrawContext); + localSrcBounds = srcRect; + srcOffset.set(0, 0); + } + + if (sigmaY > 0.0f) { + if (scaleFactorY > 1 || sigmaX > 0.0f) { + SkASSERT(srcDrawContext); + + // Clear out a radius below the srcRect to prevent the Y + // convolution from reading garbage. + clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, + srcRect.width(), radiusY); + srcDrawContext->clear(&clearRect, 0x0, false); + } + + convolve_gaussian(dstDrawContext.get(), clip, srcRect, + srcTexture.get(), Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, + srcBounds, srcOffset); + + srcDrawContext = dstDrawContext; + srcRect.offsetTo(0, 0); + dstDrawContext.swap(tmpDrawContext); + } + + SkASSERT(srcDrawContext); + srcTexture = nullptr; // we don't use this from here on out + + if (scaleFactorX > 1 || scaleFactorY > 1) { + // Clear one pixel to the right and below, to accommodate bilinear upsampling. + clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); + srcDrawContext->clear(&clearRect, 0x0, false); + clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height()); + srcDrawContext->clear(&clearRect, 0x0, false); + + SkMatrix matrix; + matrix.setIDiv(srcDrawContext->width(), srcDrawContext->height()); + + GrPaint paint; + paint.setGammaCorrect(dstDrawContext->isGammaCorrect()); + // FIXME: this should be mitchell, not bilinear. + GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); + sk_sp tex(srcDrawContext->asTexture()); + paint.addColorTextureProcessor(tex.get(), nullptr, matrix, params); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + SkIRect dstRect(srcRect); + scale_irect(&dstRect, scaleFactorX, scaleFactorY); + + dstDrawContext->fillRectToRect(clip, paint, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); + + srcDrawContext = dstDrawContext; + srcRect = dstRect; + dstDrawContext.swap(tmpDrawContext); + } + + return srcDrawContext; +} + +} + +#endif + diff --git a/gfx/skia/skia/src/core/SkGpuBlurUtils.h b/gfx/skia/skia/src/core/SkGpuBlurUtils.h new file mode 100644 index 000000000000..a12a08873c3a --- /dev/null +++ b/gfx/skia/skia/src/core/SkGpuBlurUtils.h @@ -0,0 +1,46 @@ +/* + * 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 SkGpuBlurUtils_DEFINED +#define SkGpuBlurUtils_DEFINED + +#if SK_SUPPORT_GPU +#include "GrDrawContext.h" + +class GrContext; +class GrTexture; + +struct SkRect; + +namespace SkGpuBlurUtils { + /** + * Applies a 2D Gaussian blur to a given texture. The blurred result is returned + * as a drawContext in case the caller wishes to future draw into the result. + * Note: one of sigmaX and sigmaY should be non-zero! + * @param context The GPU context + * @param srcTexture The source texture to be blurred. + * @param colorSpace Color space of the source (used for the drawContext result, too). + * @param dstBounds The destination bounds, relative to the source texture. + * @param srcBounds The source bounds, relative to the source texture. If non-null, + * no pixels will be sampled outside of this rectangle. + * @param sigmaX The blur's standard deviation in X. + * @param sigmaY The blur's standard deviation in Y. + * @param fit backing fit for the returned draw context + * @return The drawContext containing the blurred result. + */ + sk_sp GaussianBlur(GrContext* context, + GrTexture* srcTexture, + sk_sp colorSpace, + const SkIRect& dstBounds, + const SkIRect* srcBounds, + float sigmaX, + float sigmaY, + SkBackingFit fit = SkBackingFit::kApprox); +}; + +#endif +#endif diff --git a/gfx/skia/skia/src/core/SkGraphics.cpp b/gfx/skia/skia/src/core/SkGraphics.cpp index 0273139ad778..01b1432ef034 100644 --- a/gfx/skia/skia/src/core/SkGraphics.cpp +++ b/gfx/skia/skia/src/core/SkGraphics.cpp @@ -10,6 +10,7 @@ #include "SkBlitter.h" #include "SkCanvas.h" +#include "SkCpu.h" #include "SkGeometry.h" #include "SkGlyphCache.h" #include "SkImageFilter.h" @@ -21,7 +22,6 @@ #include "SkPixelRef.h" #include "SkRefCnt.h" #include "SkResourceCache.h" -#include "SkRTConf.h" #include "SkScalerContext.h" #include "SkShader.h" #include "SkStream.h" @@ -46,16 +46,8 @@ void SkGraphics::GetVersion(int32_t* major, int32_t* minor, int32_t* patch) { void SkGraphics::Init() { // SkGraphics::Init() must be thread-safe and idempotent. + SkCpu::CacheRuntimeFeatures(); SkOpts::Init(); - -#ifdef SK_DEVELOPER - skRTConfRegistry().possiblyDumpFile(); - skRTConfRegistry().validate(); - if (skRTConfRegistry().hasNonDefault()) { - SkDebugf("Non-default runtime configuration options:\n"); - skRTConfRegistry().printNonDefault(); - } -#endif } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkHalf.h b/gfx/skia/skia/src/core/SkHalf.h index 5f5575ae1aea..dd978a2347e7 100644 --- a/gfx/skia/skia/src/core/SkHalf.h +++ b/gfx/skia/skia/src/core/SkHalf.h @@ -16,18 +16,20 @@ // only used for storage typedef uint16_t SkHalf; -#define SK_HalfMin 0x0400 // 2^-24 (minimum positive normal value) -#define SK_HalfMax 0x7bff // 65504 -#define SK_HalfEpsilon 0x1400 // 2^-10 +static constexpr uint16_t SK_HalfMin = 0x0400; // 2^-24 (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 SkFloatToHalf(float f); -// Convert between half and single precision floating point, but pull any dirty -// trick we can to make it faster as long as it's correct enough for values in [0,1]. -static inline Sk4f SkHalfToFloat_01(uint64_t); -static inline uint64_t SkFloatToHalf_01(const Sk4f&); +// 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 ~~~~~~~~~~~~~~ // @@ -36,89 +38,51 @@ static inline uint64_t SkFloatToHalf_01(const Sk4f&); // GCC 4.9 lacks the intrinsics to use ARMv8 f16<->f32 instructions, so we use inline assembly. -static inline Sk4f SkHalfToFloat_01(uint64_t hs) { +static inline Sk4f SkHalfToFloat_finite_ftz(const Sk4h& hs) { #if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64) float32x4_t fs; - asm ("fmov %d[fs], %[hs] \n" // vcreate_f16(hs) - "fcvtl %[fs].4s, %[fs].4h \n" // vcvt_f32_f16(...) + asm ("fcvtl %[fs].4s, %[hs].4h \n" // vcvt_f32_f16(...) : [fs] "=w" (fs) // =w: write-only NEON register - : [hs] "r" (hs)); // r: read-only 64-bit general register + : [hs] "w" (hs.fVec)); // w: read-only NEON register return fs; - -#elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) - // NEON makes this pretty easy: - // - denormals are 10-bit * 2^-14 == 24-bit fixed point; - // - handle normals the same way as in SSE: align mantissa, then rebias exponent. - uint32x4_t h = vmovl_u16(vcreate_u16(hs)), - is_denorm = vcltq_u32(h, vdupq_n_u32(1<<10)); - float32x4_t denorm = vcvtq_n_f32_u32(h, 24), - norm = vreinterpretq_f32_u32(vaddq_u32(vshlq_n_u32(h, 13), - vdupq_n_u32((127-15) << 23))); - return vbslq_f32(is_denorm, denorm, norm); - -#elif !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - // If our input is a normal 16-bit float, things are pretty easy: - // - shift left by 13 to put the mantissa in the right place; - // - the exponent is wrong, but it just needs to be rebiased; - // - re-bias the exponent from 15-bias to 127-bias by adding (127-15). - - // If our input is denormalized, we're going to do the same steps, plus a few more fix ups: - // - the input is h = K*2^-14, for some 10-bit fixed point K in [0,1); - // - by shifting left 13 and adding (127-15) to the exponent, we constructed the float value - // 2^-15*(1+K); - // - we'd need to subtract 2^-15 and multiply by 2 to get back to K*2^-14, or equivallently - // multiply by 2 then subtract 2^-14. - // - // - We'll work that multiply by 2 into the rebias, by adding 1 more to the exponent. - // - Conveniently, this leaves that rebias constant 2^-14, exactly what we want to subtract. - - __m128i h = _mm_unpacklo_epi16(_mm_loadl_epi64((const __m128i*)&hs), _mm_setzero_si128()); - const __m128i is_denorm = _mm_cmplt_epi32(h, _mm_set1_epi32(1<<10)); - - __m128i rebias = _mm_set1_epi32((127-15) << 23); - rebias = _mm_add_epi32(rebias, _mm_and_si128(is_denorm, _mm_set1_epi32(1<<23))); - - __m128i f = _mm_add_epi32(_mm_slli_epi32(h, 13), rebias); - return _mm_sub_ps(_mm_castsi128_ps(f), - _mm_castsi128_ps(_mm_and_si128(is_denorm, rebias))); #else - float fs[4]; - for (int i = 0; i < 4; i++) { - fs[i] = SkHalfToFloat(hs >> (i*16)); - } - return Sk4f::Load(fs); + 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 uint64_t SkFloatToHalf_01(const Sk4f& fs) { - uint64_t r; +static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t hs) { + return SkHalfToFloat_finite_ftz(Sk4h::Load(&hs)); +} + +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) - "fmov %[r], %d[vec] \n" // vst1_f16(&r, ...) - : [r] "=r" (r) // =r: write-only 64-bit general register - , [vec] "+w" (vec)); // +w: read-write NEON register - -// TODO: ARMv7 NEON float->half? - -#elif !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 - // Scale down from 127-bias to 15-bias, then cut off bottom 13 mantissa bits. - // This doesn't round, so it can be 1 bit too small. - const __m128 rebias = _mm_castsi128_ps(_mm_set1_epi32((127 - (127-15)) << 23)); - __m128i h = _mm_srli_epi32(_mm_castps_si128(_mm_mul_ps(fs.fVec, rebias)), 13); - _mm_storel_epi64((__m128i*)&r, _mm_packs_epi32(h,h)); - + : [vec] "+w" (vec)); // +w: read-write NEON register + return vreinterpret_u16_f32(vget_low_f32(vec)); #else - SkHalf hs[4]; - for (int i = 0; i < 4; i++) { - hs[i] = SkFloatToHalf(fs[i]); - } - r = (uint64_t)hs[3] << 48 - | (uint64_t)hs[2] << 32 - | (uint64_t)hs[1] << 16 - | (uint64_t)hs[0] << 0; + 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 - return r; } #endif diff --git a/gfx/skia/skia/src/core/SkImageCacherator.cpp b/gfx/skia/skia/src/core/SkImageCacherator.cpp index 7b5ff2267774..496ca74d9a18 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.cpp +++ b/gfx/skia/skia/src/core/SkImageCacherator.cpp @@ -25,6 +25,13 @@ #include "SkGrPriv.h" #endif +// Until we actually have codecs/etc. that can contain/support a GPU texture format +// skip this step, since for some generators, returning their encoded data as a SkData +// can be somewhat expensive, and this call doesn't indicate to the generator that we're +// only interested in GPU datas... +// see skbug.com/ 4971, 5128, ... +//#define SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR + SkImageCacherator* SkImageCacherator::NewFromGenerator(SkImageGenerator* gen, const SkIRect* subset) { if (!gen) { @@ -195,6 +202,7 @@ bool SkImageCacherator::lockAsBitmap(SkBitmap* bitmap, const SkImage* client, #if SK_SUPPORT_GPU +#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrSurfaceDesc desc) { const void* rawStart; GrPixelConfig config = GrIsCompressedTextureDataSupported(ctx, data, desc.fWidth, desc.fHeight, @@ -206,6 +214,7 @@ static GrTexture* load_compressed_into_texture(GrContext* ctx, SkData* data, GrS desc.fConfig = config; return ctx->textureProvider()->createTexture(desc, SkBudgeted::kYes, rawStart, 0); } +#endif class Generator_GrYUVProvider : public GrYUVProvider { SkImageGenerator* fGen; @@ -240,7 +249,8 @@ static GrTexture* set_key_and_return(GrTexture* tex, const GrUniqueKey& key) { */ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key, const SkImage* client, SkImage::CachingHint chint, - bool willBeMipped) { + bool willBeMipped, + SkSourceGammaTreatment gammaTreatment) { // Values representing the various texture lock paths we can take. Used for logging the path // taken to a histogram. enum LockTexturePath { @@ -276,8 +286,9 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key const GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(fInfo, *ctx->caps()); +#ifdef SK_SUPPORT_COMPRESSED_TEXTURES_IN_CACHERATOR // 3. Ask the generator to return a compressed form that the GPU might support - SkAutoTUnref data(this->refEncoded(ctx)); + sk_sp data(this->refEncoded(ctx)); if (data) { GrTexture* tex = load_compressed_into_texture(ctx, data, desc); if (tex) { @@ -286,16 +297,17 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key return set_key_and_return(tex, key); } } +#endif // 4. Ask the generator to return YUV planes, which the GPU can convert { ScopedGenerator generator(this); Generator_GrYUVProvider provider(generator); - GrTexture* tex = provider.refAsTexture(ctx, desc, true); + sk_sp tex = provider.refAsTexture(ctx, desc, true); if (tex) { SK_HISTOGRAM_ENUMERATION("LockTexturePath", kYUV_LockTexturePath, kLockTexturePathCount); - return set_key_and_return(tex, key); + return set_key_and_return(tex.release(), key); } } @@ -304,7 +316,7 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key if (this->tryLockAsBitmap(&bitmap, client, chint)) { GrTexture* tex = nullptr; if (willBeMipped) { - tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap); + tex = GrGenerateMipMapsAndUploadToTexture(ctx, bitmap, gammaTreatment); } if (!tex) { tex = GrUploadBitmapToTexture(ctx, bitmap); @@ -323,17 +335,20 @@ GrTexture* SkImageCacherator::lockTexture(GrContext* ctx, const GrUniqueKey& key /////////////////////////////////////////////////////////////////////////////////////////////////// GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams& params, + SkSourceGammaTreatment gammaTreatment, const SkImage* client, SkImage::CachingHint chint) { if (!ctx) { return nullptr; } - return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params); + return GrImageTextureMaker(ctx, this, client, chint).refTextureForParams(params, + gammaTreatment); } #else GrTexture* SkImageCacherator::lockAsTexture(GrContext* ctx, const GrTextureParams&, + SkSourceGammaTreatment gammaTreatment, const SkImage* client, SkImage::CachingHint) { return nullptr; } diff --git a/gfx/skia/skia/src/core/SkImageCacherator.h b/gfx/skia/skia/src/core/SkImageCacherator.h index 7e146182c7ac..3be69a578568 100644 --- a/gfx/skia/skia/src/core/SkImageCacherator.h +++ b/gfx/skia/skia/src/core/SkImageCacherator.h @@ -48,7 +48,8 @@ public: * * The caller is responsible for calling texture->unref() when they are done. */ - GrTexture* lockAsTexture(GrContext*, const GrTextureParams&, const SkImage* client, + GrTexture* lockAsTexture(GrContext*, const GrTextureParams&, + SkSourceGammaTreatment gammaTreatment, const SkImage* client, SkImage::CachingHint = SkImage::kAllow_CachingHint); /** @@ -75,7 +76,7 @@ private: // Returns the texture. If the cacherator is generating the texture and wants to cache it, // it should use the passed in key (if the key is valid). GrTexture* lockTexture(GrContext*, const GrUniqueKey& key, const SkImage* client, - SkImage::CachingHint, bool willBeMipped); + SkImage::CachingHint, bool willBeMipped, SkSourceGammaTreatment); #endif class ScopedGenerator { diff --git a/gfx/skia/skia/src/core/SkImageFilter.cpp b/gfx/skia/skia/src/core/SkImageFilter.cpp index 743dc2ad1afa..68183cc444b3 100644 --- a/gfx/skia/skia/src/core/SkImageFilter.cpp +++ b/gfx/skia/skia/src/core/SkImageFilter.cpp @@ -6,34 +6,23 @@ */ #include "SkImageFilter.h" -#include "SkImageFilterCacheKey.h" -#include "SkBitmap.h" -#include "SkBitmapDevice.h" -#include "SkChecksum.h" -#include "SkDevice.h" +#include "SkCanvas.h" +#include "SkFuzzLogging.h" +#include "SkImageFilterCache.h" #include "SkLocalMatrixImageFilter.h" #include "SkMatrixImageFilter.h" -#include "SkOncePtr.h" #include "SkReadBuffer.h" #include "SkRect.h" #include "SkSpecialImage.h" #include "SkSpecialSurface.h" -#include "SkTDynamicHash.h" -#include "SkTInternalLList.h" #include "SkValidationUtils.h" #include "SkWriteBuffer.h" #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrDrawContext.h" -#include "SkGrPixelRef.h" -#include "SkGr.h" -#endif - -#ifdef SK_BUILD_FOR_IOS - enum { kDefaultCacheSize = 2 * 1024 * 1024 }; -#else - enum { kDefaultCacheSize = 128 * 1024 * 1024 }; +#include "GrFixedClip.h" +#include "SkGrPriv.h" #endif #ifndef SK_IGNORE_TO_STRING @@ -122,12 +111,6 @@ void SkImageFilter::Common::allocInputs(int count) { fInputs.reset(count); } -void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) { - for (int i = 0; i < fInputs.count(); ++i) { - inputs[i] = fInputs[i].release(); - } -} - bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) { const int count = buffer.readInt(); if (!buffer.validate(count >= 0)) { @@ -137,6 +120,7 @@ bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) { return false; } + SkFUZZF(("allocInputs: %d\n", count)); this->allocInputs(count); for (int i = 0; i < count; i++) { if (buffer.readBool()) { @@ -163,67 +147,46 @@ bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) { /////////////////////////////////////////////////////////////////////////////////////////////////// +void SkImageFilter::init(sk_sp* inputs, + int inputCount, + const CropRect* cropRect) { + fCropRect = cropRect ? *cropRect : CropRect(SkRect(), 0x0); + + fInputs.reset(inputCount); + + for (int i = 0; i < inputCount; ++i) { + if (!inputs[i] || inputs[i]->usesSrcInput()) { + fUsesSrcInput = true; + } + fInputs[i] = inputs[i]; + } +} + SkImageFilter::SkImageFilter(sk_sp* inputs, int inputCount, const CropRect* cropRect) - : fInputCount(inputCount), - fInputs(new SkImageFilter*[inputCount]), - fUsesSrcInput(false), - fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)), - fUniqueID(next_image_filter_unique_id()) { - for (int i = 0; i < inputCount; ++i) { - if (nullptr == inputs[i] || inputs[i]->usesSrcInput()) { - fUsesSrcInput = true; - } - fInputs[i] = SkSafeRef(inputs[i].get()); - } -} - -SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect) - : fInputCount(inputCount), - fInputs(new SkImageFilter*[inputCount]), - fUsesSrcInput(false), - fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)), - fUniqueID(next_image_filter_unique_id()) { - for (int i = 0; i < inputCount; ++i) { - if (nullptr == inputs[i] || inputs[i]->usesSrcInput()) { - fUsesSrcInput = true; - } - fInputs[i] = SkSafeRef(inputs[i]); - } + : fUsesSrcInput(false) + , fUniqueID(next_image_filter_unique_id()) { + this->init(inputs, inputCount, cropRect); } SkImageFilter::~SkImageFilter() { - for (int i = 0; i < fInputCount; i++) { - SkSafeUnref(fInputs[i]); - } - delete[] fInputs; - Cache::Get()->purgeByKeys(fCacheKeys.begin(), fCacheKeys.count()); + SkImageFilterCache::Get()->purgeByKeys(fCacheKeys.begin(), fCacheKeys.count()); } SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) - : fUsesSrcInput(false) - , fUniqueID(next_image_filter_unique_id()) { + : fUsesSrcInput(false) + , fCropRect(SkRect(), 0x0) + , fUniqueID(next_image_filter_unique_id()) { Common common; if (common.unflatten(buffer, inputCount)) { - fCropRect = common.cropRect(); - fInputCount = common.inputCount(); - fInputs = new SkImageFilter* [fInputCount]; - common.detachInputs(fInputs); - for (int i = 0; i < fInputCount; ++i) { - if (nullptr == fInputs[i] || fInputs[i]->usesSrcInput()) { - fUsesSrcInput = true; - } - } - } else { - fInputCount = 0; - fInputs = nullptr; + this->init(common.inputs(), common.inputCount(), &common.cropRect()); } } void SkImageFilter::flatten(SkWriteBuffer& buffer) const { - buffer.writeInt(fInputCount); - for (int i = 0; i < fInputCount; i++) { + buffer.writeInt(fInputs.count()); + for (int i = 0; i < fInputs.count(); i++) { SkImageFilter* input = this->getInput(i); buffer.writeBool(input != nullptr); if (input != nullptr) { @@ -240,7 +203,7 @@ sk_sp SkImageFilter::filterImage(SkSpecialImage* src, const Cont uint32_t srcGenID = fUsesSrcInput ? src->uniqueID() : 0; const SkIRect srcSubset = fUsesSrcInput ? src->subset() : SkIRect::MakeWH(0, 0); - Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset); + SkImageFilterCacheKey key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID, srcSubset); if (context.cache()) { SkSpecialImage* result = context.cache()->get(key, offset); if (result) { @@ -249,6 +212,16 @@ sk_sp SkImageFilter::filterImage(SkSpecialImage* src, const Cont } sk_sp result(this->onFilterImage(src, context, offset)); + +#if SK_SUPPORT_GPU + if (src->isTextureBacked() && result && !result->isTextureBacked()) { + // Keep the result on the GPU - this is still required for some + // image filters that don't support GPU in all cases + GrContext* context = src->getContext(); + result = result->makeTextureImage(context); + } +#endif + if (result && context.cache()) { context.cache()->set(key, result.get(), *offset); SkAutoMutexAcquire mutex(fMutex); @@ -258,59 +231,6 @@ sk_sp SkImageFilter::filterImage(SkSpecialImage* src, const Cont return result; } -bool SkImageFilter::filterImageDeprecated(Proxy* proxy, const SkBitmap& src, - const Context& context, - SkBitmap* result, SkIPoint* offset) const { - SkASSERT(result); - SkASSERT(offset); - uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0; - Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), - srcGenID, SkIRect::MakeWH(0, 0)); - if (context.cache()) { - if (context.cache()->get(key, result, offset)) { - return true; - } - } - /* - * Give the proxy first shot at the filter. If it returns false, ask - * the filter to do it. - */ - if ((proxy && proxy->filterImage(this, src, context, result, offset)) || - this->onFilterImageDeprecated(proxy, src, context, result, offset)) { - if (context.cache()) { - context.cache()->set(key, *result, *offset); - SkAutoMutexAcquire mutex(fMutex); - fCacheKeys.push_back(key); - } - return true; - } - return false; -} - -bool SkImageFilter::filterInputDeprecated(int index, Proxy* proxy, const SkBitmap& src, - const Context& ctx, - SkBitmap* result, SkIPoint* offset) const { - SkImageFilter* input = this->getInput(index); - if (!input) { - return true; - } - - // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted. - sk_sp specialSrc(SkSpecialImage::internal_fromBM(proxy, src, nullptr)); - if (!specialSrc) { - return false; - } - - sk_sp tmp(input->onFilterImage(specialSrc.get(), - this->mapContext(ctx), - offset)); - if (!tmp) { - return false; - } - - return tmp->internal_getBM(result); -} - SkIRect SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { if (kReverse_MapDirection == direction) { @@ -326,11 +246,11 @@ SkIRect SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, } SkRect SkImageFilter::computeFastBounds(const SkRect& src) const { - if (0 == fInputCount) { + if (0 == this->countInputs()) { return src; } SkRect combinedBounds = this->getInput(0) ? this->getInput(0)->computeFastBounds(src) : src; - for (int i = 1; i < fInputCount; i++) { + for (int i = 1; i < this->countInputs(); i++) { SkImageFilter* input = this->getInput(i); if (input) { combinedBounds.join(input->computeFastBounds(src)); @@ -345,7 +265,7 @@ bool SkImageFilter::canComputeFastBounds() const { if (this->affectsTransparentBlack()) { return false; } - for (int i = 0; i < fInputCount; i++) { + for (int i = 0; i < this->countInputs(); i++) { SkImageFilter* input = this->getInput(i); if (input && !input->canComputeFastBounds()) { return false; @@ -354,91 +274,37 @@ bool SkImageFilter::canComputeFastBounds() const { return true; } -bool SkImageFilter::onFilterImageDeprecated(Proxy*, const SkBitmap&, const Context&, - SkBitmap*, SkIPoint*) const { - // Only classes that now use the new SkSpecialImage-based path will not have - // onFilterImageDeprecated methods. For those classes we should never be - // calling this method. - SkASSERT(0); - return false; -} - -// SkImageFilter-derived classes that do not yet have their own onFilterImage -// implementation convert back to calling the deprecated filterImage method -sk_sp SkImageFilter::onFilterImage(SkSpecialImage* src, const Context& ctx, - SkIPoint* offset) const { - SkBitmap srcBM, resultBM; - - if (!src->internal_getBM(&srcBM)) { - return nullptr; - } - - // This is the only valid call to the old filterImage path - if (!this->filterImageDeprecated(src->internal_getProxy(), srcBM, ctx, &resultBM, offset)) { - return nullptr; - } - - return SkSpecialImage::internal_fromBM(src->internal_getProxy(), resultBM, &src->props()); -} - -bool SkImageFilter::canFilterImageGPU() const { - return this->asFragmentProcessor(nullptr, nullptr, SkMatrix::I(), SkIRect()); -} - -bool SkImageFilter::filterImageGPUDeprecated(Proxy* proxy, const SkBitmap& src, const Context& ctx, - SkBitmap* result, SkIPoint* offset) const { #if SK_SUPPORT_GPU - SkBitmap input = src; - SkASSERT(fInputCount == 1); - SkIPoint srcOffset = SkIPoint::Make(0, 0); - if (!this->filterInputGPUDeprecated(0, proxy, src, ctx, &input, &srcOffset)) { - return false; - } - GrTexture* srcTexture = input.getTexture(); - SkIRect bounds; - if (!this->applyCropRectDeprecated(ctx, proxy, input, &srcOffset, &bounds, &input)) { - return false; - } - GrContext* context = srcTexture->getContext(); - - GrSurfaceDesc desc; - desc.fFlags = kRenderTarget_GrSurfaceFlag, - desc.fWidth = bounds.width(); - desc.fHeight = bounds.height(); - desc.fConfig = kRGBA_8888_GrPixelConfig; - - SkAutoTUnref dst(context->textureProvider()->createApproxTexture(desc)); - if (!dst) { - return false; - } - - GrFragmentProcessor* fp; - offset->fX = bounds.left(); - offset->fY = bounds.top(); - bounds.offset(-srcOffset); - SkMatrix matrix(ctx.ctm()); - matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); +sk_sp SkImageFilter::DrawWithFP(GrContext* context, + sk_sp fp, + const SkIRect& bounds, + const OutputProperties& outputProperties) { GrPaint paint; - // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted. - if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) { - SkASSERT(fp); - paint.addColorFragmentProcessor(fp)->unref(); - paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); + paint.addColorFragmentProcessor(std::move(fp)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - SkAutoTUnref drawContext(context->drawContext(dst->asRenderTarget())); - if (drawContext) { - SkRect srcRect = SkRect::Make(bounds); - SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - GrClip clip(dstRect); - drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); - - GrWrapTextureInBitmap(dst, bounds.width(), bounds.height(), false, result); - return true; - } + sk_sp colorSpace = sk_ref_sp(outputProperties.colorSpace()); + GrPixelConfig config = GrRenderableConfigForColorSpace(colorSpace.get()); + sk_sp drawContext(context->makeDrawContext(SkBackingFit::kApprox, + bounds.width(), bounds.height(), + config, + std::move(colorSpace))); + if (!drawContext) { + return nullptr; } -#endif - return false; + paint.setGammaCorrect(drawContext->isGammaCorrect()); + + SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height()); + SkRect srcRect = SkRect::Make(bounds); + SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); + GrFixedClip clip(dstIRect); + drawContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect); + + return SkSpecialImage::MakeFromGpu(dstIRect, kNeedNewImageUniqueID_SpecialImage, + drawContext->asTexture(), + sk_ref_sp(drawContext->getColorSpace())); } +#endif bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const { SkASSERT(nullptr != filterPtr); @@ -452,6 +318,20 @@ bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const { return true; } +bool SkImageFilter::canHandleComplexCTM() const { + if (!this->onCanHandleComplexCTM()) { + return false; + } + const int count = this->countInputs(); + for (int i = 0; i < count; ++i) { + SkImageFilter* input = this->getInput(i); + if (input && !input->canHandleComplexCTM()) { + return false; + } + } + return true; +} + bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds, SkIRect* dstBounds) const { SkIRect temp = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection); @@ -464,42 +344,28 @@ bool SkImageFilter::applyCropRect(const Context& ctx, const SkIRect& srcBounds, return dstBounds->intersect(ctx.clipBounds()); } -bool SkImageFilter::applyCropRectDeprecated(const Context& ctx, Proxy* proxy, const SkBitmap& src, - SkIPoint* srcOffset, SkIRect* bounds, - SkBitmap* dst) const { - SkIRect srcBounds; - src.getBounds(&srcBounds); - srcBounds.offset(*srcOffset); - SkIRect dstBounds = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection); - fCropRect.applyTo(dstBounds, ctx.ctm(), this->affectsTransparentBlack(), bounds); - if (!bounds->intersect(ctx.clipBounds())) { - return false; - } - - if (srcBounds.contains(*bounds)) { - *dst = src; - return true; - } else { - SkAutoTUnref device(proxy->createDevice(bounds->width(), bounds->height())); - if (!device) { - return false; - } - SkCanvas canvas(device); - canvas.clear(0x00000000); - canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y()); - *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); - *dst = device->accessBitmap(false); - return true; - } -} - // Return a larger (newWidth x newHeight) copy of 'src' with black padding // around it. static sk_sp pad_image(SkSpecialImage* src, + const SkImageFilter::OutputProperties& outProps, int newWidth, int newHeight, int offX, int offY) { - - SkImageInfo info = SkImageInfo::MakeN32Premul(newWidth, newHeight); - sk_sp surf(src->makeSurface(info)); + // We would like to operate in the source's color space (so that we return an "identical" + // image, other than the padding. To achieve that, we'd create new output properties: + // + // SkImageFilter::OutputProperties outProps(src->getColorSpace()); + // + // That fails in at least two ways. For formats that are texturable but not renderable (like + // F16 on some ES implementations), we can't create a surface to do the work. For sRGB, images + // may be tagged with an sRGB color space (which leads to an sRGB config in makeSurface). But + // the actual config of that sRGB image on a device with no sRGB support is non-sRGB. + // + // Rather than try to special case these situations, we execute the image padding in the + // destination color space. This should not affect the output of the DAG in (almost) any case, + // because the result of this call is going to be used as an input, where it would have been + // switched to the destination space anyway. The one exception would be a filter that expected + // to consume unclamped F16 data, but the padded version of the image is pre-clamped to 8888. + // We can revisit this logic if that ever becomes an actual problem. + sk_sp surf(src->makeSurface(outProps, SkISize::Make(newWidth, newHeight))); if (!surf) { return nullptr; } @@ -518,8 +384,8 @@ sk_sp SkImageFilter::applyCropRect(const Context& ctx, SkSpecialImage* src, SkIPoint* srcOffset, SkIRect* bounds) const { - SkIRect srcBounds; - srcBounds = SkIRect::MakeXYWH(srcOffset->fX, srcOffset->fY, src->width(), src->height()); + const SkIRect srcBounds = SkIRect::MakeXYWH(srcOffset->x(), srcOffset->y(), + src->width(), src->height()); SkIRect dstBounds = this->onFilterNodeBounds(srcBounds, ctx.ctm(), kForward_MapDirection); fCropRect.applyTo(dstBounds, ctx.ctm(), this->affectsTransparentBlack(), bounds); @@ -530,7 +396,7 @@ sk_sp SkImageFilter::applyCropRect(const Context& ctx, if (srcBounds.contains(*bounds)) { return sk_sp(SkRef(src)); } else { - sk_sp img(pad_image(src, + sk_sp img(pad_image(src, ctx.outputProperties(), bounds->width(), bounds->height(), srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y())); @@ -541,12 +407,12 @@ sk_sp SkImageFilter::applyCropRect(const Context& ctx, SkIRect SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, MapDirection direction) const { - if (fInputCount < 1) { + if (this->countInputs() < 1) { return src; } SkIRect totalBounds; - for (int i = 0; i < fInputCount; ++i) { + for (int i = 0; i < this->countInputs(); ++i) { SkImageFilter* filter = this->getInput(i); SkIRect rect = filter ? filter->filterBounds(src, ctm, direction) : src; if (0 == i) { @@ -567,12 +433,7 @@ SkIRect SkImageFilter::onFilterNodeBounds(const SkIRect& src, const SkMatrix&, M SkImageFilter::Context SkImageFilter::mapContext(const Context& ctx) const { SkIRect clipBounds = this->onFilterNodeBounds(ctx.clipBounds(), ctx.ctm(), MapDirection::kReverse_MapDirection); - return Context(ctx.ctm(), clipBounds, ctx.cache()); -} - -bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, - const SkMatrix&, const SkIRect&) const { - return false; + return Context(ctx.ctm(), clipBounds, ctx.cache(), ctx.outputProperties()); } sk_sp SkImageFilter::MakeMatrixFilter(const SkMatrix& matrix, @@ -600,234 +461,11 @@ sk_sp SkImageFilter::filterInput(int index, sk_sp result(input->filterImage(src, this->mapContext(ctx), offset)); -#if SK_SUPPORT_GPU - if (src->peekTexture() && result && !result->peekTexture()) { - // Keep the result on the GPU - this is still required for some - // image filters that don't support GPU in all cases - GrContext* context = src->peekTexture()->getContext(); - return result->makeTextureImage(src->internal_getProxy(), context); - } -#endif + SkASSERT(!result || src->isTextureBacked() == result->isTextureBacked()); return result; } -#if SK_SUPPORT_GPU - -bool SkImageFilter::filterInputGPUDeprecated(int index, SkImageFilter::Proxy* proxy, - const SkBitmap& src, const Context& ctx, - SkBitmap* result, SkIPoint* offset) const { - SkImageFilter* input = this->getInput(index); - if (!input) { - return true; - } - - // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted. - sk_sp specialSrc(SkSpecialImage::internal_fromBM(proxy, src, nullptr)); - if (!specialSrc) { - return false; - } - - sk_sp tmp(input->onFilterImage(specialSrc.get(), - this->mapContext(ctx), - offset)); - if (!tmp) { - return false; - } - - if (!tmp->internal_getBM(result)) { - return false; - } - - if (!result->getTexture()) { - GrContext* context = src.getTexture()->getContext(); - - const SkImageInfo info = result->info(); - if (kUnknown_SkColorType == info.colorType()) { - return false; - } - SkAutoTUnref resultTex( - GrRefCachedBitmapTexture(context, *result, GrTextureParams::ClampNoFilter())); - if (!resultTex) { - return false; - } - result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); - } - - return true; -} -#endif - -namespace { - -class CacheImpl : public SkImageFilter::Cache { -public: - CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { } - ~CacheImpl() override { - SkTDynamicHash::Iter iter(&fLookup); - - while (!iter.done()) { - Value* v = &*iter; - ++iter; - delete v; - } - } - struct Value { - Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) - : fKey(key), fBitmap(bitmap), fOffset(offset) {} - Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset) - : fKey(key), fImage(SkRef(image)), fOffset(offset) {} - - Key fKey; - SkBitmap fBitmap; - SkAutoTUnref fImage; - SkIPoint fOffset; - static const Key& GetKey(const Value& v) { - return v.fKey; - } - static uint32_t Hash(const Key& key) { - return SkChecksum::Murmur3(reinterpret_cast(&key), sizeof(Key)); - } - SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); - }; - - bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const override { - SkAutoMutexAcquire mutex(fMutex); - if (Value* v = fLookup.find(key)) { - *result = v->fBitmap; - *offset = v->fOffset; - if (v != fLRU.head()) { - fLRU.remove(v); - fLRU.addToHead(v); - } - return true; - } - return false; - } - - SkSpecialImage* get(const Key& key, SkIPoint* offset) const override { - SkAutoMutexAcquire mutex(fMutex); - if (Value* v = fLookup.find(key)) { - *offset = v->fOffset; - if (v != fLRU.head()) { - fLRU.remove(v); - fLRU.addToHead(v); - } - return v->fImage; - } - return nullptr; - } - - void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) override { - SkAutoMutexAcquire mutex(fMutex); - if (Value* v = fLookup.find(key)) { - this->removeInternal(v); - } - Value* v = new Value(key, result, offset); - fLookup.add(v); - fLRU.addToHead(v); - fCurrentBytes += result.getSize(); - while (fCurrentBytes > fMaxBytes) { - Value* tail = fLRU.tail(); - SkASSERT(tail); - if (tail == v) { - break; - } - this->removeInternal(tail); - } - } - - void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override { - SkAutoMutexAcquire mutex(fMutex); - if (Value* v = fLookup.find(key)) { - this->removeInternal(v); - } - Value* v = new Value(key, image, offset); - fLookup.add(v); - fLRU.addToHead(v); - fCurrentBytes += image->getSize(); - while (fCurrentBytes > fMaxBytes) { - Value* tail = fLRU.tail(); - SkASSERT(tail); - if (tail == v) { - break; - } - this->removeInternal(tail); - } - } - - void purge() override { - SkAutoMutexAcquire mutex(fMutex); - while (fCurrentBytes > 0) { - Value* tail = fLRU.tail(); - SkASSERT(tail); - this->removeInternal(tail); - } - } - - void purgeByKeys(const Key keys[], int count) override { - SkAutoMutexAcquire mutex(fMutex); - for (int i = 0; i < count; i++) { - if (Value* v = fLookup.find(keys[i])) { - this->removeInternal(v); - } - } - } - -private: - void removeInternal(Value* v) { - if (v->fImage) { - fCurrentBytes -= v->fImage->getSize(); - } else { - fCurrentBytes -= v->fBitmap.getSize(); - } - fLRU.remove(v); - fLookup.remove(v->fKey); - delete v; - } -private: - SkTDynamicHash fLookup; - mutable SkTInternalLList fLRU; - size_t fMaxBytes; - size_t fCurrentBytes; - mutable SkMutex fMutex; -}; - -} // namespace - -SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) { - return new CacheImpl(maxBytes); -} - -SK_DECLARE_STATIC_ONCE_PTR(SkImageFilter::Cache, cache); -SkImageFilter::Cache* SkImageFilter::Cache::Get() { - return cache.get([]{ return SkImageFilter::Cache::Create(kDefaultCacheSize); }); -} - void SkImageFilter::PurgeCache() { - Cache::Get()->purge(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -SkBaseDevice* SkImageFilter::DeviceProxy::createDevice(int w, int h, TileUsage usage) { - SkBaseDevice::CreateInfo cinfo(SkImageInfo::MakeN32Premul(w, h), - kPossible_TileUsage == usage ? SkBaseDevice::kPossible_TileUsage - : SkBaseDevice::kNever_TileUsage, - kUnknown_SkPixelGeometry, - false, /* preserveLCDText */ - true /*forImageFilter*/); - SkBaseDevice* dev = fDevice->onCreateDevice(cinfo, nullptr); - if (nullptr == dev) { - const SkSurfaceProps surfaceProps(fDevice->fSurfaceProps.flags(), - kUnknown_SkPixelGeometry); - dev = SkBitmapDevice::Create(cinfo.fInfo, surfaceProps); - } - return dev; -} - -bool SkImageFilter::DeviceProxy::filterImage(const SkImageFilter* filter, const SkBitmap& src, - const SkImageFilter::Context& ctx, - SkBitmap* result, SkIPoint* offset) { - return fDevice->filterImage(filter, src, ctx, result, offset); + SkImageFilterCache::Get()->purge(); } diff --git a/gfx/skia/skia/src/core/SkImageFilterCache.cpp b/gfx/skia/skia/src/core/SkImageFilterCache.cpp new file mode 100644 index 000000000000..c7104def3728 --- /dev/null +++ b/gfx/skia/skia/src/core/SkImageFilterCache.cpp @@ -0,0 +1,134 @@ +/* + * 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 "SkImageFilterCache.h" + +#include "SkMutex.h" +#include "SkOnce.h" +#include "SkOpts.h" +#include "SkRefCnt.h" +#include "SkSpecialImage.h" +#include "SkTDynamicHash.h" +#include "SkTInternalLList.h" + +#ifdef SK_BUILD_FOR_IOS + enum { kDefaultCacheSize = 2 * 1024 * 1024 }; +#else + enum { kDefaultCacheSize = 128 * 1024 * 1024 }; +#endif + +namespace { + +class CacheImpl : public SkImageFilterCache { +public: + typedef SkImageFilterCacheKey Key; + CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { } + ~CacheImpl() override { + SkTDynamicHash::Iter iter(&fLookup); + + while (!iter.done()) { + Value* v = &*iter; + ++iter; + delete v; + } + } + struct Value { + Value(const Key& key, SkSpecialImage* image, const SkIPoint& offset) + : fKey(key), fImage(SkRef(image)), fOffset(offset) {} + + Key fKey; + SkAutoTUnref fImage; + SkIPoint fOffset; + static const Key& GetKey(const Value& v) { + return v.fKey; + } + static uint32_t Hash(const Key& key) { + return SkOpts::hash(reinterpret_cast(&key), sizeof(Key)); + } + SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); + }; + + SkSpecialImage* get(const Key& key, SkIPoint* offset) const override { + SkAutoMutexAcquire mutex(fMutex); + if (Value* v = fLookup.find(key)) { + *offset = v->fOffset; + if (v != fLRU.head()) { + fLRU.remove(v); + fLRU.addToHead(v); + } + return v->fImage; + } + return nullptr; + } + + void set(const Key& key, SkSpecialImage* image, const SkIPoint& offset) override { + SkAutoMutexAcquire mutex(fMutex); + if (Value* v = fLookup.find(key)) { + this->removeInternal(v); + } + Value* v = new Value(key, image, offset); + fLookup.add(v); + fLRU.addToHead(v); + fCurrentBytes += image->getSize(); + while (fCurrentBytes > fMaxBytes) { + Value* tail = fLRU.tail(); + SkASSERT(tail); + if (tail == v) { + break; + } + this->removeInternal(tail); + } + } + + void purge() override { + SkAutoMutexAcquire mutex(fMutex); + while (fCurrentBytes > 0) { + Value* tail = fLRU.tail(); + SkASSERT(tail); + this->removeInternal(tail); + } + } + + void purgeByKeys(const Key keys[], int count) override { + SkAutoMutexAcquire mutex(fMutex); + for (int i = 0; i < count; i++) { + if (Value* v = fLookup.find(keys[i])) { + this->removeInternal(v); + } + } + } + + SkDEBUGCODE(int count() const override { return fLookup.count(); }) +private: + void removeInternal(Value* v) { + SkASSERT(v->fImage); + fCurrentBytes -= v->fImage->getSize(); + fLRU.remove(v); + fLookup.remove(v->fKey); + delete v; + } +private: + SkTDynamicHash fLookup; + mutable SkTInternalLList fLRU; + size_t fMaxBytes; + size_t fCurrentBytes; + mutable SkMutex fMutex; +}; + +} // namespace + +SkImageFilterCache* SkImageFilterCache::Create(size_t maxBytes) { + return new CacheImpl(maxBytes); +} + +SkImageFilterCache* SkImageFilterCache::Get() { + static SkOnce once; + static SkImageFilterCache* cache; + + once([]{ cache = SkImageFilterCache::Create(kDefaultCacheSize); }); + return cache; +} diff --git a/gfx/skia/skia/src/core/SkImageFilterCache.h b/gfx/skia/skia/src/core/SkImageFilterCache.h new file mode 100644 index 000000000000..a65357f69cb0 --- /dev/null +++ b/gfx/skia/skia/src/core/SkImageFilterCache.h @@ -0,0 +1,64 @@ +/* + * 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 SkImageFilterCache_DEFINED +#define SkImageFilterCache_DEFINED + +#include "SkMatrix.h" +#include "SkRefCnt.h" + +struct SkIPoint; +class SkSpecialImage; + +struct SkImageFilterCacheKey { + SkImageFilterCacheKey(const uint32_t uniqueID, const SkMatrix& matrix, + const SkIRect& clipBounds, uint32_t srcGenID, const SkIRect& srcSubset) + : fUniqueID(uniqueID) + , fMatrix(matrix) + , fClipBounds(clipBounds) + , fSrcGenID(srcGenID) + , fSrcSubset(srcSubset) { + // Assert that Key is tightly-packed, since it is hashed. + static_assert(sizeof(SkImageFilterCacheKey) == sizeof(uint32_t) + sizeof(SkMatrix) + + sizeof(SkIRect) + sizeof(uint32_t) + 4 * sizeof(int32_t), + "image_filter_key_tight_packing"); + fMatrix.getType(); // force initialization of type, so hashes match + } + + uint32_t fUniqueID; + SkMatrix fMatrix; + SkIRect fClipBounds; + uint32_t fSrcGenID; + SkIRect fSrcSubset; + + bool operator==(const SkImageFilterCacheKey& other) const { + return fUniqueID == other.fUniqueID && + fMatrix == other.fMatrix && + fClipBounds == other.fClipBounds && + fSrcGenID == other.fSrcGenID && + fSrcSubset == other.fSrcSubset; + } +}; + +// This cache maps from (filter's unique ID + CTM + clipBounds + src bitmap generation ID) to +// (result, offset). +class SkImageFilterCache : public SkRefCnt { +public: + enum { kDefaultTransientSize = 32 * 1024 * 1024 }; + + virtual ~SkImageFilterCache() {} + static SkImageFilterCache* Create(size_t maxBytes); + static SkImageFilterCache* Get(); + virtual SkSpecialImage* get(const SkImageFilterCacheKey& key, SkIPoint* offset) const = 0; + virtual void set(const SkImageFilterCacheKey& key, SkSpecialImage* image, + const SkIPoint& offset) = 0; + virtual void purge() = 0; + virtual void purgeByKeys(const SkImageFilterCacheKey[], int) = 0; + SkDEBUGCODE(virtual int count() const = 0;) +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkImageFilterCacheKey.h b/gfx/skia/skia/src/core/SkImageFilterCacheKey.h deleted file mode 100644 index 3f5d1c8fa267..000000000000 --- a/gfx/skia/skia/src/core/SkImageFilterCacheKey.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 SkImageFilterCacheKey_DEFINED -#define SkImageFilterCacheKey_DEFINED - -struct SkImageFilter::Cache::Key { - Key(const uint32_t uniqueID, const SkMatrix& matrix, - const SkIRect& clipBounds, uint32_t srcGenID, const SkIRect& srcSubset) - : fUniqueID(uniqueID) - , fMatrix(matrix) - , fClipBounds(clipBounds) - , fSrcGenID(srcGenID) - , fSrcSubset(srcSubset) { - // Assert that Key is tightly-packed, since it is hashed. - static_assert(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) + - sizeof(uint32_t) + 4 * sizeof(int32_t), - "image_filter_key_tight_packing"); - fMatrix.getType(); // force initialization of type, so hashes match - } - - uint32_t fUniqueID; - SkMatrix fMatrix; - SkIRect fClipBounds; - uint32_t fSrcGenID; - SkIRect fSrcSubset; - - bool operator==(const Key& other) const { - return fUniqueID == other.fUniqueID && - fMatrix == other.fMatrix && - fClipBounds == other.fClipBounds && - fSrcGenID == other.fSrcGenID && - fSrcSubset == other.fSrcSubset; - } -}; - -#endif diff --git a/gfx/skia/skia/src/core/SkImageGenerator.cpp b/gfx/skia/skia/src/core/SkImageGenerator.cpp index c8c94c22707f..84d9c743eb4d 100644 --- a/gfx/skia/skia/src/core/SkImageGenerator.cpp +++ b/gfx/skia/skia/src/core/SkImageGenerator.cpp @@ -8,9 +8,9 @@ #include "SkImageGenerator.h" #include "SkNextID.h" -SkImageGenerator::SkImageGenerator(const SkImageInfo& info) +SkImageGenerator::SkImageGenerator(const SkImageInfo& info, uint32_t uniqueID) : fInfo(info) - , fUniqueID(SkNextID::ImageID()) + , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) {} bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, diff --git a/gfx/skia/skia/src/core/SkImageInfo.cpp b/gfx/skia/skia/src/core/SkImageInfo.cpp index 16f0a0109cc3..75c6807d17fc 100644 --- a/gfx/skia/skia/src/core/SkImageInfo.cpp +++ b/gfx/skia/skia/src/core/SkImageInfo.cpp @@ -9,10 +9,6 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" -static bool profile_type_is_valid(SkColorProfileType profileType) { - return (profileType >= 0) && (profileType <= kLastEnum_SkColorProfileType); -} - static bool alpha_type_is_valid(SkAlphaType alphaType) { return (alphaType >= 0) && (alphaType <= kLastEnum_SkAlphaType); } @@ -21,29 +17,47 @@ static bool color_type_is_valid(SkColorType colorType) { return (colorType >= 0) && (colorType <= kLastEnum_SkColorType); } +SkImageInfo SkImageInfo::MakeS32(int width, int height, SkAlphaType at) { + return SkImageInfo(width, height, kN32_SkColorType, at, + SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)); +} + +static const int kColorTypeMask = 0x0F; +static const int kAlphaTypeMask = 0x03; + void SkImageInfo::unflatten(SkReadBuffer& buffer) { fWidth = buffer.read32(); fHeight = buffer.read32(); uint32_t packed = buffer.read32(); - SkASSERT(0 == (packed >> 24)); - fProfileType = (SkColorProfileType)((packed >> 16) & 0xFF); - fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF); - fColorType = (SkColorType)((packed >> 0) & 0xFF); - buffer.validate(profile_type_is_valid(fProfileType) && - alpha_type_is_valid(fAlphaType) && - color_type_is_valid(fColorType)); + fColorType = (SkColorType)((packed >> 0) & kColorTypeMask); + fAlphaType = (SkAlphaType)((packed >> 8) & kAlphaTypeMask); + buffer.validate(alpha_type_is_valid(fAlphaType) && color_type_is_valid(fColorType)); + + sk_sp data = buffer.readByteArrayAsData(); + fColorSpace = SkColorSpace::Deserialize(data->data(), data->size()); } void SkImageInfo::flatten(SkWriteBuffer& buffer) const { buffer.write32(fWidth); buffer.write32(fHeight); - SkASSERT(0 == (fProfileType & ~0xFF)); - SkASSERT(0 == (fAlphaType & ~0xFF)); - SkASSERT(0 == (fColorType & ~0xFF)); - uint32_t packed = (fProfileType << 16) | (fAlphaType << 8) | fColorType; + SkASSERT(0 == (fAlphaType & ~kAlphaTypeMask)); + SkASSERT(0 == (fColorType & ~kColorTypeMask)); + uint32_t packed = (fAlphaType << 8) | fColorType; buffer.write32(packed); + + if (fColorSpace) { + sk_sp data = fColorSpace->serialize(); + if (data) { + buffer.writeDataAsByteArray(data.get()); + } else { + buffer.writeByteArray(nullptr, 0); + } + } else { + sk_sp data = SkData::MakeEmpty(); + buffer.writeDataAsByteArray(data.get()); + } } bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, diff --git a/gfx/skia/skia/src/core/SkImagePriv.h b/gfx/skia/skia/src/core/SkImagePriv.h new file mode 100644 index 000000000000..8e2f5cecde21 --- /dev/null +++ b/gfx/skia/skia/src/core/SkImagePriv.h @@ -0,0 +1,103 @@ +/* + * 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 SkImagePriv_DEFINED +#define SkImagePriv_DEFINED + +#include "SkImage.h" +#include "SkSmallAllocator.h" +#include "SkSurface.h" + +enum SkCopyPixelsMode { + kIfMutable_SkCopyPixelsMode, //!< only copy src pixels if they are marked mutable + kAlways_SkCopyPixelsMode, //!< always copy src pixels (even if they are marked immutable) + kNever_SkCopyPixelsMode, //!< never copy src pixels (even if they are marked mutable) +}; + +enum {kSkBlitterContextSize = 3332}; + +// Commonly used allocator. It currently is only used to allocate up to 3 objects. The total +// bytes requested is calculated using one of our large shaders, its context size plus the size of +// an Sk3DBlitter in SkDraw.cpp +// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not +// yet found a situation where the size below isn't big enough. +typedef SkSmallAllocator<3, kSkBlitterContextSize> SkTBlitterAllocator; + +// If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive +// the SkShader. +sk_sp SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode, + const SkMatrix* localMatrix, SkCopyPixelsMode, + SkTBlitterAllocator* alloc); + +// Call this if you explicitly want to use/share this pixelRef in the image +extern sk_sp SkMakeImageFromPixelRef(const SkImageInfo&, SkPixelRef*, + const SkIPoint& pixelRefOrigin, + size_t rowBytes); + +/** + * Examines the bitmap to decide if it can share the existing pixelRef, or + * if it needs to make a deep-copy of the pixels. + * + * The bitmap's pixelref will be shared if either the bitmap is marked as + * immutable, or CopyPixelsMode allows it. Shared pixel refs are also + * locked when kLocked_SharedPixelRefMode is specified. + * + * Passing kLocked_SharedPixelRefMode allows the image's peekPixels() method + * to succeed, but it will force any lazy decodes/generators to execute if + * they exist on the pixelref. + * + * It is illegal to call this with a texture-backed bitmap. + * + * If the bitmap's colortype cannot be converted into a corresponding + * SkImageInfo, or the bitmap's pixels cannot be accessed, this will return + * nullptr. + */ +extern sk_sp SkMakeImageFromRasterBitmap(const SkBitmap&, SkCopyPixelsMode, + SkTBlitterAllocator* = nullptr); + +// Given an image created from SkNewImageFromBitmap, return its pixelref. This +// may be called to see if the surface and the image share the same pixelref, +// in which case the surface may need to perform a copy-on-write. +extern const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* rasterImage); + +// When a texture is shared by a surface and an image its budgeted status is that of the +// surface. This function is used when the surface makes a new texture for itself in order +// for the orphaned image to determine whether the original texture counts against the +// budget or not. +extern void SkTextureImageApplyBudgetedDecision(SkImage* textureImage); + +// Update the texture wrapped by an image created with NewTexture. This +// is called when a surface and image share the same GrTexture and the +// surface needs to perform a copy-on-write +extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture); + +/** + * Will attempt to upload and lock the contents of the image as a texture, so that subsequent + * draws to a gpu-target will come from that texture (and not by looking at the original image + * src). In particular this is intended to use the texture even if the image's original content + * changes subsequent to this call (i.e. the src is mutable!). + * + * This must be balanced by an equal number of calls to SkImage_unpinAsTexture() -- calls can be + * nested. + * + * Once in this "pinned" state, the image has all of the same thread restrictions that exist + * for a natively created gpu image (e.g. SkImage::MakeFromTexture) + * - all drawing, pinning, unpinning must happen in the same thread as the GrContext. + */ +void SkImage_pinAsTexture(const SkImage*, GrContext*); + +/** + * The balancing call to SkImage_pinAsTexture. When a balanced number of calls have been made, then + * the "pinned" texture is free to be purged, etc. This also means that a subsequent "pin" call + * will look at the original content again, and if its uniqueID/generationID has changed, then + * a newer texture will be uploaded/pinned. + * + * The context passed to unpin must match the one passed to pin. + */ +void SkImage_unpinAsTexture(const SkImage*, GrContext*); + +#endif diff --git a/gfx/skia/skia/src/core/SkLatticeIter.cpp b/gfx/skia/skia/src/core/SkLatticeIter.cpp new file mode 100644 index 000000000000..4fe9352d0a5e --- /dev/null +++ b/gfx/skia/skia/src/core/SkLatticeIter.cpp @@ -0,0 +1,288 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkLatticeIter.h" +#include "SkRect.h" + +/** + * Divs must be in increasing order with no duplicates. + */ +static bool valid_divs(const int* divs, int count, int start, int end) { + int prev = start - 1; + for (int i = 0; i < count; i++) { + if (prev >= divs[i] || divs[i] >= end) { + return false; + } + } + + return true; +} + +bool SkLatticeIter::Valid(int width, int height, const SkCanvas::Lattice& lattice) { + SkIRect totalBounds = SkIRect::MakeWH(width, height); + SkASSERT(lattice.fBounds); + const SkIRect latticeBounds = *lattice.fBounds; + if (!totalBounds.contains(latticeBounds)) { + return false; + } + + bool zeroXDivs = lattice.fXCount <= 0 || (1 == lattice.fXCount && + latticeBounds.fLeft == lattice.fXDivs[0]); + bool zeroYDivs = lattice.fYCount <= 0 || (1 == lattice.fYCount && + latticeBounds.fTop == lattice.fYDivs[0]); + if (zeroXDivs && zeroYDivs) { + return false; + } + + return valid_divs(lattice.fXDivs, lattice.fXCount, latticeBounds.fLeft, latticeBounds.fRight) + && valid_divs(lattice.fYDivs, lattice.fYCount, latticeBounds.fTop, latticeBounds.fBottom); +} + +/** + * Count the number of pixels that are in "scalable" patches. + */ +static int count_scalable_pixels(const int32_t* divs, int numDivs, bool firstIsScalable, + int start, int end) { + if (0 == numDivs) { + return firstIsScalable ? end - start : 0; + } + + int i; + int count; + if (firstIsScalable) { + count = divs[0] - start; + i = 1; + } else { + count = 0; + i = 0; + } + + for (; i < numDivs; i += 2) { + // Alternatively, we could use |top| and |bottom| as variable names, instead of + // |left| and |right|. + int left = divs[i]; + int right = (i + 1 < numDivs) ? divs[i + 1] : end; + count += right - left; + } + + return count; +} + +/** + * Set points for the src and dst rects on subsequent draw calls. + */ +static void set_points(float* dst, float* src, const int* divs, int divCount, int srcFixed, + int srcScalable, float srcStart, float srcEnd, float dstStart, float dstEnd, + bool isScalable) { + + float dstLen = dstEnd - dstStart; + float scale; + if (srcFixed <= dstLen) { + // This is the "normal" case, where we scale the "scalable" patches and leave + // the other patches fixed. + scale = (dstLen - ((float) srcFixed)) / ((float) srcScalable); + } else { + // In this case, we eliminate the "scalable" patches and scale the "fixed" patches. + scale = dstLen / ((float) srcFixed); + } + + src[0] = srcStart; + dst[0] = dstStart; + for (int i = 0; i < divCount; i++) { + src[i + 1] = (float) (divs[i]); + float srcDelta = src[i + 1] - src[i]; + float dstDelta; + if (srcFixed <= dstLen) { + dstDelta = isScalable ? scale * srcDelta : srcDelta; + } else { + dstDelta = isScalable ? 0.0f : scale * srcDelta; + } + dst[i + 1] = dst[i] + dstDelta; + + // Alternate between "scalable" and "fixed" patches. + isScalable = !isScalable; + } + + src[divCount + 1] = srcEnd; + dst[divCount + 1] = dstEnd; +} + +SkLatticeIter::SkLatticeIter(const SkCanvas::Lattice& lattice, const SkRect& dst) { + const int* xDivs = lattice.fXDivs; + const int origXCount = lattice.fXCount; + const int* yDivs = lattice.fYDivs; + const int origYCount = lattice.fYCount; + SkASSERT(lattice.fBounds); + const SkIRect src = *lattice.fBounds; + + // In the x-dimension, the first rectangle always starts at x = 0 and is "scalable". + // If xDiv[0] is 0, it indicates that the first rectangle is degenerate, so the + // first real rectangle "scalable" in the x-direction. + // + // The same interpretation applies to the y-dimension. + // + // As we move left to right across the image, alternating patches will be "fixed" or + // "scalable" in the x-direction. Similarly, as move top to bottom, alternating + // patches will be "fixed" or "scalable" in the y-direction. + int xCount = origXCount; + int yCount = origYCount; + bool xIsScalable = (xCount > 0 && src.fLeft == xDivs[0]); + if (xIsScalable) { + // Once we've decided that the first patch is "scalable", we don't need the + // xDiv. It is always implied that we start at the edge of the bounds. + xDivs++; + xCount--; + } + bool yIsScalable = (yCount > 0 && src.fTop == yDivs[0]); + if (yIsScalable) { + // Once we've decided that the first patch is "scalable", we don't need the + // yDiv. It is always implied that we start at the edge of the bounds. + yDivs++; + yCount--; + } + + // Count "scalable" and "fixed" pixels in each dimension. + int xCountScalable = count_scalable_pixels(xDivs, xCount, xIsScalable, src.fLeft, src.fRight); + int xCountFixed = src.width() - xCountScalable; + int yCountScalable = count_scalable_pixels(yDivs, yCount, yIsScalable, src.fTop, src.fBottom); + int yCountFixed = src.height() - yCountScalable; + + fSrcX.reset(xCount + 2); + fDstX.reset(xCount + 2); + set_points(fDstX.begin(), fSrcX.begin(), xDivs, xCount, xCountFixed, xCountScalable, + src.fLeft, src.fRight, dst.fLeft, dst.fRight, xIsScalable); + + fSrcY.reset(yCount + 2); + fDstY.reset(yCount + 2); + set_points(fDstY.begin(), fSrcY.begin(), yDivs, yCount, yCountFixed, yCountScalable, + src.fTop, src.fBottom, dst.fTop, dst.fBottom, yIsScalable); + + fCurrX = fCurrY = 0; + fNumRectsInLattice = (xCount + 1) * (yCount + 1); + fNumRectsToDraw = fNumRectsInLattice; + + if (lattice.fFlags) { + fFlags.push_back_n(fNumRectsInLattice); + + const SkCanvas::Lattice::Flags* flags = lattice.fFlags; + + bool hasPadRow = (yCount != origYCount); + bool hasPadCol = (xCount != origXCount); + if (hasPadRow) { + // The first row of rects are all empty, skip the first row of flags. + flags += origXCount + 1; + } + + int i = 0; + for (int y = 0; y < yCount + 1; y++) { + for (int x = 0; x < origXCount + 1; x++) { + if (0 == x && hasPadCol) { + // The first column of rects are all empty. Skip a rect. + flags++; + continue; + } + + fFlags[i] = *flags; + flags++; + i++; + } + } + + for (int j = 0; j < fFlags.count(); j++) { + if (SkCanvas::Lattice::kTransparent_Flags == fFlags[j]) { + fNumRectsToDraw--; + } + } + } +} + +bool SkLatticeIter::Valid(int width, int height, const SkIRect& center) { + return !center.isEmpty() && SkIRect::MakeWH(width, height).contains(center); +} + +SkLatticeIter::SkLatticeIter(int w, int h, const SkIRect& c, const SkRect& dst) { + SkASSERT(SkIRect::MakeWH(w, h).contains(c)); + + fSrcX.reset(4); + fSrcY.reset(4); + fDstX.reset(4); + fDstY.reset(4); + + fSrcX[0] = 0; + fSrcX[1] = SkIntToScalar(c.fLeft); + fSrcX[2] = SkIntToScalar(c.fRight); + fSrcX[3] = SkIntToScalar(w); + + fSrcY[0] = 0; + fSrcY[1] = SkIntToScalar(c.fTop); + fSrcY[2] = SkIntToScalar(c.fBottom); + fSrcY[3] = SkIntToScalar(h); + + fDstX[0] = dst.fLeft; + fDstX[1] = dst.fLeft + SkIntToScalar(c.fLeft); + fDstX[2] = dst.fRight - SkIntToScalar(w - c.fRight); + fDstX[3] = dst.fRight; + + fDstY[0] = dst.fTop; + fDstY[1] = dst.fTop + SkIntToScalar(c.fTop); + fDstY[2] = dst.fBottom - SkIntToScalar(h - c.fBottom); + fDstY[3] = dst.fBottom; + + if (fDstX[1] > fDstX[2]) { + fDstX[1] = fDstX[0] + (fDstX[3] - fDstX[0]) * c.fLeft / (w - c.width()); + fDstX[2] = fDstX[1]; + } + + if (fDstY[1] > fDstY[2]) { + fDstY[1] = fDstY[0] + (fDstY[3] - fDstY[0]) * c.fTop / (h - c.height()); + fDstY[2] = fDstY[1]; + } + + fCurrX = fCurrY = 0; + fNumRectsInLattice = 9; + fNumRectsToDraw = 9; +} + +bool SkLatticeIter::next(SkRect* src, SkRect* dst) { + int currRect = fCurrX + fCurrY * (fSrcX.count() - 1); + if (currRect == fNumRectsInLattice) { + return false; + } + + const int x = fCurrX; + const int y = fCurrY; + SkASSERT(x >= 0 && x < fSrcX.count() - 1); + SkASSERT(y >= 0 && y < fSrcY.count() - 1); + + if (fSrcX.count() - 1 == ++fCurrX) { + fCurrX = 0; + fCurrY += 1; + } + + if (fFlags.count() > 0 && SkToBool(SkCanvas::Lattice::kTransparent_Flags & fFlags[currRect])) { + return this->next(src, dst); + } + + src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]); + dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]); + return true; +} + +void SkLatticeIter::mapDstScaleTranslate(const SkMatrix& matrix) { + SkASSERT(matrix.isScaleTranslate()); + SkScalar tx = matrix.getTranslateX(); + SkScalar sx = matrix.getScaleX(); + for (int i = 0; i < fDstX.count(); i++) { + fDstX[i] = fDstX[i] * sx + tx; + } + + SkScalar ty = matrix.getTranslateY(); + SkScalar sy = matrix.getScaleY(); + for (int i = 0; i < fDstY.count(); i++) { + fDstY[i] = fDstY[i] * sy + ty; + } +} diff --git a/gfx/skia/skia/src/core/SkLatticeIter.h b/gfx/skia/skia/src/core/SkLatticeIter.h new file mode 100644 index 000000000000..f3d37e6688e4 --- /dev/null +++ b/gfx/skia/skia/src/core/SkLatticeIter.h @@ -0,0 +1,62 @@ +/* + * 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 SkLatticeIter_DEFINED +#define SkLatticeIter_DEFINED + +#include "SkCanvas.h" +#include "SkScalar.h" +#include "SkTArray.h" + +struct SkIRect; +struct SkRect; + +/** + * Disect a lattice request into an sequence of src-rect / dst-rect pairs + */ +class SkLatticeIter { +public: + + static bool Valid(int imageWidth, int imageHeight, const SkCanvas::Lattice& lattice); + + SkLatticeIter(const SkCanvas::Lattice& lattice, const SkRect& dst); + + static bool Valid(int imageWidth, int imageHeight, const SkIRect& center); + + SkLatticeIter(int imageWidth, int imageHeight, const SkIRect& center, const SkRect& dst); + + /** + * While it returns true, use src/dst to draw the image/bitmap + */ + bool next(SkRect* src, SkRect* dst); + + /** + * Apply a matrix to the dst points. + */ + void mapDstScaleTranslate(const SkMatrix& matrix); + + /** + * Returns the number of rects that will actually be drawn. + */ + int numRectsToDraw() const { + return fNumRectsToDraw; + } + +private: + SkTArray fSrcX; + SkTArray fSrcY; + SkTArray fDstX; + SkTArray fDstY; + SkTArray fFlags; + + int fCurrX; + int fCurrY; + int fNumRectsInLattice; + int fNumRectsToDraw; +}; + +#endif diff --git a/gfx/skia/skia/src/core/SkLayerInfo.h b/gfx/skia/skia/src/core/SkLayerInfo.h deleted file mode 100644 index aa19ecbd0c49..000000000000 --- a/gfx/skia/skia/src/core/SkLayerInfo.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 SkLayerInfo_DEFINED -#define SkLayerInfo_DEFINED - -#include "SkBigPicture.h" -#include "SkMatrix.h" -#include "SkPaint.h" -#include "SkTArray.h" - -// This class stores information about the saveLayer/restore pairs found -// within an SkPicture. It is used by Ganesh to perform layer hoisting. -class SkLayerInfo : public SkBigPicture::AccelData { -public: - // Information about a given saveLayer/restore block in an SkPicture - class BlockInfo { - public: - BlockInfo() : fPicture(nullptr), fPaint(nullptr), fKey(nullptr), fKeySize(0) {} - ~BlockInfo() { - SkSafeUnref(fPicture); - delete fPaint; - delete[] fKey; - } - - // The picture owning the layer. If the owning picture is the top-most - // one (i.e., the picture for which this SkLayerInfo was created) then - // this pointer is nullptr. If it is a nested picture then the pointer - // is non-nullptr and owns a ref on the picture. - const SkPicture* fPicture; - // The device space bounds of this layer. - SkRect fBounds; - // If not-empty, the optional bounds parameter passed in to the saveLayer - // call. - SkRect fSrcBounds; - // The pre-matrix begins as the identity and accumulates the transforms - // of the containing SkPictures (if any). This matrix state has to be - // part of the initial matrix during replay so that it will be - // preserved across setMatrix calls. - SkMatrix fPreMat; - // The matrix state (in the leaf picture) in which this layer's draws - // must occur. It will/can be overridden by setMatrix calls in the - // layer itself. It does not include the translation needed to map the - // layer's top-left point to the origin (which must be part of the - // initial matrix). - SkMatrix fLocalMat; - // The paint to use on restore. Can be nullptr since it is optional. - const SkPaint* fPaint; - // The index of this saveLayer in the picture. - size_t fSaveLayerOpID; - // The index of the matching restore in the picture. - size_t fRestoreOpID; - // True if this saveLayer has at least one other saveLayer nested within it. - // False otherwise. - bool fHasNestedLayers; - // True if this saveLayer is nested within another. False otherwise. - bool fIsNested; - // The variable length key for this saveLayer block. It stores the - // thread of drawPicture and saveLayer operation indices that lead to this - // saveLayer (including its own op index). The BlockInfo owns this memory. - int* fKey; - int fKeySize; // # of ints - }; - - SkLayerInfo() {} - - BlockInfo& addBlock() { return fBlocks.push_back(); } - - int numBlocks() const { return fBlocks.count(); } - - const BlockInfo& block(int index) const { - SkASSERT(index < fBlocks.count()); - - return fBlocks[index]; - } - -private: - SkTArray fBlocks; - - typedef SkBigPicture::AccelData INHERITED; -}; - -#endif // SkLayerInfo_DEFINED diff --git a/gfx/skia/skia/src/core/SkLight.h b/gfx/skia/skia/src/core/SkLight.h deleted file mode 100644 index d9eb78d1122a..000000000000 --- a/gfx/skia/skia/src/core/SkLight.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 SkLight_DEFINED -#define SkLight_DEFINED - -#include "SkPoint3.h" - -class SK_API SkLight { -public: - enum LightType { - kAmbient_LightType, // only 'fColor' is used - kDirectional_LightType - }; - - SkLight() : fType(kAmbient_LightType) { - fColor.set(0.0f, 0.0f, 0.0f); - fDirection.set(0.0f, 0.0f, 1.0f); - } - - SkLight(const SkColor3f& color) - : fType(kAmbient_LightType) - , fColor(color) { - fDirection.set(0.0f, 0.0f, 1.0f); - } - - SkLight(const SkColor3f& color, const SkVector3& dir) - : fType(kDirectional_LightType) - , fColor(color) - , fDirection(dir) { - if (!fDirection.normalize()) { - fDirection.set(0.0f, 0.0f, 1.0f); - } - } - - LightType type() const { return fType; } - const SkColor3f& color() const { return fColor; } - const SkVector3& dir() const { - SkASSERT(kAmbient_LightType != fType); - return fDirection; - } - -private: - LightType fType; - SkColor3f fColor; // linear (unpremul) color. Range is 0..1 in each channel. - SkVector3 fDirection; // direction towards the light (+Z is out of the screen). - // If degenerate, it will be replaced with (0, 0, 1). -}; - - -#endif diff --git a/gfx/skia/skia/src/core/SkLightingShader.cpp b/gfx/skia/skia/src/core/SkLightingShader.cpp index eba7d652eb6d..9030a192b477 100644 --- a/gfx/skia/skia/src/core/SkLightingShader.cpp +++ b/gfx/skia/skia/src/core/SkLightingShader.cpp @@ -5,12 +5,14 @@ * found in the LICENSE file. */ +#include "SkBitmapProcShader.h" #include "SkBitmapProcState.h" #include "SkColor.h" #include "SkEmptyShader.h" #include "SkErrorInternals.h" #include "SkLightingShader.h" #include "SkMathPriv.h" +#include "SkNormalSource.h" #include "SkPoint3.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" @@ -19,15 +21,11 @@ /* SkLightingShader TODOs: - support other than clamp mode - allow 'diffuse' & 'normal' to be of different dimensions? support different light types support multiple lights - enforce normal map is 4 channel - use SkImages instead if SkBitmaps + fix non-opaque diffuse textures To Test: - non-opaque diffuse textures A8 diffuse textures down & upsampled draws */ @@ -37,53 +35,35 @@ /** \class SkLightingShaderImpl This subclass of shader applies lighting. */ -class SK_API SkLightingShaderImpl : public SkShader { +class SkLightingShaderImpl : public SkShader { public: - /** Create a new lighting shader that uses the provided normal map and lights to light the diffuse bitmap. - @param diffuse the diffuse bitmap - @param normal the normal map - @param lights the lights applied to the normal map - @param invNormRotation rotation applied to the normal map's normals - @param diffLocalM the local matrix for the diffuse coordinates - @param normLocalM the local matrix for the normal coordinates + @param diffuseShader the shader that provides the diffuse colors + @param normalSource the source of normals for lighting computation + @param lights the lights applied to the geometry */ - SkLightingShaderImpl(const SkBitmap& diffuse, const SkBitmap& normal, - const SkLightingShader::Lights* lights, - const SkVector& invNormRotation, - const SkMatrix* diffLocalM, const SkMatrix* normLocalM) - : INHERITED(diffLocalM) - , fDiffuseMap(diffuse) - , fNormalMap(normal) - , fLights(SkRef(lights)) - , fInvNormRotation(invNormRotation) { - - if (normLocalM) { - fNormLocalMatrix = *normLocalM; - } else { - fNormLocalMatrix.reset(); - } - // Pre-cache so future calls to fNormLocalMatrix.getType() are threadsafe. - (void)fNormLocalMatrix.getType(); - - } + SkLightingShaderImpl(sk_sp diffuseShader, + sk_sp normalSource, + sk_sp lights) + : fDiffuseShader(std::move(diffuseShader)) + , fNormalSource(std::move(normalSource)) + , fLights(std::move(lights)) {} bool isOpaque() const override; #if SK_SUPPORT_GPU - const GrFragmentProcessor* asFragmentProcessor(GrContext*, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality) const override; + sk_sp asFragmentProcessor(const AsFPArgs&) const override; #endif class LightingShaderContext : public SkShader::Context { public: - // The context takes ownership of the states. It will call their destructors - // but will NOT free the memory. + // The context takes ownership of the context and provider. It will call their destructors + // and then indirectly free their memory by calling free() on heapAllocated LightingShaderContext(const SkLightingShaderImpl&, const ContextRec&, - SkBitmapProcState* diffuseState, SkBitmapProcState* normalState); + SkShader::Context* diffuseContext, SkNormalSource::Provider*, + void* heapAllocated); + ~LightingShaderContext() override; void shadeSpan(int x, int y, SkPMColor[], int count) override; @@ -91,9 +71,12 @@ public: uint32_t getFlags() const override { return fFlags; } private: - SkBitmapProcState* fDiffuseState; - SkBitmapProcState* fNormalState; - uint32_t fFlags; + SkShader::Context* fDiffuseContext; + SkNormalSource::Provider* fNormalProvider; + SkColor fPaintColor; + uint32_t fFlags; + + void* fHeapAllocated; typedef SkShader::Context INHERITED; }; @@ -105,16 +88,11 @@ protected: void flatten(SkWriteBuffer&) const override; size_t onContextSize(const ContextRec&) const override; Context* onCreateContext(const ContextRec&, void*) const override; - bool computeNormTotalInverse(const ContextRec& rec, SkMatrix* normTotalInverse) const; private: - SkBitmap fDiffuseMap; - SkBitmap fNormalMap; - - SkAutoTUnref fLights; - - SkMatrix fNormLocalMatrix; - SkVector fInvNormRotation; + sk_sp fDiffuseShader; + sk_sp fNormalSource; + sk_sp fLights; friend class SkLightingShader; @@ -136,124 +114,116 @@ private: #include "SkGr.h" #include "SkGrPriv.h" +// This FP expects a premul'd color input for its diffuse color. Premul'ing of the paint's color is +// handled by the asFragmentProcessor() factory, but shaders providing diffuse color must output it +// premul'd. class LightingFP : public GrFragmentProcessor { public: - LightingFP(GrTexture* diffuse, GrTexture* normal, const SkMatrix& diffMatrix, - const SkMatrix& normMatrix, const GrTextureParams& diffParams, - const GrTextureParams& normParams, const SkLightingShader::Lights* lights, - const SkVector& invNormRotation) - : fDiffDeviceTransform(kLocal_GrCoordSet, diffMatrix, diffuse, diffParams.filterMode()) - , fNormDeviceTransform(kLocal_GrCoordSet, normMatrix, normal, normParams.filterMode()) - , fDiffuseTextureAccess(diffuse, diffParams) - , fNormalTextureAccess(normal, normParams) - , fInvNormRotation(invNormRotation) { - this->addCoordTransform(&fDiffDeviceTransform); - this->addCoordTransform(&fNormDeviceTransform); - this->addTextureAccess(&fDiffuseTextureAccess); - this->addTextureAccess(&fNormalTextureAccess); + LightingFP(sk_sp normalFP, sk_sp lights) { // fuse all ambient lights into a single one - fAmbientColor.set(0.0f, 0.0f, 0.0f); + fAmbientColor = lights->ambientLightColor(); for (int i = 0; i < lights->numLights(); ++i) { - if (SkLight::kAmbient_LightType == lights->light(i).type()) { - fAmbientColor += lights->light(i).color(); + if (SkLights::Light::kDirectional_LightType == lights->light(i).type()) { + fDirectionalLights.push_back(lights->light(i)); + // TODO get the handle to the shadow map if there is one } else { - // TODO: handle more than one of these - fLightColor = lights->light(i).color(); - fLightDir = lights->light(i).dir(); + SkDEBUGFAIL("Unimplemented Light Type passed to LightingFP"); } } + this->registerChildProcessor(std::move(normalFP)); this->initClassID(); } - class LightingGLFP : public GrGLSLFragmentProcessor { + class GLSLLightingFP : public GrGLSLFragmentProcessor { public: - LightingGLFP() { - fLightDir.fX = 10000.0f; - fLightColor.fX = 0.0f; + GLSLLightingFP() { fAmbientColor.fX = 0.0f; - fInvNormRotation.set(0.0f, 0.0f); } void emitCode(EmitArgs& args) override { GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + const LightingFP& lightingFP = args.fFp.cast(); - // add uniforms - const char* lightDirUniName = nullptr; - fLightDirUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightDir", &lightDirUniName); - - const char* lightColorUniName = nullptr; - fLightColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec3f_GrSLType, kDefault_GrSLPrecision, - "LightColor", &lightColorUniName); + const char *lightDirsUniName = nullptr; + const char *lightColorsUniName = nullptr; + if (lightingFP.fDirectionalLights.count() != 0) { + fLightDirsUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "LightDir", + lightingFP.fDirectionalLights.count(), + &lightDirsUniName); + fLightColorsUni = uniformHandler->addUniformArray( + kFragment_GrShaderFlag, + kVec3f_GrSLType, + kDefault_GrSLPrecision, + "LightColor", + lightingFP.fDirectionalLights.count(), + &lightColorsUniName); + } const char* ambientColorUniName = nullptr; fAmbientColorUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kVec3f_GrSLType, kDefault_GrSLPrecision, "AmbientColor", &ambientColorUniName); - const char* xformUniName = nullptr; - fXformUni = uniformHandler->addUniform(kFragment_GrShaderFlag, - kVec2f_GrSLType, kDefault_GrSLPrecision, - "Xform", &xformUniName); + fragBuilder->codeAppendf("vec4 diffuseColor = %s;", args.fInputColor); - fragBuilder->codeAppend("vec4 diffuseColor = "); - fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], - args.fCoords[0].c_str(), - args.fCoords[0].getType()); - fragBuilder->codeAppend(";"); + SkString dstNormalName("dstNormal"); + this->emitChild(0, nullptr, &dstNormalName, args); - fragBuilder->codeAppend("vec4 normalColor = "); - fragBuilder->appendTextureLookup(args.fSamplers[1], - args.fCoords[1].c_str(), - args.fCoords[1].getType()); - fragBuilder->codeAppend(";"); + fragBuilder->codeAppendf("vec3 normal = %s.xyz;", dstNormalName.c_str()); - fragBuilder->codeAppend("vec3 normal = normalColor.rgb - vec3(0.5);"); + fragBuilder->codeAppend( "vec3 result = vec3(0.0);"); - fragBuilder->codeAppendf( - "mat3 m = mat3(%s.x, -%s.y, 0.0, %s.y, %s.x, 0.0, 0.0, 0.0, 1.0);", - xformUniName, xformUniName, xformUniName, xformUniName); - - // TODO: inverse map the light direction vectors in the vertex shader rather than - // transforming all the normals here! - fragBuilder->codeAppend("normal = normalize(m*normal);"); - - fragBuilder->codeAppendf("float NdotL = clamp(dot(normal, %s), 0.0, 1.0);", - lightDirUniName); // diffuse light - fragBuilder->codeAppendf("vec3 result = %s*diffuseColor.rgb*NdotL;", lightColorUniName); + if (lightingFP.fDirectionalLights.count() != 0) { + fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {", + lightingFP.fDirectionalLights.count()); + // TODO: modulate the contribution from each light based on the shadow map + fragBuilder->codeAppendf(" float NdotL = clamp(dot(normal, %s[i]), 0.0, 1.0);", + lightDirsUniName); + fragBuilder->codeAppendf(" result += %s[i]*diffuseColor.rgb*NdotL;", + lightColorsUniName); + fragBuilder->codeAppend("}"); + } + // ambient light - fragBuilder->codeAppendf("result += %s;", ambientColorUniName); - fragBuilder->codeAppendf("%s = vec4(result.rgb, diffuseColor.a);", args.fOutputColor); + fragBuilder->codeAppendf("result += %s * diffuseColor.rgb;", ambientColorUniName); + + // Clamping to alpha (equivalent to an unpremul'd clamp to 1.0) + fragBuilder->codeAppendf("%s = vec4(clamp(result.rgb, 0.0, diffuseColor.a), " + "diffuseColor.a);", args.fOutputColor); } static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { -// const LightingFP& lightingFP = proc.cast(); - // only one shader generated currently - b->add32(0x0); + const LightingFP& lightingFP = proc.cast(); + b->add32(lightingFP.fDirectionalLights.count()); } protected: void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override { const LightingFP& lightingFP = proc.cast(); - const SkVector3& lightDir = lightingFP.lightDir(); - if (lightDir != fLightDir) { - pdman.set3fv(fLightDirUni, 1, &lightDir.fX); - fLightDir = lightDir; - } + const SkTArray& directionalLights = lightingFP.directionalLights(); + if (directionalLights != fDirectionalLights) { + SkTArray lightDirs(directionalLights.count()); + SkTArray lightColors(directionalLights.count()); + for (const SkLights::Light& light : directionalLights) { + lightDirs.push_back(light.dir()); + lightColors.push_back(light.color()); + } - const SkColor3f& lightColor = lightingFP.lightColor(); - if (lightColor != fLightColor) { - pdman.set3fv(fLightColorUni, 1, &lightColor.fX); - fLightColor = lightColor; + pdman.set3fv(fLightDirsUni, directionalLights.count(), &(lightDirs[0].fX)); + pdman.set3fv(fLightColorsUni, directionalLights.count(), &(lightColors[0].fX)); + + fDirectionalLights = directionalLights; } const SkColor3f& ambientColor = lightingFP.ambientColor(); @@ -261,30 +231,19 @@ public: pdman.set3fv(fAmbientColorUni, 1, &ambientColor.fX); fAmbientColor = ambientColor; } - - const SkVector& invNormRotation = lightingFP.invNormRotation(); - if (invNormRotation != fInvNormRotation) { - pdman.set2fv(fXformUni, 1, &invNormRotation.fX); - fInvNormRotation = invNormRotation; - } } private: - SkVector3 fLightDir; - GrGLSLProgramDataManager::UniformHandle fLightDirUni; - - SkColor3f fLightColor; - GrGLSLProgramDataManager::UniformHandle fLightColorUni; + SkTArray fDirectionalLights; + GrGLSLProgramDataManager::UniformHandle fLightDirsUni; + GrGLSLProgramDataManager::UniformHandle fLightColorsUni; SkColor3f fAmbientColor; GrGLSLProgramDataManager::UniformHandle fAmbientColorUni; - - SkVector fInvNormRotation; - GrGLSLProgramDataManager::UniformHandle fXformUni; }; void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override { - LightingGLFP::GenKey(*this, caps, b); + GLSLLightingFP::GenKey(*this, caps, b); } const char* name() const override { return "LightingFP"; } @@ -293,117 +252,48 @@ public: inout->mulByUnknownFourComponents(); } - const SkVector3& lightDir() const { return fLightDir; } - const SkColor3f& lightColor() const { return fLightColor; } + const SkTArray& directionalLights() const { return fDirectionalLights; } const SkColor3f& ambientColor() const { return fAmbientColor; } - const SkVector& invNormRotation() const { return fInvNormRotation; } private: - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new LightingGLFP; } + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLLightingFP; } bool onIsEqual(const GrFragmentProcessor& proc) const override { const LightingFP& lightingFP = proc.cast(); - return fDiffDeviceTransform == lightingFP.fDiffDeviceTransform && - fNormDeviceTransform == lightingFP.fNormDeviceTransform && - fDiffuseTextureAccess == lightingFP.fDiffuseTextureAccess && - fNormalTextureAccess == lightingFP.fNormalTextureAccess && - fLightDir == lightingFP.fLightDir && - fLightColor == lightingFP.fLightColor && - fAmbientColor == lightingFP.fAmbientColor && - fInvNormRotation == lightingFP.fInvNormRotation; + return fDirectionalLights == lightingFP.fDirectionalLights && + fAmbientColor == lightingFP.fAmbientColor; } - GrCoordTransform fDiffDeviceTransform; - GrCoordTransform fNormDeviceTransform; - GrTextureAccess fDiffuseTextureAccess; - GrTextureAccess fNormalTextureAccess; - SkVector3 fLightDir; - SkColor3f fLightColor; - SkColor3f fAmbientColor; - - SkVector fInvNormRotation; + SkTArray fDirectionalLights; + SkColor3f fAmbientColor; }; //////////////////////////////////////////////////////////////////////////// -static bool make_mat(const SkBitmap& bm, - const SkMatrix& localMatrix1, - const SkMatrix* localMatrix2, - SkMatrix* result) { - - result->setIDiv(bm.width(), bm.height()); - - SkMatrix lmInverse; - if (!localMatrix1.invert(&lmInverse)) { - return false; +sk_sp SkLightingShaderImpl::asFragmentProcessor(const AsFPArgs& args) const { + sk_sp normalFP(fNormalSource->asFragmentProcessor(args)); + if (!normalFP) { + return nullptr; } - if (localMatrix2) { - SkMatrix inv; - if (!localMatrix2->invert(&inv)) { - return false; + + if (fDiffuseShader) { + sk_sp fpPipeline[] = { + fDiffuseShader->asFragmentProcessor(args), + sk_make_sp(std::move(normalFP), fLights) + }; + if(!fpPipeline[0]) { + return nullptr; } - lmInverse.postConcat(inv); + + sk_sp innerLightFP = GrFragmentProcessor::RunInSeries(fpPipeline, 2); + // FP is wrapped because paint's alpha needs to be applied to output + return GrFragmentProcessor::MulOutputByInputAlpha(std::move(innerLightFP)); + } else { + // FP is wrapped because paint comes in unpremul'd to fragment shader, but LightingFP + // expects premul'd color. + return GrFragmentProcessor::PremulInput(sk_make_sp(std::move(normalFP), + fLights)); } - result->preConcat(lmInverse); - - return true; -} - -const GrFragmentProcessor* SkLightingShaderImpl::asFragmentProcessor( - GrContext* context, - const SkMatrix& viewM, - const SkMatrix* localMatrix, - SkFilterQuality filterQuality) const { - // we assume diffuse and normal maps have same width and height - // TODO: support different sizes - SkASSERT(fDiffuseMap.width() == fNormalMap.width() && - fDiffuseMap.height() == fNormalMap.height()); - SkMatrix diffM, normM; - - if (!make_mat(fDiffuseMap, this->getLocalMatrix(), localMatrix, &diffM)) { - return nullptr; - } - - if (!make_mat(fNormalMap, fNormLocalMatrix, localMatrix, &normM)) { - return nullptr; - } - - bool doBicubic; - GrTextureParams::FilterMode diffFilterMode = GrSkFilterQualityToGrFilterMode( - SkTMin(filterQuality, kMedium_SkFilterQuality), - viewM, - this->getLocalMatrix(), - &doBicubic); - SkASSERT(!doBicubic); - - GrTextureParams::FilterMode normFilterMode = GrSkFilterQualityToGrFilterMode( - SkTMin(filterQuality, kMedium_SkFilterQuality), - viewM, - fNormLocalMatrix, - &doBicubic); - SkASSERT(!doBicubic); - - // TODO: support other tile modes - GrTextureParams diffParams(kClamp_TileMode, diffFilterMode); - SkAutoTUnref diffuseTexture(GrRefCachedBitmapTexture(context, - fDiffuseMap, diffParams)); - if (!diffuseTexture) { - SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); - return nullptr; - } - - GrTextureParams normParams(kClamp_TileMode, normFilterMode); - SkAutoTUnref normalTexture(GrRefCachedBitmapTexture(context, - fNormalMap, normParams)); - if (!normalTexture) { - SkErrorInternals::SetError(kInternalError_SkError, "Couldn't convert bitmap to texture."); - return nullptr; - } - - SkAutoTUnref inner ( - new LightingFP(diffuseTexture, normalTexture, diffM, normM, diffParams, normParams, fLights, - fInvNormRotation)); - return GrFragmentProcessor::MulOutputByInputAlpha(inner); } #endif @@ -411,19 +301,18 @@ const GrFragmentProcessor* SkLightingShaderImpl::asFragmentProcessor( //////////////////////////////////////////////////////////////////////////// bool SkLightingShaderImpl::isOpaque() const { - return fDiffuseMap.isOpaque(); + return (fDiffuseShader ? fDiffuseShader->isOpaque() : false); } -SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLightingShaderImpl& shader, - const ContextRec& rec, - SkBitmapProcState* diffuseState, - SkBitmapProcState* normalState) +SkLightingShaderImpl::LightingShaderContext::LightingShaderContext( + const SkLightingShaderImpl& shader, const ContextRec& rec, + SkShader::Context* diffuseContext, SkNormalSource::Provider* normalProvider, + void* heapAllocated) : INHERITED(shader, rec) - , fDiffuseState(diffuseState) - , fNormalState(normalState) -{ - const SkPixmap& pixmap = fDiffuseState->fPixmap; - bool isOpaque = pixmap.isOpaque(); + , fDiffuseContext(diffuseContext) + , fNormalProvider(normalProvider) + , fHeapAllocated(heapAllocated) { + bool isOpaque = shader.isOpaque(); // update fFlags uint32_t flags = 0; @@ -431,14 +320,19 @@ SkLightingShaderImpl::LightingShaderContext::LightingShaderContext(const SkLight flags |= kOpaqueAlpha_Flag; } + fPaintColor = rec.fPaint->getColor(); fFlags = flags; } SkLightingShaderImpl::LightingShaderContext::~LightingShaderContext() { - // The bitmap proc states have been created outside of the context on memory that will be freed - // elsewhere. Call the destructors but leave the freeing of the memory to the caller. - fDiffuseState->~SkBitmapProcState(); - fNormalState->~SkBitmapProcState(); + // The dependencies have been created outside of the context on memory that was allocated by + // the onCreateContext() method. Call the destructors and free the memory. + if (fDiffuseContext) { + fDiffuseContext->~Context(); + } + fNormalProvider->~Provider(); + + sk_free(fHeapAllocated); } static inline SkPMColor convert(SkColor3f color, U8CPU a) { @@ -465,76 +359,56 @@ static inline SkPMColor convert(SkColor3f color, U8CPU a) { // larger is better (fewer times we have to loop), but we shouldn't // take up too much stack-space (each one here costs 16 bytes) -#define TMP_COUNT 16 - +#define BUFFER_MAX 16 void SkLightingShaderImpl::LightingShaderContext::shadeSpan(int x, int y, SkPMColor result[], int count) { const SkLightingShaderImpl& lightShader = static_cast(fShader); - uint32_t tmpColor[TMP_COUNT], tmpNormal[TMP_COUNT]; - SkPMColor tmpColor2[2*TMP_COUNT], tmpNormal2[2*TMP_COUNT]; + SkPMColor diffuse[BUFFER_MAX]; + SkPoint3 normals[BUFFER_MAX]; - SkBitmapProcState::MatrixProc diffMProc = fDiffuseState->getMatrixProc(); - SkBitmapProcState::SampleProc32 diffSProc = fDiffuseState->getSampleProc32(); - - SkBitmapProcState::MatrixProc normalMProc = fNormalState->getMatrixProc(); - SkBitmapProcState::SampleProc32 normalSProc = fNormalState->getSampleProc32(); - - int diffMax = fDiffuseState->maxCountForBufferSize(sizeof(tmpColor[0]) * TMP_COUNT); - int normMax = fNormalState->maxCountForBufferSize(sizeof(tmpNormal[0]) * TMP_COUNT); - int max = SkTMin(diffMax, normMax); - - SkASSERT(fDiffuseState->fPixmap.addr()); - SkASSERT(fNormalState->fPixmap.addr()); - - SkPoint3 norm, xformedNorm; + SkColor diffColor = fPaintColor; do { - int n = count; - if (n > max) { - n = max; + int n = SkTMin(count, BUFFER_MAX); + + fNormalProvider->fillScanLine(x, y, normals, n); + + if (fDiffuseContext) { + fDiffuseContext->shadeSpan(x, y, diffuse, n); } - diffMProc(*fDiffuseState, tmpColor, n, x, y); - diffSProc(*fDiffuseState, tmpColor, n, tmpColor2); - - normalMProc(*fNormalState, tmpNormal, n, x, y); - normalSProc(*fNormalState, tmpNormal, n, tmpNormal2); - for (int i = 0; i < n; ++i) { - SkASSERT(0xFF == SkColorGetA(tmpNormal2[i])); // opaque -> unpremul - norm.set(SkIntToScalar(SkGetPackedR32(tmpNormal2[i]))-127.0f, - SkIntToScalar(SkGetPackedG32(tmpNormal2[i]))-127.0f, - SkIntToScalar(SkGetPackedB32(tmpNormal2[i]))-127.0f); - norm.normalize(); - - xformedNorm.fX = lightShader.fInvNormRotation.fX * norm.fX + - lightShader.fInvNormRotation.fY * norm.fY; - xformedNorm.fY = lightShader.fInvNormRotation.fX * norm.fX - - lightShader.fInvNormRotation.fY * norm.fY; - xformedNorm.fZ = norm.fZ; - - SkColor diffColor = SkUnPreMultiply::PMColorToColor(tmpColor2[i]); - - SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); - // This is all done in linear unpremul color space (each component 0..255.0f though) - for (int l = 0; l < lightShader.fLights->numLights(); ++l) { - const SkLight& light = lightShader.fLights->light(l); - - if (SkLight::kAmbient_LightType == light.type()) { - accum += light.color().makeScale(255.0f); - } else { - SkScalar NdotL = xformedNorm.dot(light.dir()); - if (NdotL < 0.0f) { - NdotL = 0.0f; - } - - accum.fX += light.color().fX * SkColorGetR(diffColor) * NdotL; - accum.fY += light.color().fY * SkColorGetG(diffColor) * NdotL; - accum.fZ += light.color().fZ * SkColorGetB(diffColor) * NdotL; - } + if (fDiffuseContext) { + diffColor = SkUnPreMultiply::PMColorToColor(diffuse[i]); } + SkColor3f accum = SkColor3f::Make(0.0f, 0.0f, 0.0f); + + // Adding ambient light + accum.fX += lightShader.fLights->ambientLightColor().fX * SkColorGetR(diffColor); + accum.fY += lightShader.fLights->ambientLightColor().fY * SkColorGetG(diffColor); + accum.fZ += lightShader.fLights->ambientLightColor().fZ * SkColorGetB(diffColor); + + // This is all done in linear unpremul color space (each component 0..255.0f though) + for (int l = 0; l < lightShader.fLights->numLights(); ++l) { + const SkLights::Light& light = lightShader.fLights->light(l); + + SkScalar illuminanceScalingFactor = 1.0f; + + if (SkLights::Light::kDirectional_LightType == light.type()) { + illuminanceScalingFactor = normals[i].dot(light.dir()); + if (illuminanceScalingFactor < 0.0f) { + illuminanceScalingFactor = 0.0f; + } + } + + accum.fX += light.color().fX * SkColorGetR(diffColor) * illuminanceScalingFactor; + accum.fY += light.color().fY * SkColorGetG(diffColor) * illuminanceScalingFactor; + accum.fZ += light.color().fZ * SkColorGetB(diffColor) * illuminanceScalingFactor; + } + + // convert() premultiplies the accumulate color with alpha result[i] = convert(accum, SkColorGetA(diffColor)); } @@ -553,167 +427,84 @@ void SkLightingShaderImpl::toString(SkString* str) const { #endif sk_sp SkLightingShaderImpl::CreateProc(SkReadBuffer& buf) { - SkMatrix diffLocalM; - bool hasDiffLocalM = buf.readBool(); - if (hasDiffLocalM) { - buf.readMatrix(&diffLocalM); - } else { - diffLocalM.reset(); + + // Discarding SkShader flattenable params + bool hasLocalMatrix = buf.readBool(); + SkAssertResult(!hasLocalMatrix); + + sk_sp lights = SkLights::MakeFromBuffer(buf); + + sk_sp normalSource(buf.readFlattenable()); + + bool hasDiffuse = buf.readBool(); + sk_sp diffuseShader = nullptr; + if (hasDiffuse) { + diffuseShader = buf.readFlattenable(); } - SkMatrix normLocalM; - bool hasNormLocalM = buf.readBool(); - if (hasNormLocalM) { - buf.readMatrix(&normLocalM); - } else { - normLocalM.reset(); - } - - SkBitmap diffuse; - if (!buf.readBitmap(&diffuse)) { - return nullptr; - } - diffuse.setImmutable(); - - SkBitmap normal; - if (!buf.readBitmap(&normal)) { - return nullptr; - } - normal.setImmutable(); - - int numLights = buf.readInt(); - - SkLightingShader::Lights::Builder builder; - - for (int l = 0; l < numLights; ++l) { - bool isAmbient = buf.readBool(); - - SkColor3f color; - if (!buf.readScalarArray(&color.fX, 3)) { - return nullptr; - } - - if (isAmbient) { - builder.add(SkLight(color)); - } else { - SkVector3 dir; - if (!buf.readScalarArray(&dir.fX, 3)) { - return nullptr; - } - builder.add(SkLight(color, dir)); - } - } - - SkAutoTUnref lights(builder.finish()); - - return sk_make_sp(diffuse, normal, lights, SkVector::Make(1.0f, 0.0f), - &diffLocalM, &normLocalM); + return sk_make_sp(std::move(diffuseShader), std::move(normalSource), + std::move(lights)); } void SkLightingShaderImpl::flatten(SkWriteBuffer& buf) const { this->INHERITED::flatten(buf); - bool hasNormLocalM = !fNormLocalMatrix.isIdentity(); - buf.writeBool(hasNormLocalM); - if (hasNormLocalM) { - buf.writeMatrix(fNormLocalMatrix); - } + fLights->flatten(buf); - buf.writeBitmap(fDiffuseMap); - buf.writeBitmap(fNormalMap); - - buf.writeInt(fLights->numLights()); - for (int l = 0; l < fLights->numLights(); ++l) { - const SkLight& light = fLights->light(l); - - bool isAmbient = SkLight::kAmbient_LightType == light.type(); - - buf.writeBool(isAmbient); - buf.writeScalarArray(&light.color().fX, 3); - if (!isAmbient) { - buf.writeScalarArray(&light.dir().fX, 3); - } + buf.writeFlattenable(fNormalSource.get()); + buf.writeBool(fDiffuseShader); + if (fDiffuseShader) { + buf.writeFlattenable(fDiffuseShader.get()); } } -bool SkLightingShaderImpl::computeNormTotalInverse(const ContextRec& rec, - SkMatrix* normTotalInverse) const { - SkMatrix total; - total.setConcat(*rec.fMatrix, fNormLocalMatrix); - - const SkMatrix* m = &total; - if (rec.fLocalMatrix) { - total.setConcat(*m, *rec.fLocalMatrix); - m = &total; - } - return m->invert(normTotalInverse); -} - -size_t SkLightingShaderImpl::onContextSize(const ContextRec&) const { - return 2 * sizeof(SkBitmapProcState) + sizeof(LightingShaderContext); +size_t SkLightingShaderImpl::onContextSize(const ContextRec& rec) const { + return sizeof(LightingShaderContext); } SkShader::Context* SkLightingShaderImpl::onCreateContext(const ContextRec& rec, void* storage) const { + size_t heapRequired = (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0) + + fNormalSource->providerSize(rec); + void* heapAllocated = sk_malloc_throw(heapRequired); - SkMatrix diffTotalInv; - // computeTotalInverse was called in SkShader::createContext so we know it will succeed - SkAssertResult(this->computeTotalInverse(rec, &diffTotalInv)); + void* diffuseContextStorage = heapAllocated; + void* normalProviderStorage = (char*) diffuseContextStorage + + (fDiffuseShader ? fDiffuseShader->contextSize(rec) : 0); - SkMatrix normTotalInv; - if (!this->computeNormTotalInverse(rec, &normTotalInv)) { + SkShader::Context *diffuseContext = nullptr; + if (fDiffuseShader) { + diffuseContext = fDiffuseShader->createContext(rec, diffuseContextStorage); + if (!diffuseContext) { + sk_free(heapAllocated); + return nullptr; + } + } + + SkNormalSource::Provider* normalProvider = fNormalSource->asProvider(rec, + normalProviderStorage); + if (!normalProvider) { + diffuseContext->~Context(); + sk_free(heapAllocated); return nullptr; } - void* diffuseStateStorage = (char*)storage + sizeof(LightingShaderContext); - SkBitmapProcState* diffuseState = new (diffuseStateStorage) SkBitmapProcState(fDiffuseMap, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - SkASSERT(diffuseState); - if (!diffuseState->setup(diffTotalInv, *rec.fPaint)) { - diffuseState->~SkBitmapProcState(); - return nullptr; - } - - void* normalStateStorage = (char*)storage + sizeof(LightingShaderContext) + sizeof(SkBitmapProcState); - SkBitmapProcState* normalState = new (normalStateStorage) SkBitmapProcState(fNormalMap, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - SkASSERT(normalState); - if (!normalState->setup(normTotalInv, *rec.fPaint)) { - diffuseState->~SkBitmapProcState(); - normalState->~SkBitmapProcState(); - return nullptr; - } - - return new (storage) LightingShaderContext(*this, rec, diffuseState, normalState); + return new (storage) LightingShaderContext(*this, rec, diffuseContext, normalProvider, + heapAllocated); } /////////////////////////////////////////////////////////////////////////////// -static bool bitmap_is_too_big(const SkBitmap& bm) { - // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it - // communicates between its matrix-proc and its sampler-proc. Until we can - // widen that, we have to reject bitmaps that are larger. - // - static const int kMaxSize = 65535; - - return bm.width() > kMaxSize || bm.height() > kMaxSize; -} - -sk_sp SkLightingShader::Make(const SkBitmap& diffuse, const SkBitmap& normal, - const Lights* lights, - const SkVector& invNormRotation, - const SkMatrix* diffLocalM, const SkMatrix* normLocalM) { - if (diffuse.isNull() || bitmap_is_too_big(diffuse) || - normal.isNull() || bitmap_is_too_big(normal) || - diffuse.width() != normal.width() || - diffuse.height() != normal.height()) { - return nullptr; +sk_sp SkLightingShader::Make(sk_sp diffuseShader, + sk_sp normalSource, + sk_sp lights) { + SkASSERT(lights); + if (!normalSource) { + normalSource = SkNormalSource::MakeFlat(); } - SkASSERT(SkScalarNearlyEqual(invNormRotation.lengthSqd(), SK_Scalar1)); - - return sk_make_sp(diffuse, normal, lights, invNormRotation, diffLocalM, - normLocalM); + return sk_make_sp(std::move(diffuseShader), std::move(normalSource), + std::move(lights)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/skia/skia/src/core/SkLightingShader.h b/gfx/skia/skia/src/core/SkLightingShader.h index ffbcbe9eb4ec..aa90710aa450 100644 --- a/gfx/skia/skia/src/core/SkLightingShader.h +++ b/gfx/skia/skia/src/core/SkLightingShader.h @@ -8,89 +8,30 @@ #ifndef SkLightingShader_DEFINED #define SkLightingShader_DEFINED -#include "SkFlattenable.h" -#include "SkLight.h" +#include "SkLights.h" #include "SkShader.h" -#include "SkTDArray.h" class SkBitmap; class SkMatrix; +class SkNormalSource; class SK_API SkLightingShader { public: - class Lights : public SkRefCnt { - public: - class Builder { - public: - Builder(const SkLight lights[], int numLights) - : fLights(new Lights(lights, numLights)) {} + /** Returns a shader that lights the shape, colored by the diffuseShader, using the + normals from normalSource, with the set of lights provided. - Builder() : fLights(new Lights) {} - - // TODO: limit the number of lights here or just ignore those - // above some maximum? - void add(const SkLight& light) { - if (fLights) { - *fLights->fLights.push() = light; - } - } - - const Lights* finish() { - return fLights.release(); - } - - private: - SkAutoTUnref fLights; - }; - - int numLights() const { - return fLights.count(); - } - - const SkLight& light(int index) const { - return fLights[index]; - } - - private: - Lights() {} - Lights(const SkLight lights[], int numLights) : fLights(lights, numLights) {} - - SkTDArray fLights; - - typedef SkRefCnt INHERITED; - }; - - /** Returns a shader that lights the diffuse and normal maps with a single light. - - It returns a shader with a reference count of 1. - The caller should decrement the shader's reference count when done with the shader. - It is an error for count to be < 2. - @param diffuse the diffuse bitmap - @param normal the normal map - @param light the light applied to the normal map - @param ambient the linear (unpremul) ambient light color. Range is 0..1/channel. - @param localMatrix the matrix mapping the textures to the dest rect - - nullptr will be returned if: - either 'diffuse' or 'normal' are empty - either 'diffuse' or 'normal' are too big (> 65535 on a side) - 'diffuse' and 'normal' aren't the same size + @param diffuseShader the shader that provides the colors. If nullptr, uses the paint's + color. + @param normalSource the source for the shape's normals. If nullptr, assumes straight + up normals (<0,0,1>). + @param lights the lights applied to the normals The lighting equation is currently: - result = LightColor * DiffuseColor * (Normal * LightDir) + AmbientColor + result = (LightColor * dot(Normal, LightDir) + AmbientColor) * DiffuseColor - The normal map is currently assumed to be an 8888 image where the normal at a texel - is retrieved by: - N.x = R-127; - N.y = G-127; - N.z = B-127; - N.normalize(); - The +Z axis is thus encoded in RGB as (127, 127, 255) while the -Z axis is - (127, 127, 0). */ - static sk_sp Make(const SkBitmap& diffuse, const SkBitmap& normal, - const Lights* lights, const SkVector& invNormRotation, - const SkMatrix* diffLocalMatrix, const SkMatrix* normLocalMatrix); + static sk_sp Make(sk_sp diffuseShader, sk_sp normalSource, + sk_sp lights); SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() }; diff --git a/gfx/skia/skia/src/core/SkLights.cpp b/gfx/skia/skia/src/core/SkLights.cpp new file mode 100644 index 000000000000..56c9299437a2 --- /dev/null +++ b/gfx/skia/skia/src/core/SkLights.cpp @@ -0,0 +1,88 @@ + +/* + * 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 "SkLights.h" +#include "SkReadBuffer.h" + +sk_sp SkLights::MakeFromBuffer(SkReadBuffer& buf) { + Builder builder; + + SkColor3f ambColor; + if (!buf.readScalarArray(&ambColor.fX, 3)) { + return nullptr; + } + + builder.setAmbientLightColor(ambColor); + + int numLights = buf.readInt(); + + for (int l = 0; l < numLights; ++l) { + bool isPoint = buf.readBool(); + + SkColor3f color; + if (!buf.readScalarArray(&color.fX, 3)) { + return nullptr; + } + + SkVector3 dirOrPos; + if (!buf.readScalarArray(&dirOrPos.fX, 3)) { + return nullptr; + } + + sk_sp depthMap; + bool hasShadowMap = buf.readBool(); + if (hasShadowMap) { + if (!(depthMap = buf.readImage())) { + return nullptr; + } + } + + bool isRadial = buf.readBool(); + if (isPoint) { + SkScalar intensity; + intensity = buf.readScalar(); + Light light = Light::MakePoint(color, dirOrPos, intensity, isRadial); + light.setShadowMap(depthMap); + builder.add(light); + } else { + Light light = Light::MakeDirectional(color, dirOrPos, isRadial); + light.setShadowMap(depthMap); + builder.add(light); + } + } + + return builder.finish(); +} + +void SkLights::flatten(SkWriteBuffer& buf) const { + buf.writeScalarArray(&this->ambientLightColor().fX, 3); + + buf.writeInt(this->numLights()); + for (int l = 0; l < this->numLights(); ++l) { + const Light& light = this->light(l); + + bool isPoint = Light::kPoint_LightType == light.type(); + + buf.writeBool(isPoint); + buf.writeScalarArray(&light.color().fX, 3); + buf.writeScalarArray(&light.dir().fX, 3); + + bool hasShadowMap = light.getShadowMap() != nullptr; + buf.writeBool(hasShadowMap); + + bool isRadial = light.isRadial(); + buf.writeBool(isRadial); + + if (hasShadowMap) { + buf.writeImage(light.getShadowMap()); + } + if (isPoint) { + buf.writeScalar(light.intensity()); + } + } +} diff --git a/gfx/skia/skia/src/core/SkLineClipper.cpp b/gfx/skia/skia/src/core/SkLineClipper.cpp index 189f03ac7351..8d10656320d0 100644 --- a/gfx/skia/skia/src/core/SkLineClipper.cpp +++ b/gfx/skia/skia/src/core/SkLineClipper.cpp @@ -157,34 +157,8 @@ static bool is_between_unsorted(SkScalar value, } #endif -#ifdef SK_DEBUG -// This is an example of why we need to pin the result computed in -// sect_with_horizontal. If we didn't explicitly pin, is_between_unsorted would -// fail. -// -static void sect_with_horizontal_test_for_pin_results() { - const SkPoint pts[] = { - { -540000, -720000 }, - { -9.10000017e-05f, 9.99999996e-13f } - }; - float x = sect_with_horizontal(pts, 0); - SkASSERT(is_between_unsorted(x, pts[0].fX, pts[1].fX)); -} -#endif - int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip, SkPoint lines[], bool canCullToTheRight) { - -#ifdef SK_DEBUG - { - static bool gOnce; - if (!gOnce) { - sect_with_horizontal_test_for_pin_results(); - gOnce = true; - } - } -#endif - int index0, index1; if (pts[0].fY < pts[1].fY) { diff --git a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp index f4133b01ac0a..401eb41b79dd 100644 --- a/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp +++ b/gfx/skia/skia/src/core/SkLinearBitmapPipeline.cpp @@ -7,84 +7,65 @@ #include "SkLinearBitmapPipeline.h" -#include "SkPM4f.h" #include #include #include -#include "SkColor.h" -#include "SkSize.h" - -#ifdef MOZ_SKIA -#include "mozilla/Tuple.h" - -namespace std { - using mozilla::Tie; - using mozilla::Tuple; - #define tie Tie - #define tuple Tuple -} -#else #include -#endif #include "SkLinearBitmapPipeline_core.h" #include "SkLinearBitmapPipeline_matrix.h" #include "SkLinearBitmapPipeline_tile.h" #include "SkLinearBitmapPipeline_sample.h" +#include "SkNx.h" +#include "SkOpts.h" +#include "SkPM4f.h" -class SkLinearBitmapPipeline::PointProcessorInterface { -public: - virtual ~PointProcessorInterface() { } - // Take the first n (where 0 < n && n < 4) items from xs and ys and sample those points. For - // nearest neighbor, that means just taking the floor xs and ys. For bilerp, this means - // to expand the bilerp filter around the point and sample using that filter. - virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; - // Same as pointListFew, but n = 4. - virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; - // A span is a compact form of sample points that are obtained by mapping points from - // destination space to source space. This is used for horizontal lines only, and is mainly - // used to take advantage of memory coherence for horizontal spans. - virtual void pointSpan(Span span) = 0; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SkLinearBitmapPipeline::Stage +template +SkLinearBitmapPipeline::Stage::~Stage() { + if (fIsInitialized) { + this->get()->~Base(); + } +} + +template +template +void SkLinearBitmapPipeline::Stage::initStage(Next* next, Args&& ... args) { + SkASSERTF(sizeof(Variant) <= sizeof(fSpace), + "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); + + new (&fSpace) Variant(next, std::forward(args)...); + fStageCloner = [this](Next* nextClone, void* addr) { + new (addr) Variant(nextClone, (const Variant&)*this->get()); + }; + fIsInitialized = true; }; -class SkLinearBitmapPipeline::SampleProcessorInterface - : public SkLinearBitmapPipeline::PointProcessorInterface { -public: - // Used for nearest neighbor when scale factor is 1.0. The span can just be repeated with no - // edge pixel alignment problems. This is for handling a very common case. - virtual void repeatSpan(Span span, int32_t repeatCount) = 0; - - // The x's and y's are setup in the following order: - // +--------+--------+ - // | | | - // | px00 | px10 | - // | 0 | 1 | - // +--------+--------+ - // | | | - // | px01 | px11 | - // | 2 | 3 | - // +--------+--------+ - // These pixels coordinates are arranged in the following order in xs and ys: - // px00 px10 px01 px11 - virtual void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) = 0; - - // A span represents sample points that have been mapped from destination space to source - // space. Each sample point is then expanded to the four bilerp points by add +/- 0.5. The - // resulting Y values my be off the tile. When y +/- 0.5 are more than 1 apart because of - // tiling, the second Y is used to denote the retiled Y value. - virtual void bilerpSpan(Span span, SkScalar y) = 0; +template +template +void SkLinearBitmapPipeline::Stage::initSink(Args&& ... args) { + SkASSERTF(sizeof(Variant) <= sizeof(fSpace), + "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); + new (&fSpace) Variant(std::forward(args)...); + fIsInitialized = true; }; -class SkLinearBitmapPipeline::PixelPlacerInterface { -public: - virtual ~PixelPlacerInterface() { } - // Count is normally not needed, but in these early stages of development it is useful to - // check bounds. - // TODO(herb): 4/6/2016 - remove count when code is stable. - virtual void setDestination(void* dst, int count) = 0; - virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; - virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0; -}; +template +template +To* SkLinearBitmapPipeline::Stage::getInterface() { + From* down = static_cast(this->get()); + return static_cast(down); +} + +template +Base* SkLinearBitmapPipeline::Stage::cloneStageTo( + Next* next, Stage* cloneToStage) const +{ + if (!fIsInitialized) return nullptr; + fStageCloner(next, &cloneToStage->fSpace); + return cloneToStage->get(); +} namespace { @@ -107,12 +88,16 @@ public: : fNext{next} , fStrategy{std::forward(args)...}{ } - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { + MatrixStage(Next* next, const MatrixStage& stage) + : fNext{next} + , fStrategy{stage.fStrategy} { } + + void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { fStrategy.processPoints(&xs, &ys); fNext->pointListFew(n, xs, ys); } - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { + void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { fStrategy.processPoints(&xs, &ys); fNext->pointList4(xs, ys); } @@ -148,7 +133,7 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( const SkMatrix& inverse, SkLinearBitmapPipeline::MatrixStage* matrixProc) { if (inverse.hasPerspective()) { - matrixProc->Initialize>( + matrixProc->initStage>( next, SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, SkVector{inverse.getScaleX(), inverse.getScaleY()}, @@ -156,18 +141,18 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( SkVector{inverse.getPerspX(), inverse.getPerspY()}, inverse.get(SkMatrix::kMPersp2)); } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { - matrixProc->Initialize>( + matrixProc->initStage>( next, SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, SkVector{inverse.getScaleX(), inverse.getScaleY()}, SkVector{inverse.getSkewX(), inverse.getSkewY()}); } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { - matrixProc->Initialize>( + matrixProc->initStage>( next, SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, SkVector{inverse.getScaleX(), inverse.getScaleY()}); } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) { - matrixProc->Initialize>( + matrixProc->initStage>( next, SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); } else { @@ -180,21 +165,25 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( // Tile Stage template -class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { +class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { public: - template - NearestTileStage(Next* next, SkISize dimensions) + CombinedTileStage(Next* next, SkISize dimensions) : fNext{next} , fXStrategy{dimensions.width()} , fYStrategy{dimensions.height()}{ } - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { + CombinedTileStage(Next* next, const CombinedTileStage& stage) + : fNext{next} + , fXStrategy{stage.fXStrategy} + , fYStrategy{stage.fYStrategy} { } + + void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { fXStrategy.tileXPoints(&xs); fYStrategy.tileYPoints(&ys); fNext->pointListFew(n, xs, ys); } - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { + void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { fXStrategy.tileXPoints(&xs); fYStrategy.tileYPoints(&ys); fNext->pointList4(xs, ys); @@ -205,9 +194,20 @@ public: SkASSERT(!span.isEmpty()); SkPoint start; SkScalar length; int count; std::tie(start, length, count) = span; + + if (span.count() == 1) { + // DANGER: + // The explicit casts from float to Sk4f are not usually necessary, but are here to + // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug + // 5566. + this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()}); + return; + } + SkScalar x = X(start); SkScalar y = fYStrategy.tileY(Y(start)); Span yAdjustedSpan{{x, y}, length, count}; + if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) { span_fallback(span, this); } @@ -219,164 +219,27 @@ private: YStrategy fYStrategy; }; -template -class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { -public: - template - BilerpTileStage(Next* next, SkISize dimensions) - : fXMax(dimensions.width()) - , fYMax(dimensions.height()) - , fNext{next} - , fXStrategy{dimensions.width()} - , fYStrategy{dimensions.height()}{ } - - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { - fXStrategy.tileXPoints(&xs); - fYStrategy.tileYPoints(&ys); - // TODO: check to see if xs and ys are in range then just call pointListFew on next. - if (n >= 1) this->bilerpPoint(xs[0], ys[0]); - if (n >= 2) this->bilerpPoint(xs[1], ys[1]); - if (n >= 3) this->bilerpPoint(xs[2], ys[2]); - } - - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { - fXStrategy.tileXPoints(&xs); - fYStrategy.tileYPoints(&ys); - // TODO: check to see if xs and ys are in range then just call pointList4 on next. - this->bilerpPoint(xs[0], ys[0]); - this->bilerpPoint(xs[1], ys[1]); - this->bilerpPoint(xs[2], ys[2]); - this->bilerpPoint(xs[3], ys[3]); - } - - struct Wrapper { - void pointSpan(Span span) { - processor->breakIntoEdges(span); - } - - void repeatSpan(Span span, int32_t repeatCount) { - while (repeatCount --> 0) { - processor->pointSpan(span); - } - } - - BilerpTileStage* processor; - }; - - // The span you pass must not be empty. - void pointSpan(Span span) override { - SkASSERT(!span.isEmpty()); - - Wrapper wrapper = {this}; - if (!fXStrategy.maybeProcessSpan(span, &wrapper)) { - span_fallback(span, this); - } - } - -private: - void bilerpPoint(SkScalar x, SkScalar y) { - Sk4f txs = Sk4f{x} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f}; - Sk4f tys = Sk4f{y} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f}; - fXStrategy.tileXPoints(&txs); - fYStrategy.tileYPoints(&tys); - fNext->bilerpEdge(txs, tys); - } - - void handleEdges(Span span, SkScalar dx) { - SkPoint start; SkScalar length; int count; - std::tie(start, length, count) = span; - SkScalar x = X(start); - SkScalar y = Y(start); - SkScalar tiledY = fYStrategy.tileY(y); - while (count > 0) { - this->bilerpPoint(x, tiledY); - x += dx; - count -= 1; - } - } - - void yProcessSpan(Span span) { - SkScalar tiledY = fYStrategy.tileY(span.startY()); - if (0.5f <= tiledY && tiledY < fYMax - 0.5f ) { - Span tiledSpan{{span.startX(), tiledY}, span.length(), span.count()}; - fNext->pointSpan(tiledSpan); - } else { - // Convert to the Y0 bilerp sample set by shifting by -0.5f. Then tile that new y - // value and shift it back resulting in the working Y0. Do the same thing with Y1 but - // in the opposite direction. - SkScalar y0 = fYStrategy.tileY(span.startY() - 0.5f) + 0.5f; - SkScalar y1 = fYStrategy.tileY(span.startY() + 0.5f) - 0.5f; - Span newSpan{{span.startX(), y0}, span.length(), span.count()}; - fNext->bilerpSpan(newSpan, y1); - } - } - void breakIntoEdges(Span span) { - if (span.length() == 0) { - yProcessSpan(span); - } else { - SkScalar dx = span.length() / (span.count() - 1); - if (span.length() > 0) { - Span leftBorder = span.breakAt(0.5f, dx); - if (!leftBorder.isEmpty()) { - this->handleEdges(leftBorder, dx); - } - Span center = span.breakAt(fXMax - 0.5f, dx); - if (!center.isEmpty()) { - this->yProcessSpan(center); - } - - if (!span.isEmpty()) { - this->handleEdges(span, dx); - } - } else { - Span center = span.breakAt(fXMax + 0.5f, dx); - if (!span.isEmpty()) { - this->handleEdges(span, dx); - } - Span leftEdge = center.breakAt(0.5f, dx); - if (!center.isEmpty()) { - this->yProcessSpan(center); - } - if (!leftEdge.isEmpty()) { - this->handleEdges(leftEdge, dx); - } - - } - } - } - - SkScalar fXMax; - SkScalar fYMax; - Next* const fNext; - XStrategy fXStrategy; - YStrategy fYStrategy; -}; - -template -void make_tile_stage( - SkFilterQuality filterQuality, SkISize dimensions, - Next* next, SkLinearBitmapPipeline::TileStage* tileStage) { - if (filterQuality == kNone_SkFilterQuality) { - tileStage->Initialize>(next, dimensions); - } else { - tileStage->Initialize>(next, dimensions); - } -} -template +template void choose_tiler_ymode( SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions, - SkLinearBitmapPipeline::SampleProcessorInterface* next, + Next* next, SkLinearBitmapPipeline::TileStage* tileStage) { switch (yMode) { - case SkShader::kClamp_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + case SkShader::kClamp_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; - case SkShader::kRepeat_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + } + case SkShader::kRepeat_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; - case SkShader::kMirror_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + } + case SkShader::kMirror_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; + } } }; @@ -410,153 +273,304 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler( return tileStage->get(); } - //////////////////////////////////////////////////////////////////////////////////////////////////// -// Source Sampling Stage -template -class NearestNeighborSampler final : public SkLinearBitmapPipeline::SampleProcessorInterface { -public: - template - NearestNeighborSampler(Next* next, Args&&... args) - : fSampler{next, std::forward(args)...} { } +// Specialized Samplers - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { - fSampler.nearestListFew(n, xs, ys); +// RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination +// are the same format and do not need in transformations in pixel space. Therefore, there is no +// need to convert them to HiFi pixel format. +class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface, + public SkLinearBitmapPipeline::DestinationInterface { +public: + RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width) + : fSrc{src}, fWidth{width} { } + + void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { + SkASSERT(fDest + n <= fEnd); + // At this point xs and ys should be >= 0, so trunc is the same as floor. + Sk4i iXs = SkNx_cast(xs); + Sk4i iYs = SkNx_cast(ys); + + if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]); + if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]); + if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]); } - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { - fSampler.nearestList4(xs, ys); + void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { + SkASSERT(fDest + 4 <= fEnd); + Sk4i iXs = SkNx_cast(xs); + Sk4i iYs = SkNx_cast(ys); + *fDest++ = *this->pixelAddress(iXs[0], iYs[0]); + *fDest++ = *this->pixelAddress(iXs[1], iYs[1]); + *fDest++ = *this->pixelAddress(iXs[2], iYs[2]); + *fDest++ = *this->pixelAddress(iXs[3], iYs[3]); } void pointSpan(Span span) override { - fSampler.nearestSpan(span); - } - - void repeatSpan(Span span, int32_t repeatCount) override { - while (repeatCount > 0) { - fSampler.nearestSpan(span); - repeatCount--; + SkASSERT(fDest + span.count() <= fEnd); + if (span.length() != 0.0f) { + int32_t x = SkScalarTruncToInt(span.startX()); + int32_t y = SkScalarTruncToInt(span.startY()); + const uint32_t* src = this->pixelAddress(x, y); + memmove(fDest, src, span.count() * sizeof(uint32_t)); + fDest += span.count(); } } - void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { - SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge."); + void repeatSpan(Span span, int32_t repeatCount) override { + SkASSERT(fDest + span.count() * repeatCount <= fEnd); + + int32_t x = SkScalarTruncToInt(span.startX()); + int32_t y = SkScalarTruncToInt(span.startY()); + const uint32_t* src = this->pixelAddress(x, y); + uint32_t* dest = fDest; + while (repeatCount --> 0) { + memmove(dest, src, span.count() * sizeof(uint32_t)); + dest += span.count(); + } + fDest = dest; } - void bilerpSpan(Span span, SkScalar y) override { - SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan."); + void setDestination(void* dst, int count) override { + fDest = static_cast(dst); + fEnd = fDest + count; } private: - GeneralSampler fSampler; + const uint32_t* pixelAddress(int32_t x, int32_t y) { + return &fSrc[fWidth * y + x]; + } + const uint32_t* const fSrc; + const int32_t fWidth; + uint32_t* fDest; + uint32_t* fEnd; }; -template -class BilerpSampler final : public SkLinearBitmapPipeline::SampleProcessorInterface { +// RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination +// are the same format and do not need in transformations in pixel space. Therefore, there is no +// need to convert them to HiFi pixel format. +class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface, + public SkLinearBitmapPipeline::DestinationInterface { public: - template - BilerpSampler(Next* next, Args&&... args) - : fSampler{next, std::forward(args)...} { } + RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width) + : fSrc{src}, fWidth{width} { } - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { - fSampler.bilerpListFew(n, xs, ys); + void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { + SkASSERT(fDest + n <= fEnd); + // At this point xs and ys should be >= 0, so trunc is the same as floor. + Sk4i iXs = SkNx_cast(xs); + Sk4i iYs = SkNx_cast(ys); + + if (n >= 1) blendPixelAt(iXs[0], iYs[0]); + if (n >= 2) blendPixelAt(iXs[1], iYs[1]); + if (n >= 3) blendPixelAt(iXs[2], iYs[2]); } - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { - fSampler.bilerpList4(xs, ys); + void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { + SkASSERT(fDest + 4 <= fEnd); + Sk4i iXs = SkNx_cast(xs); + Sk4i iYs = SkNx_cast(ys); + blendPixelAt(iXs[0], iYs[0]); + blendPixelAt(iXs[1], iYs[1]); + blendPixelAt(iXs[2], iYs[2]); + blendPixelAt(iXs[3], iYs[3]); } void pointSpan(Span span) override { - fSampler.bilerpSpan(span); - } - - void repeatSpan(Span span, int32_t repeatCount) override { - while (repeatCount > 0) { - fSampler.bilerpSpan(span); - repeatCount--; + if (span.length() != 0.0f) { + this->repeatSpan(span, 1); } } - void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { - fSampler.bilerpEdge(xs, ys); + void repeatSpan(Span span, int32_t repeatCount) override { + SkASSERT(fDest + span.count() * repeatCount <= fEnd); + SkASSERT(span.count() > 0); + SkASSERT(repeatCount > 0); + + int32_t x = (int32_t)span.startX(); + int32_t y = (int32_t)span.startY(); + const uint32_t* beginSpan = this->pixelAddress(x, y); + + SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count()); + + fDest += span.count() * repeatCount; + + SkASSERT(fDest <= fEnd); } - void bilerpSpan(Span span, SkScalar y) override { - fSampler.bilerpSpanWithY(span, y); + void setDestination(void* dst, int count) override { + SkASSERT(count > 0); + fDest = static_cast(dst); + fEnd = fDest + count; } private: - GeneralSampler fSampler; + const uint32_t* pixelAddress(int32_t x, int32_t y) { + return &fSrc[fWidth * y + x]; + } + + void blendPixelAt(int32_t x, int32_t y) { + const uint32_t* src = this->pixelAddress(x, y); + SkOpts::srcover_srgb_srgb(fDest, src, 1, 1); + fDest += 1; + } + + const uint32_t* const fSrc; + const int32_t fWidth; + uint32_t* fDest; + uint32_t* fEnd; }; -using Placer = SkLinearBitmapPipeline::PixelPlacerInterface; +using Blender = SkLinearBitmapPipeline::BlendProcessorInterface; -template