diff options
Diffstat (limited to 'gfx/2d/DrawTargetSkia.cpp')
-rw-r--r-- | gfx/2d/DrawTargetSkia.cpp | 654 |
1 files changed, 433 insertions, 221 deletions
diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 005ba2b6d..837cf9922 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -4,12 +4,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DrawTargetSkia.h" +#include "SourceSurfaceCairo.h" #include "SourceSurfaceSkia.h" #include "ScaledFontBase.h" -#include "skia/SkDevice.h" +#include "ScaledFontCairo.h" +#include "skia/SkGpuDevice.h" +#include "skia/SkBitmapDevice.h" +#include "FilterNodeSoftware.h" #ifdef USE_SKIA_GPU #include "skia/SkGpuDevice.h" +#include "skia/GrGLInterface.h" #endif #include "skia/SkTypeface.h" @@ -17,26 +22,22 @@ #include "skia/SkBlurDrawLooper.h" #include "skia/SkBlurMaskFilter.h" #include "skia/SkColorFilter.h" +#include "skia/SkDropShadowImageFilter.h" #include "skia/SkLayerRasterizer.h" #include "skia/SkLayerDrawLooper.h" #include "skia/SkDashPathEffect.h" #include "Logging.h" -#include "HelpersSkia.h" #include "Tools.h" +#include "DataSurfaceHelpers.h" #include <algorithm> -#ifdef ANDROID -# define USE_SOFT_CLIPPING false -#else -# define USE_SOFT_CLIPPING true -#endif - namespace mozilla { namespace gfx { class GradientStopsSkia : public GradientStops { public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsSkia) GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops, ExtendMode aExtendMode) : mCount(aNumStops) , mExtendMode(aExtendMode) @@ -71,7 +72,7 @@ public: } } - BackendType GetBackendType() const { return BACKEND_SKIA; } + BackendType GetBackendType() const { return BackendType::SKIA; } std::vector<SkColor> mColors; std::vector<SkScalar> mPositions; @@ -79,43 +80,85 @@ public: ExtendMode mExtendMode; }; +/** + * When constructing a temporary SkBitmap via GetBitmapForSurface, we may also + * have to construct a temporary DataSourceSurface, which must live as long as + * the SkBitmap. So we return a pair of the SkBitmap and the (optional) + * temporary surface. + */ +struct TempBitmap +{ + SkBitmap mBitmap; + RefPtr<SourceSurface> mTmpSurface; +}; + +static TempBitmap +GetBitmapForSurface(SourceSurface* aSurface) +{ + TempBitmap result; + + if (aSurface->GetType() == SurfaceType::SKIA) { + result.mBitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap(); + return result; + } + + RefPtr<DataSourceSurface> surf = aSurface->GetDataSurface(); + if (!surf) { + MOZ_CRASH("Non-skia SourceSurfaces need to be DataSourceSurfaces"); + } + + SkAlphaType alphaType = (surf->GetFormat() == SurfaceFormat::B8G8R8X8) ? + kOpaque_SkAlphaType : kPremul_SkAlphaType; + + SkImageInfo info = SkImageInfo::Make(surf->GetSize().width, + surf->GetSize().height, + GfxFormatToSkiaColorType(surf->GetFormat()), + alphaType); + result.mBitmap.setInfo(info, surf->Stride()); + + result.mBitmap.setPixels(surf->GetData()); + result.mTmpSurface = surf.forget(); + return result; +} + DrawTargetSkia::DrawTargetSkia() + : +#ifdef USE_SKIA_GPU + mTexture(0), +#endif + mSnapshot(nullptr) { } DrawTargetSkia::~DrawTargetSkia() { - if (mSnapshots.size()) { - for (std::vector<SourceSurfaceSkia*>::iterator iter = mSnapshots.begin(); - iter != mSnapshots.end(); iter++) { - (*iter)->DrawTargetDestroyed(); - } - // All snapshots will now have copied data. - mSnapshots.clear(); - } } TemporaryRef<SourceSurface> DrawTargetSkia::Snapshot() { - RefPtr<SourceSurfaceSkia> source = new SourceSurfaceSkia(); - - if (!source->InitFromCanvas(mCanvas.get(), mFormat, this)) - return nullptr; + RefPtr<SourceSurfaceSkia> snapshot = mSnapshot; + if (!snapshot) { + snapshot = new SourceSurfaceSkia(); + mSnapshot = snapshot; + if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this)) + return nullptr; + } - AppendSnapshot(source); - return source; + return snapshot.forget(); } -void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0) +static void +SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap, + Float aAlpha = 1.0) { switch (aPattern.GetType()) { - case PATTERN_COLOR: { + case PatternType::COLOR: { Color color = static_cast<const ColorPattern&>(aPattern).mColor; aPaint.setColor(ColorToSkColor(color, aAlpha)); break; } - case PATTERN_LINEAR_GRADIENT: { + case PatternType::LINEAR_GRADIENT: { const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); @@ -125,17 +168,18 @@ void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1. points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y)); - SkShader* shader = SkGradientShader::CreateLinear(points, - &stops->mColors.front(), - &stops->mPositions.front(), - stops->mCount, + SkShader* shader = SkGradientShader::CreateLinear(points, + &stops->mColors.front(), + &stops->mPositions.front(), + stops->mCount, mode); if (shader) { SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); } } else { @@ -143,7 +187,7 @@ void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1. } break; } - case PATTERN_RADIAL_GRADIENT: { + case PatternType::RADIAL_GRADIENT: { const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern); GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get()); SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode); @@ -153,19 +197,20 @@ void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1. points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y)); points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y)); - SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0], + SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0], SkFloatToScalar(pat.mRadius1), - points[1], + points[1], SkFloatToScalar(pat.mRadius2), - &stops->mColors.front(), - &stops->mPositions.front(), - stops->mCount, + &stops->mColors.front(), + &stops->mPositions.front(), + stops->mCount, mode); if (shader) { SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); } } else { @@ -173,36 +218,53 @@ void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1. } break; } - case PATTERN_SURFACE: { + case PatternType::SURFACE: { const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern); - const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap(); + aTmpBitmap = GetBitmapForSurface(pat.mSurface); + SkBitmap& bitmap = aTmpBitmap.mBitmap; - SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode); - SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode); SkMatrix mat; GfxMatrixToSkiaMatrix(pat.mMatrix, mat); - shader->setLocalMatrix(mat); - SkSafeUnref(aPaint.setShader(shader)); - if (pat.mFilter == FILTER_POINT) { - aPaint.setFilterBitmap(false); + + if (!pat.mSamplingRect.IsEmpty()) { + SkIRect rect = IntRectToSkIRect(pat.mSamplingRect); + bitmap.extractSubset(&bitmap, rect); + mat.preTranslate(rect.x(), rect.y()); + } + + SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode); + SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat); + SkSafeUnref(shader); + SkSafeUnref(aPaint.setShader(matrixShader)); + if (pat.mFilter == Filter::POINT) { + aPaint.setFilterLevel(SkPaint::kNone_FilterLevel); } break; } } } +static inline Rect +GetClipBounds(SkCanvas *aCanvas) +{ + SkRect clipBounds; + aCanvas->getClipBounds(&clipBounds); + return SkRectToRect(clipBounds); +} + struct AutoPaintSetup { - AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern) + AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern, const Rect* aMaskBounds = nullptr) : mNeedsRestore(false), mAlpha(1.0) { - Init(aCanvas, aOptions); - SetPaintPattern(mPaint, aPattern, mAlpha); + Init(aCanvas, aOptions, aMaskBounds); + SetPaintPattern(mPaint, aPattern, mTmpBitmap, mAlpha); } - AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions) + AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr) : mNeedsRestore(false), mAlpha(1.0) { - Init(aCanvas, aOptions); + Init(aCanvas, aOptions, aMaskBounds); } ~AutoPaintSetup() @@ -212,40 +274,43 @@ struct AutoPaintSetup { } } - void Init(SkCanvas *aCanvas, const DrawOptions& aOptions) + void Init(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds) { mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); mCanvas = aCanvas; //TODO: Can we set greyscale somehow? - if (aOptions.mAntialiasMode != AA_NONE) { + if (aOptions.mAntialiasMode != AntialiasMode::NONE) { mPaint.setAntiAlias(true); } else { mPaint.setAntiAlias(false); } - MOZ_ASSERT(aOptions.mSnapping == SNAP_NONE, "Pixel snapping not supported yet!"); - + Rect clipBounds = GetClipBounds(aCanvas); + bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) && + (!aMaskBounds || !aMaskBounds->Contains(clipBounds)); + // TODO: We could skip the temporary for operator_source and just // clear the clip rect. The other operators would be harder // but could be worth it to skip pushing a group. - if (!IsOperatorBoundByMask(aOptions.mCompositionOp)) { + if (needsGroup) { mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode); SkPaint temp; temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp)); - temp.setAlpha(U8CPU(aOptions.mAlpha*255)); + temp.setAlpha(ColorFloatToByte(aOptions.mAlpha)); //TODO: Get a rect here mCanvas->saveLayer(nullptr, &temp); mNeedsRestore = true; } else { - mPaint.setAlpha(U8CPU(aOptions.mAlpha*255.0)); + mPaint.setAlpha(ColorFloatToByte(aOptions.mAlpha)); mAlpha = aOptions.mAlpha; } - mPaint.setFilterBitmap(true); + mPaint.setFilterLevel(SkPaint::kLow_FilterLevel); } // TODO: Maybe add an operator overload to access this easier? SkPaint mPaint; + TempBitmap mTmpBitmap; bool mNeedsRestore; SkCanvas* mCanvas; Float mAlpha; @@ -264,8 +329,15 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface, const DrawSurfaceOptions &aSurfOptions, const DrawOptions &aOptions) { - if (aSurface->GetType() != SURFACE_SKIA) { - return; + RefPtr<SourceSurface> dataSurface; + + if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) { + dataSurface = aSurface->GetDataSurface(); + if (!dataSurface) { + gfxDebug() << *this << ": DrawSurface() can't draw surface"; + return; + } + aSurface = dataSurface.get(); } if (aSource.IsEmpty()) { @@ -277,19 +349,35 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface, SkRect destRect = RectToSkRect(aDest); SkRect sourceRect = RectToSkRect(aSource); - SkMatrix matrix; - matrix.setRectToRect(sourceRect, destRect, SkMatrix::kFill_ScaleToFit); - - const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap(); - - AutoPaintSetup paint(mCanvas.get(), aOptions); - SkShader *shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - shader->setLocalMatrix(matrix); - SkSafeUnref(paint.mPaint.setShader(shader)); - if (aSurfOptions.mFilter != FILTER_LINEAR) { - paint.mPaint.setFilterBitmap(false); + TempBitmap bitmap = GetBitmapForSurface(aSurface); + + AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest); + if (aSurfOptions.mFilter == Filter::POINT) { + paint.mPaint.setFilterLevel(SkPaint::kNone_FilterLevel); + } + + mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint); +} + +DrawTargetType +DrawTargetSkia::GetType() const +{ +#ifdef USE_SKIA_GPU + if (mGrContext) { + return DrawTargetType::HARDWARE_RASTER; } - mCanvas->drawRect(destRect, paint.mPaint); +#endif + return DrawTargetType::SOFTWARE_RASTER; +} + +void +DrawTargetSkia::DrawFilter(FilterNode *aNode, + const Rect &aSourceRect, + const Point &aDestPoint, + const DrawOptions &aOptions) +{ + FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode); + filter->Draw(this, aSourceRect, aDestPoint, aOptions); } void @@ -300,59 +388,27 @@ DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface, Float aSigma, CompositionOp aOperator) { + if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) { + return; + } + MarkChanged(); - mCanvas->save(SkCanvas::kMatrix_SaveFlag); + + mCanvas->save(); mCanvas->resetMatrix(); - uint32_t blurFlags = SkBlurMaskFilter::kHighQuality_BlurFlag | - SkBlurMaskFilter::kIgnoreTransform_BlurFlag; - const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap(); - SkShader* shader = SkShader::CreateBitmapShader(bitmap, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); - SkMatrix matrix; - matrix.reset(); - matrix.setTranslateX(SkFloatToScalar(aDest.x)); - matrix.setTranslateY(SkFloatToScalar(aDest.y)); - shader->setLocalMatrix(matrix); - SkLayerDrawLooper* dl = new SkLayerDrawLooper; - SkLayerDrawLooper::LayerInfo info; - info.fPaintBits |= SkLayerDrawLooper::kShader_Bit; - SkPaint *layerPaint = dl->addLayer(info); - layerPaint->setShader(shader); - - info.fPaintBits = 0; - info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit; - info.fPaintBits |= SkLayerDrawLooper::kColorFilter_Bit; - info.fColorMode = SkXfermode::kDst_Mode; - info.fOffset.set(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); - info.fPostTranslate = true; - - SkMaskFilter* mf = SkBlurMaskFilter::Create(aSigma, SkBlurMaskFilter::kNormal_BlurStyle, blurFlags); - SkColor color = ColorToSkColor(aColor, 1); - SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode); - - - layerPaint = dl->addLayer(info); - SkSafeUnref(layerPaint->setMaskFilter(mf)); - SkSafeUnref(layerPaint->setColorFilter(cf)); - layerPaint->setColor(color); - - // TODO: This is using the rasterizer to calculate an alpha mask - // on both the shadow and normal layers. We should fix this - // properly so it only happens for the shadow layer - SkLayerRasterizer *raster = new SkLayerRasterizer(); - SkPaint maskPaint; - SkSafeUnref(maskPaint.setShader(shader)); - raster->addLayer(maskPaint, 0, 0); - + TempBitmap bitmap = GetBitmapForSurface(aSurface); + SkPaint paint; - paint.setAntiAlias(true); - SkSafeUnref(paint.setRasterizer(raster)); + + SkImageFilter* filter = SkDropShadowImageFilter::Create(aOffset.x, aOffset.y, + aSigma, aSigma, + ColorToSkColor(aColor, 1.0)); + + paint.setImageFilter(filter); paint.setXfermodeMode(GfxOpToSkiaOp(aOperator)); - SkSafeUnref(paint.setLooper(dl)); - SkRect rect = RectToSkRect(Rect(Float(aDest.x), Float(aDest.y), - Float(bitmap.width()), Float(bitmap.height()))); - mCanvas->drawRect(rect, paint); + mCanvas->drawBitmap(bitmap.mBitmap, aDest.x, aDest.y, &paint); mCanvas->restore(); } @@ -363,7 +419,7 @@ DrawTargetSkia::FillRect(const Rect &aRect, { MarkChanged(); SkRect rect = RectToSkRect(aRect); - AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern, &aRect); mCanvas->drawRect(rect, paint.mPaint); } @@ -376,7 +432,7 @@ DrawTargetSkia::Stroke(const Path *aPath, { MarkChanged(); MOZ_ASSERT(aPath, "Null path"); - if (aPath->GetBackendType() != BACKEND_SKIA) { + if (aPath->GetBackendType() != BackendType::SKIA) { return; } @@ -406,7 +462,7 @@ DrawTargetSkia::StrokeRect(const Rect &aRect, mCanvas->drawRect(RectToSkRect(aRect), paint.mPaint); } -void +void DrawTargetSkia::StrokeLine(const Point &aStart, const Point &aEnd, const Pattern &aPattern, @@ -419,8 +475,8 @@ DrawTargetSkia::StrokeLine(const Point &aStart, return; } - mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y), - SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y), + mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y), + SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y), paint.mPaint); } @@ -430,7 +486,7 @@ DrawTargetSkia::Fill(const Path *aPath, const DrawOptions &aOptions) { MarkChanged(); - if (aPath->GetBackendType() != BACKEND_SKIA) { + if (aPath->GetBackendType() != BackendType::SKIA) { return; } @@ -446,11 +502,11 @@ DrawTargetSkia::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aOptions, - const GlyphRenderingOptions*) + const GlyphRenderingOptions *aRenderingOptions) { - if (aFont->GetType() != FONT_MAC && - aFont->GetType() != FONT_SKIA && - aFont->GetType() != FONT_GDI) { + if (aFont->GetType() != FontType::MAC && + aFont->GetType() != FontType::SKIA && + aFont->GetType() != FontType::GDI) { return; } @@ -462,7 +518,30 @@ DrawTargetSkia::FillGlyphs(ScaledFont *aFont, paint.mPaint.setTypeface(skiaFont->GetSkTypeface()); paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize)); paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); - + + if (aRenderingOptions && aRenderingOptions->GetType() == FontType::CAIRO) { + switch (static_cast<const GlyphRenderingOptionsCairo*>(aRenderingOptions)->GetHinting()) { + case FontHinting::NONE: + paint.mPaint.setHinting(SkPaint::kNo_Hinting); + break; + case FontHinting::LIGHT: + paint.mPaint.setHinting(SkPaint::kSlight_Hinting); + break; + case FontHinting::NORMAL: + paint.mPaint.setHinting(SkPaint::kNormal_Hinting); + break; + case FontHinting::FULL: + paint.mPaint.setHinting(SkPaint::kFull_Hinting); + break; + } + + if (static_cast<const GlyphRenderingOptionsCairo*>(aRenderingOptions)->GetAutoHinting()) { + paint.mPaint.setAutohinted(true); + } + } else { + paint.mPaint.setHinting(SkPaint::kNormal_Hinting); + } + std::vector<uint16_t> indices; std::vector<SkPoint> offsets; indices.resize(aBuffer.mNumGlyphs); @@ -486,32 +565,55 @@ DrawTargetSkia::Mask(const Pattern &aSource, AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); SkPaint maskPaint; - SetPaintPattern(maskPaint, aMask); - - SkLayerRasterizer *raster = new SkLayerRasterizer(); - raster->addLayer(maskPaint); - SkSafeUnref(paint.mPaint.setRasterizer(raster)); - - // Skia only uses the mask rasterizer when we are drawing a path/rect. - // Take our destination bounds and convert them into user space to use - // as the path to draw. - SkPath path; - path.addRect(SkRect::MakeWH(SkScalar(mSize.width), SkScalar(mSize.height))); - - Matrix temp = mTransform; - temp.Invert(); - SkMatrix mat; - GfxMatrixToSkiaMatrix(temp, mat); - path.transform(mat); + TempBitmap tmpBitmap; + SetPaintPattern(maskPaint, aMask, tmpBitmap); + + SkLayerRasterizer::Builder builder; + builder.addLayer(maskPaint); + SkAutoTUnref<SkRasterizer> raster(builder.detachRasterizer()); + paint.mPaint.setRasterizer(raster.get()); + + mCanvas->drawRect(SkRectCoveringWholeSurface(), paint.mPaint); +} - mCanvas->drawPath(path, paint.mPaint); +void +DrawTargetSkia::MaskSurface(const Pattern &aSource, + SourceSurface *aMask, + Point aOffset, + const DrawOptions &aOptions) +{ + MarkChanged(); + AutoPaintSetup paint(mCanvas.get(), aOptions, aSource); + + TempBitmap bitmap = GetBitmapForSurface(aMask); + if (bitmap.mBitmap.colorType() == kAlpha_8_SkColorType) { + mCanvas->drawBitmap(bitmap.mBitmap, aOffset.x, aOffset.y, &paint.mPaint); + } else { + SkPaint maskPaint; + TempBitmap tmpBitmap; + SetPaintPattern(maskPaint, SurfacePattern(aMask, ExtendMode::CLAMP), tmpBitmap); + + SkMatrix transform = maskPaint.getShader()->getLocalMatrix(); + transform.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y)); + SkShader* matrixShader = SkShader::CreateLocalMatrixShader(maskPaint.getShader(), transform); + SkSafeUnref(maskPaint.setShader(matrixShader)); + + SkLayerRasterizer::Builder builder; + builder.addLayer(maskPaint); + SkAutoTUnref<SkRasterizer> raster(builder.detachRasterizer()); + paint.mPaint.setRasterizer(raster.get()); + + IntSize size = aMask->GetSize(); + Rect rect = Rect(aOffset.x, aOffset.y, size.width, size.height); + mCanvas->drawRect(RectToSkRect(rect), paint.mPaint); + } } TemporaryRef<SourceSurface> DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - SurfaceFormat aFormat) const + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const { RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia(); @@ -519,8 +621,8 @@ DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData, gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize; return nullptr; } - - return newSurf; + + return newSurf.forget(); } TemporaryRef<DrawTarget> @@ -530,18 +632,72 @@ DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFor if (!target->Init(aSize, aFormat)) { return nullptr; } - return target; + return target.forget(); +} + +bool +DrawTargetSkia::UsingSkiaGPU() const +{ +#ifdef USE_SKIA_GPU + return !!mTexture; +#else + return false; +#endif } TemporaryRef<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const { - return nullptr; + if (aSurface->GetType() == SurfaceType::SKIA) { + return aSurface; + } + + if (!UsingSkiaGPU()) { + // If we're not using skia-gl then drawing doesn't require any + // uploading, so any data surface is fine. Call GetDataSurface + // to trigger any required readback so that it only happens + // once. + return aSurface->GetDataSurface(); + } + + // If we are using skia-gl then we want to copy into a surface that + // will cache the uploaded gl texture. + RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface(); + DataSourceSurface::MappedSurface map; + if (!dataSurf->Map(DataSourceSurface::READ, &map)) { + return nullptr; + } + + RefPtr<SourceSurface> result = CreateSourceSurfaceFromData(map.mData, + dataSurf->GetSize(), + map.mStride, + dataSurf->GetFormat()); + dataSurf->Unmap(); + return result.forget(); } TemporaryRef<SourceSurface> DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const { + if (aSurface.mType == NativeSurfaceType::CAIRO_SURFACE) { + if (aSurface.mSize.width <= 0 || + aSurface.mSize.height <= 0) { + gfxWarning() << "Can't create a SourceSurface without a valid size"; + return nullptr; + } + cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface); + return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat); +#if USE_SKIA_GPU + } else if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE) { + RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia(); + unsigned int texture = (unsigned int)((uintptr_t)aSurface.mSurface); + if (UsingSkiaGPU() && newSurf->InitFromTexture((DrawTargetSkia*)this, texture, aSurface.mSize, aSurface.mFormat)) { + return newSurf; + } + return nullptr; +#endif + } + return nullptr; } @@ -551,23 +707,39 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface, const IntPoint &aDestination) { //TODO: We could just use writePixels() here if the sourceRect is the entire source - - if (aSurface->GetType() != SURFACE_SKIA) { + + if (aSurface->GetType() != SurfaceType::SKIA && aSurface->GetType() != SurfaceType::DATA) { return; } MarkChanged(); - - const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap(); + + TempBitmap bitmap = GetBitmapForSurface(aSurface); + + // This is a fast path that is disabled for now to mimimize risk + if (false && !bitmap.mBitmap.getTexture() && mCanvas->imageInfo() == bitmap.mBitmap.info()) { + SkBitmap bm(bitmap.mBitmap); + bm.lockPixels(); + if (bm.getPixels()) { + SkImageInfo info = bm.info(); + info.fWidth = aSourceRect.width; + info.fHeight = aSourceRect.height; + uint8_t* pixels = static_cast<uint8_t*>(bm.getPixels()); + // adjust pixels for the source offset + pixels += aSourceRect.x + aSourceRect.y*bm.rowBytes(); + mCanvas->writePixels(info, pixels, bm.rowBytes(), aDestination.x, aDestination.y); + return; + } + } mCanvas->save(); mCanvas->resetMatrix(); - SkRect dest = IntRectToSkRect(IntRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height)); + SkRect dest = IntRectToSkRect(IntRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height)); SkIRect source = IntRectToSkIRect(aSourceRect); mCanvas->clipRect(dest, SkRegion::kReplace_Op); SkPaint paint; - if (mCanvas->getDevice()->config() == SkBitmap::kRGB_565_Config) { + if (mCanvas->imageInfo().colorType() == kRGB_565_SkColorType) { // Set the xfermode to SOURCE_OVER to workaround // http://code.google.com/p/skia/issues/detail?id=628 // RGB565 is opaque so they're equivalent anyway @@ -575,15 +747,33 @@ DrawTargetSkia::CopySurface(SourceSurface *aSurface, } else { paint.setXfermodeMode(SkXfermode::kSrc_Mode); } - - mCanvas->drawBitmapRect(bitmap, &source, dest, &paint); + // drawBitmapRect with A8 bitmaps ends up doing a mask operation + // so we need to clear before + if (bitmap.mBitmap.colorType() == kAlpha_8_SkColorType) { + SkPaint clearPaint; + clearPaint.setColor(SkColorSetARGB(0, 0, 0, 0)); + clearPaint.setXfermodeMode(SkXfermode::kSrc_Mode); + mCanvas->drawPaint(clearPaint); + } + mCanvas->drawBitmapRect(bitmap.mBitmap, &source, dest, &paint); mCanvas->restore(); } bool DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) { - SkAutoTUnref<SkDevice> device(new SkDevice(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height)); + SkAlphaType alphaType = (aFormat == SurfaceFormat::B8G8R8X8) ? + kOpaque_SkAlphaType : kPremul_SkAlphaType; + + SkImageInfo skiInfo = SkImageInfo::Make( + aSize.width, aSize.height, + GfxFormatToSkiaColorType(aFormat), + alphaType); + + SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(skiInfo)); + if (!device) { + return false; + } SkBitmap bitmap = device->accessBitmap(true); if (!bitmap.allocPixels()) { @@ -592,60 +782,70 @@ DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat) bitmap.eraseARGB(0, 0, 0, 0); - SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get())); + mCanvas.adopt(new SkCanvas(device.get())); mSize = aSize; - mCanvas = canvas.get(); mFormat = aFormat; return true; } #ifdef USE_SKIA_GPU -void -DrawTargetSkia::InitWithFBO(unsigned int aFBOID, GrContext* aGrContext, const IntSize &aSize, SurfaceFormat aFormat) +bool +DrawTargetSkia::InitWithGrContext(GrContext* aGrContext, + const IntSize &aSize, + SurfaceFormat aFormat) { - GrPlatformRenderTargetDesc targetDescriptor; + MOZ_ASSERT(aGrContext, "null GrContext"); - targetDescriptor.fWidth = aSize.width; - targetDescriptor.fHeight = aSize.height; - targetDescriptor.fConfig = GfxFormatToGrConfig(aFormat); + mGrContext = aGrContext; + mSize = aSize; + mFormat = aFormat; + + GrTextureDesc targetDescriptor; + + targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit; + targetDescriptor.fWidth = mSize.width; + targetDescriptor.fHeight = mSize.height; + targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat); + targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin; targetDescriptor.fSampleCnt = 0; - targetDescriptor.fRenderTargetHandle = aFBOID; - SkAutoTUnref<GrRenderTarget> target(aGrContext->createPlatformRenderTarget(targetDescriptor)); + SkAutoTUnref<GrTexture> skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0)); + if (!skiaTexture) { + return false; + } - SkAutoTUnref<SkDevice> device(new SkGpuDevice(aGrContext, target.get())); - SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get())); - mSize = aSize; + mTexture = (uint32_t)skiaTexture->getTextureHandle(); - mCanvas = canvas.get(); - mFormat = aFormat; + SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget())); + mCanvas.adopt(new SkCanvas(device.get())); + + return true; } + #endif void DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) { - bool isOpaque = false; - if (aFormat == FORMAT_B8G8R8X8) { + SkAlphaType alphaType = kPremul_SkAlphaType; + if (aFormat == SurfaceFormat::B8G8R8X8) { // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX ConvertBGRXToBGRA(aData, aSize, aStride); - isOpaque = true; + alphaType = kOpaque_SkAlphaType; } - - SkAutoTUnref<SkDevice> device(new SkDevice(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, isOpaque)); - SkBitmap bitmap = (SkBitmap)device->accessBitmap(true); - bitmap.lockPixels(); + SkBitmap bitmap; + + SkImageInfo info = SkImageInfo::Make(aSize.width, + aSize.height, + GfxFormatToSkiaColorType(aFormat), + alphaType); + bitmap.setInfo(info, aStride); bitmap.setPixels(aData); - bitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride); - bitmap.unlockPixels(); - bitmap.notifyPixelsChanged(); + mCanvas.adopt(new SkCanvas(bitmap)); - SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get())); mSize = aSize; - - mCanvas = canvas.get(); mFormat = aFormat; } @@ -658,11 +858,22 @@ DrawTargetSkia::SetTransform(const Matrix& aTransform) mTransform = aTransform; } -TemporaryRef<PathBuilder> +void* +DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType) +{ +#ifdef USE_SKIA_GPU + if (aType == NativeSurfaceType::OPENGL_TEXTURE) { + return (void*)((uintptr_t)mTexture); + } +#endif + return nullptr; +} + + +TemporaryRef<PathBuilder> DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const { - RefPtr<PathBuilderSkia> pb = new PathBuilderSkia(aFillRule); - return pb; + return new PathBuilderSkia(aFillRule); } void @@ -671,7 +882,7 @@ DrawTargetSkia::ClearRect(const Rect &aRect) MarkChanged(); SkPaint paint; mCanvas->save(); - mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); + mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, true); paint.setColor(SkColorSetARGB(0, 0, 0, 0)); paint.setXfermodeMode(SkXfermode::kSrc_Mode); mCanvas->drawPaint(paint); @@ -681,13 +892,13 @@ DrawTargetSkia::ClearRect(const Rect &aRect) void DrawTargetSkia::PushClip(const Path *aPath) { - if (aPath->GetBackendType() != BACKEND_SKIA) { + if (aPath->GetBackendType() != BackendType::SKIA) { return; } const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath); - mCanvas->save(SkCanvas::kClip_SaveFlag); - mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); + mCanvas->save(); + mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, true); } void @@ -695,8 +906,8 @@ DrawTargetSkia::PushClipRect(const Rect& aRect) { SkRect rect = RectToSkRect(aRect); - mCanvas->save(SkCanvas::kClip_SaveFlag); - mCanvas->clipRect(rect, SkRegion::kIntersect_Op, USE_SOFT_CLIPPING); + mCanvas->save(); + mCanvas->clipRect(rect, SkRegion::kIntersect_Op, true); } void @@ -714,36 +925,37 @@ DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, Ex stops[i] = aStops[i]; } std::stable_sort(stops.begin(), stops.end()); - + return new GradientStopsSkia(stops, aNumStops, aExtendMode); } -void -DrawTargetSkia::AppendSnapshot(SourceSurfaceSkia* aSnapshot) +TemporaryRef<FilterNode> +DrawTargetSkia::CreateFilter(FilterType aType) { - mSnapshots.push_back(aSnapshot); + return FilterNodeSoftware::Create(aType); } void -DrawTargetSkia::RemoveSnapshot(SourceSurfaceSkia* aSnapshot) +DrawTargetSkia::MarkChanged() { - std::vector<SourceSurfaceSkia*>::iterator iter = std::find(mSnapshots.begin(), mSnapshots.end(), aSnapshot); - if (iter != mSnapshots.end()) { - mSnapshots.erase(iter); + if (mSnapshot) { + mSnapshot->DrawTargetWillChange(); + mSnapshot = nullptr; } } +// Return a rect (in user space) that covers the entire surface by applying +// the inverse of GetTransform() to (0, 0, mSize.width, mSize.height). +SkRect +DrawTargetSkia::SkRectCoveringWholeSurface() const +{ + return RectToSkRect(mTransform.TransformBounds(Rect(0, 0, mSize.width, mSize.height))); +} + void -DrawTargetSkia::MarkChanged() +DrawTargetSkia::SnapshotDestroyed() { - if (mSnapshots.size()) { - for (std::vector<SourceSurfaceSkia*>::iterator iter = mSnapshots.begin(); - iter != mSnapshots.end(); iter++) { - (*iter)->DrawTargetWillChange(); - } - // All snapshots will now have copied data. - mSnapshots.clear(); - } + mSnapshot = nullptr; } } |