Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DrawTargetSkia.h"
7 #include "SourceSurfaceSkia.h"
8 #include "ScaledFontBase.h"
9 #include "ScaledFontCairo.h"
10 #include "skia/SkGpuDevice.h"
11 #include "skia/SkBitmapDevice.h"
12 #include "FilterNodeSoftware.h"
14 #ifdef USE_SKIA_GPU
15 #include "skia/SkGpuDevice.h"
16 #include "skia/GrGLInterface.h"
17 #endif
19 #include "skia/SkTypeface.h"
20 #include "skia/SkGradientShader.h"
21 #include "skia/SkBlurDrawLooper.h"
22 #include "skia/SkBlurMaskFilter.h"
23 #include "skia/SkColorFilter.h"
24 #include "skia/SkDropShadowImageFilter.h"
25 #include "skia/SkLayerRasterizer.h"
26 #include "skia/SkLayerDrawLooper.h"
27 #include "skia/SkDashPathEffect.h"
28 #include "Logging.h"
29 #include "HelpersSkia.h"
30 #include "Tools.h"
31 #include "DataSurfaceHelpers.h"
32 #include <algorithm>
34 namespace mozilla {
35 namespace gfx {
37 class GradientStopsSkia : public GradientStops
38 {
39 public:
40 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStopsSkia)
41 GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops, ExtendMode aExtendMode)
42 : mCount(aNumStops)
43 , mExtendMode(aExtendMode)
44 {
45 if (mCount == 0) {
46 return;
47 }
49 // Skia gradients always require a stop at 0.0 and 1.0, insert these if
50 // we don't have them.
51 uint32_t shift = 0;
52 if (aStops[0].offset != 0) {
53 mCount++;
54 shift = 1;
55 }
56 if (aStops[aNumStops-1].offset != 1) {
57 mCount++;
58 }
59 mColors.resize(mCount);
60 mPositions.resize(mCount);
61 if (aStops[0].offset != 0) {
62 mColors[0] = ColorToSkColor(aStops[0].color, 1.0);
63 mPositions[0] = 0;
64 }
65 for (uint32_t i = 0; i < aNumStops; i++) {
66 mColors[i + shift] = ColorToSkColor(aStops[i].color, 1.0);
67 mPositions[i + shift] = SkFloatToScalar(aStops[i].offset);
68 }
69 if (aStops[aNumStops-1].offset != 1) {
70 mColors[mCount-1] = ColorToSkColor(aStops[aNumStops-1].color, 1.0);
71 mPositions[mCount-1] = SK_Scalar1;
72 }
73 }
75 BackendType GetBackendType() const { return BackendType::SKIA; }
77 std::vector<SkColor> mColors;
78 std::vector<SkScalar> mPositions;
79 int mCount;
80 ExtendMode mExtendMode;
81 };
83 /**
84 * When constructing a temporary SkBitmap via GetBitmapForSurface, we may also
85 * have to construct a temporary DataSourceSurface, which must live as long as
86 * the SkBitmap. So we return a pair of the SkBitmap and the (optional)
87 * temporary surface.
88 */
89 struct TempBitmap
90 {
91 SkBitmap mBitmap;
92 RefPtr<SourceSurface> mTmpSurface;
93 };
95 static TempBitmap
96 GetBitmapForSurface(SourceSurface* aSurface)
97 {
98 TempBitmap result;
100 if (aSurface->GetType() == SurfaceType::SKIA) {
101 result.mBitmap = static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap();
102 return result;
103 }
105 RefPtr<DataSourceSurface> surf = aSurface->GetDataSurface();
106 if (!surf) {
107 MOZ_CRASH("Non-skia SourceSurfaces need to be DataSourceSurfaces");
108 }
110 result.mBitmap.setConfig(GfxFormatToSkiaConfig(surf->GetFormat()),
111 surf->GetSize().width, surf->GetSize().height,
112 surf->Stride());
113 result.mBitmap.setPixels(surf->GetData());
114 result.mTmpSurface = surf.forget();
115 return result;
116 }
118 DrawTargetSkia::DrawTargetSkia()
119 : mTexture(0), mSnapshot(nullptr)
120 {
121 }
123 DrawTargetSkia::~DrawTargetSkia()
124 {
125 }
127 TemporaryRef<SourceSurface>
128 DrawTargetSkia::Snapshot()
129 {
130 RefPtr<SourceSurfaceSkia> snapshot = mSnapshot;
131 if (!snapshot) {
132 snapshot = new SourceSurfaceSkia();
133 mSnapshot = snapshot;
134 if (!snapshot->InitFromCanvas(mCanvas.get(), mFormat, this))
135 return nullptr;
136 }
138 return snapshot;
139 }
141 static void
142 SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap,
143 Float aAlpha = 1.0)
144 {
145 switch (aPattern.GetType()) {
146 case PatternType::COLOR: {
147 Color color = static_cast<const ColorPattern&>(aPattern).mColor;
148 aPaint.setColor(ColorToSkColor(color, aAlpha));
149 break;
150 }
151 case PatternType::LINEAR_GRADIENT: {
152 const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
153 GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
154 SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
156 if (stops->mCount >= 2) {
157 SkPoint points[2];
158 points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
159 points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
161 SkShader* shader = SkGradientShader::CreateLinear(points,
162 &stops->mColors.front(),
163 &stops->mPositions.front(),
164 stops->mCount,
165 mode);
167 if (shader) {
168 SkMatrix mat;
169 GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
170 shader->setLocalMatrix(mat);
171 SkSafeUnref(aPaint.setShader(shader));
172 }
174 } else {
175 aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
176 }
177 break;
178 }
179 case PatternType::RADIAL_GRADIENT: {
180 const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
181 GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
182 SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
184 if (stops->mCount >= 2) {
185 SkPoint points[2];
186 points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
187 points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
189 SkShader* shader = SkGradientShader::CreateTwoPointConical(points[0],
190 SkFloatToScalar(pat.mRadius1),
191 points[1],
192 SkFloatToScalar(pat.mRadius2),
193 &stops->mColors.front(),
194 &stops->mPositions.front(),
195 stops->mCount,
196 mode);
197 if (shader) {
198 SkMatrix mat;
199 GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
200 shader->setLocalMatrix(mat);
201 SkSafeUnref(aPaint.setShader(shader));
202 }
204 } else {
205 aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
206 }
207 break;
208 }
209 case PatternType::SURFACE: {
210 const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
211 aTmpBitmap = GetBitmapForSurface(pat.mSurface);
212 const SkBitmap& bitmap = aTmpBitmap.mBitmap;
214 SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
215 SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
216 SkMatrix mat;
217 GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
218 shader->setLocalMatrix(mat);
219 SkSafeUnref(aPaint.setShader(shader));
220 if (pat.mFilter == Filter::POINT) {
221 aPaint.setFilterLevel(SkPaint::kNone_FilterLevel);
222 }
223 break;
224 }
225 }
226 }
228 static inline Rect
229 GetClipBounds(SkCanvas *aCanvas)
230 {
231 SkRect clipBounds;
232 aCanvas->getClipBounds(&clipBounds);
233 return SkRectToRect(clipBounds);
234 }
236 struct AutoPaintSetup {
237 AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern, const Rect* aMaskBounds = nullptr)
238 : mNeedsRestore(false), mAlpha(1.0)
239 {
240 Init(aCanvas, aOptions, aMaskBounds);
241 SetPaintPattern(mPaint, aPattern, mTmpBitmap, mAlpha);
242 }
244 AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds = nullptr)
245 : mNeedsRestore(false), mAlpha(1.0)
246 {
247 Init(aCanvas, aOptions, aMaskBounds);
248 }
250 ~AutoPaintSetup()
251 {
252 if (mNeedsRestore) {
253 mCanvas->restore();
254 }
255 }
257 void Init(SkCanvas *aCanvas, const DrawOptions& aOptions, const Rect* aMaskBounds)
258 {
259 mPaint.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp));
260 mCanvas = aCanvas;
262 //TODO: Can we set greyscale somehow?
263 if (aOptions.mAntialiasMode != AntialiasMode::NONE) {
264 mPaint.setAntiAlias(true);
265 } else {
266 mPaint.setAntiAlias(false);
267 }
269 Rect clipBounds = GetClipBounds(aCanvas);
270 bool needsGroup = !IsOperatorBoundByMask(aOptions.mCompositionOp) &&
271 (!aMaskBounds || !aMaskBounds->Contains(clipBounds));
273 // TODO: We could skip the temporary for operator_source and just
274 // clear the clip rect. The other operators would be harder
275 // but could be worth it to skip pushing a group.
276 if (needsGroup) {
277 mPaint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
278 SkPaint temp;
279 temp.setXfermodeMode(GfxOpToSkiaOp(aOptions.mCompositionOp));
280 temp.setAlpha(U8CPU(aOptions.mAlpha*255));
281 //TODO: Get a rect here
282 mCanvas->saveLayer(nullptr, &temp);
283 mNeedsRestore = true;
284 } else {
285 mPaint.setAlpha(U8CPU(aOptions.mAlpha*255.0));
286 mAlpha = aOptions.mAlpha;
287 }
288 mPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
289 }
291 // TODO: Maybe add an operator overload to access this easier?
292 SkPaint mPaint;
293 TempBitmap mTmpBitmap;
294 bool mNeedsRestore;
295 SkCanvas* mCanvas;
296 Float mAlpha;
297 };
299 void
300 DrawTargetSkia::Flush()
301 {
302 mCanvas->flush();
303 }
305 void
306 DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
307 const Rect &aDest,
308 const Rect &aSource,
309 const DrawSurfaceOptions &aSurfOptions,
310 const DrawOptions &aOptions)
311 {
312 RefPtr<SourceSurface> dataSurface;
314 if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) {
315 dataSurface = aSurface->GetDataSurface();
316 if (!dataSurface) {
317 gfxDebug() << *this << ": DrawSurface() can't draw surface";
318 return;
319 }
320 aSurface = dataSurface.get();
321 }
323 if (aSource.IsEmpty()) {
324 return;
325 }
327 MarkChanged();
329 SkRect destRect = RectToSkRect(aDest);
330 SkRect sourceRect = RectToSkRect(aSource);
332 TempBitmap bitmap = GetBitmapForSurface(aSurface);
334 AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest);
335 if (aSurfOptions.mFilter == Filter::POINT) {
336 paint.mPaint.setFilterLevel(SkPaint::kNone_FilterLevel);
337 }
339 mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint);
340 }
342 void
343 DrawTargetSkia::DrawFilter(FilterNode *aNode,
344 const Rect &aSourceRect,
345 const Point &aDestPoint,
346 const DrawOptions &aOptions)
347 {
348 FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode);
349 filter->Draw(this, aSourceRect, aDestPoint, aOptions);
350 }
352 void
353 DrawTargetSkia::DrawSurfaceWithShadow(SourceSurface *aSurface,
354 const Point &aDest,
355 const Color &aColor,
356 const Point &aOffset,
357 Float aSigma,
358 CompositionOp aOperator)
359 {
360 if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) {
361 return;
362 }
364 MarkChanged();
366 mCanvas->save(SkCanvas::kMatrix_SaveFlag);
367 mCanvas->resetMatrix();
369 TempBitmap bitmap = GetBitmapForSurface(aSurface);
371 SkPaint paint;
373 SkImageFilter* filter = SkDropShadowImageFilter::Create(aOffset.x, aOffset.y,
374 aSigma, ColorToSkColor(aColor, 1.0));
376 paint.setImageFilter(filter);
377 paint.setXfermodeMode(GfxOpToSkiaOp(aOperator));
379 mCanvas->drawBitmap(bitmap.mBitmap, aDest.x, aDest.y, &paint);
380 mCanvas->restore();
381 }
383 void
384 DrawTargetSkia::FillRect(const Rect &aRect,
385 const Pattern &aPattern,
386 const DrawOptions &aOptions)
387 {
388 MarkChanged();
389 SkRect rect = RectToSkRect(aRect);
390 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern, &aRect);
392 mCanvas->drawRect(rect, paint.mPaint);
393 }
395 void
396 DrawTargetSkia::Stroke(const Path *aPath,
397 const Pattern &aPattern,
398 const StrokeOptions &aStrokeOptions,
399 const DrawOptions &aOptions)
400 {
401 MarkChanged();
402 MOZ_ASSERT(aPath, "Null path");
403 if (aPath->GetBackendType() != BackendType::SKIA) {
404 return;
405 }
407 const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
410 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
411 if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
412 return;
413 }
415 mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint);
416 }
418 void
419 DrawTargetSkia::StrokeRect(const Rect &aRect,
420 const Pattern &aPattern,
421 const StrokeOptions &aStrokeOptions,
422 const DrawOptions &aOptions)
423 {
424 MarkChanged();
425 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
426 if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
427 return;
428 }
430 mCanvas->drawRect(RectToSkRect(aRect), paint.mPaint);
431 }
433 void
434 DrawTargetSkia::StrokeLine(const Point &aStart,
435 const Point &aEnd,
436 const Pattern &aPattern,
437 const StrokeOptions &aStrokeOptions,
438 const DrawOptions &aOptions)
439 {
440 MarkChanged();
441 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
442 if (!StrokeOptionsToPaint(paint.mPaint, aStrokeOptions)) {
443 return;
444 }
446 mCanvas->drawLine(SkFloatToScalar(aStart.x), SkFloatToScalar(aStart.y),
447 SkFloatToScalar(aEnd.x), SkFloatToScalar(aEnd.y),
448 paint.mPaint);
449 }
451 void
452 DrawTargetSkia::Fill(const Path *aPath,
453 const Pattern &aPattern,
454 const DrawOptions &aOptions)
455 {
456 MarkChanged();
457 if (aPath->GetBackendType() != BackendType::SKIA) {
458 return;
459 }
461 const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
463 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
465 mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint);
466 }
468 void
469 DrawTargetSkia::FillGlyphs(ScaledFont *aFont,
470 const GlyphBuffer &aBuffer,
471 const Pattern &aPattern,
472 const DrawOptions &aOptions,
473 const GlyphRenderingOptions *aRenderingOptions)
474 {
475 if (aFont->GetType() != FontType::MAC &&
476 aFont->GetType() != FontType::SKIA &&
477 aFont->GetType() != FontType::GDI) {
478 return;
479 }
481 MarkChanged();
483 ScaledFontBase* skiaFont = static_cast<ScaledFontBase*>(aFont);
485 AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern);
486 paint.mPaint.setTypeface(skiaFont->GetSkTypeface());
487 paint.mPaint.setTextSize(SkFloatToScalar(skiaFont->mSize));
488 paint.mPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
490 if (aRenderingOptions && aRenderingOptions->GetType() == FontType::CAIRO) {
491 switch (static_cast<const GlyphRenderingOptionsCairo*>(aRenderingOptions)->GetHinting()) {
492 case FontHinting::NONE:
493 paint.mPaint.setHinting(SkPaint::kNo_Hinting);
494 break;
495 case FontHinting::LIGHT:
496 paint.mPaint.setHinting(SkPaint::kSlight_Hinting);
497 break;
498 case FontHinting::NORMAL:
499 paint.mPaint.setHinting(SkPaint::kNormal_Hinting);
500 break;
501 case FontHinting::FULL:
502 paint.mPaint.setHinting(SkPaint::kFull_Hinting);
503 break;
504 }
506 if (static_cast<const GlyphRenderingOptionsCairo*>(aRenderingOptions)->GetAutoHinting()) {
507 paint.mPaint.setAutohinted(true);
508 }
509 } else {
510 paint.mPaint.setHinting(SkPaint::kNormal_Hinting);
511 }
513 std::vector<uint16_t> indices;
514 std::vector<SkPoint> offsets;
515 indices.resize(aBuffer.mNumGlyphs);
516 offsets.resize(aBuffer.mNumGlyphs);
518 for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) {
519 indices[i] = aBuffer.mGlyphs[i].mIndex;
520 offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
521 offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
522 }
524 mCanvas->drawPosText(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), paint.mPaint);
525 }
527 void
528 DrawTargetSkia::Mask(const Pattern &aSource,
529 const Pattern &aMask,
530 const DrawOptions &aOptions)
531 {
532 MarkChanged();
533 AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
535 SkPaint maskPaint;
536 TempBitmap tmpBitmap;
537 SetPaintPattern(maskPaint, aMask, tmpBitmap);
539 SkLayerRasterizer *raster = new SkLayerRasterizer();
540 raster->addLayer(maskPaint);
541 SkSafeUnref(paint.mPaint.setRasterizer(raster));
543 mCanvas->drawRect(SkRectCoveringWholeSurface(), paint.mPaint);
544 }
546 void
547 DrawTargetSkia::MaskSurface(const Pattern &aSource,
548 SourceSurface *aMask,
549 Point aOffset,
550 const DrawOptions &aOptions)
551 {
552 MarkChanged();
553 AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
555 SkPaint maskPaint;
556 TempBitmap tmpBitmap;
557 SetPaintPattern(maskPaint, SurfacePattern(aMask, ExtendMode::CLAMP), tmpBitmap);
559 SkMatrix transform = maskPaint.getShader()->getLocalMatrix();
560 transform.postTranslate(SkFloatToScalar(aOffset.x), SkFloatToScalar(aOffset.y));
561 maskPaint.getShader()->setLocalMatrix(transform);
563 SkLayerRasterizer *raster = new SkLayerRasterizer();
564 raster->addLayer(maskPaint);
565 SkSafeUnref(paint.mPaint.setRasterizer(raster));
567 IntSize size = aMask->GetSize();
568 Rect rect = Rect(aOffset.x, aOffset.y, size.width, size.height);
569 mCanvas->drawRect(RectToSkRect(rect), paint.mPaint);
570 }
572 TemporaryRef<SourceSurface>
573 DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
574 const IntSize &aSize,
575 int32_t aStride,
576 SurfaceFormat aFormat) const
577 {
578 RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
580 if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
581 gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize;
582 return nullptr;
583 }
585 return newSurf;
586 }
588 TemporaryRef<DrawTarget>
589 DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
590 {
591 RefPtr<DrawTargetSkia> target = new DrawTargetSkia();
592 if (!target->Init(aSize, aFormat)) {
593 return nullptr;
594 }
595 return target;
596 }
598 TemporaryRef<SourceSurface>
599 DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const
600 {
601 if (aSurface->GetType() == SurfaceType::SKIA) {
602 return aSurface;
603 }
605 return aSurface->GetDataSurface();
606 }
608 TemporaryRef<SourceSurface>
609 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
610 {
611 return nullptr;
612 }
614 void
615 DrawTargetSkia::CopySurface(SourceSurface *aSurface,
616 const IntRect& aSourceRect,
617 const IntPoint &aDestination)
618 {
619 //TODO: We could just use writePixels() here if the sourceRect is the entire source
621 if (aSurface->GetType() != SurfaceType::SKIA) {
622 return;
623 }
625 MarkChanged();
627 TempBitmap bitmap = GetBitmapForSurface(aSurface);
629 mCanvas->save();
630 mCanvas->resetMatrix();
631 SkRect dest = IntRectToSkRect(IntRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height));
632 SkIRect source = IntRectToSkIRect(aSourceRect);
633 mCanvas->clipRect(dest, SkRegion::kReplace_Op);
634 SkPaint paint;
636 if (mCanvas->getDevice()->config() == SkBitmap::kRGB_565_Config) {
637 // Set the xfermode to SOURCE_OVER to workaround
638 // http://code.google.com/p/skia/issues/detail?id=628
639 // RGB565 is opaque so they're equivalent anyway
640 paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
641 } else {
642 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
643 }
645 mCanvas->drawBitmapRect(bitmap.mBitmap, &source, dest, &paint);
646 mCanvas->restore();
647 }
649 bool
650 DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
651 {
652 SkAutoTUnref<SkBaseDevice> device(new SkBitmapDevice(GfxFormatToSkiaConfig(aFormat),
653 aSize.width, aSize.height,
654 aFormat == SurfaceFormat::B8G8R8X8));
656 SkBitmap bitmap = device->accessBitmap(true);
657 if (!bitmap.allocPixels()) {
658 return false;
659 }
661 bitmap.eraseARGB(0, 0, 0, 0);
663 SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
664 mSize = aSize;
666 mCanvas = canvas.get();
667 mFormat = aFormat;
668 return true;
669 }
671 #ifdef USE_SKIA_GPU
672 bool
673 DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
674 const IntSize &aSize,
675 SurfaceFormat aFormat)
676 {
677 MOZ_ASSERT(aGrContext, "null GrContext");
679 mGrContext = aGrContext;
681 mSize = aSize;
682 mFormat = aFormat;
684 GrTextureDesc targetDescriptor;
686 targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit;
687 targetDescriptor.fWidth = mSize.width;
688 targetDescriptor.fHeight = mSize.height;
689 targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat);
690 targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin;
691 targetDescriptor.fSampleCnt = 0;
693 SkAutoTUnref<GrTexture> skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0));
694 if (!skiaTexture) {
695 return false;
696 }
698 mTexture = (uint32_t)skiaTexture->getTextureHandle();
700 SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget()));
701 SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
702 mCanvas = canvas.get();
704 return true;
705 }
707 #endif
709 void
710 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
711 {
712 SkAlphaType alphaType = kPremul_SkAlphaType;
713 if (aFormat == SurfaceFormat::B8G8R8X8) {
714 // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX
715 ConvertBGRXToBGRA(aData, aSize, aStride);
716 alphaType = kOpaque_SkAlphaType;
717 }
719 SkBitmap bitmap;
720 bitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride, alphaType);
721 bitmap.setPixels(aData);
722 SkAutoTUnref<SkCanvas> canvas(new SkCanvas(new SkBitmapDevice(bitmap)));
724 mSize = aSize;
725 mCanvas = canvas.get();
726 mFormat = aFormat;
727 }
729 void
730 DrawTargetSkia::SetTransform(const Matrix& aTransform)
731 {
732 SkMatrix mat;
733 GfxMatrixToSkiaMatrix(aTransform, mat);
734 mCanvas->setMatrix(mat);
735 mTransform = aTransform;
736 }
738 void*
739 DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType)
740 {
741 if (aType == NativeSurfaceType::OPENGL_TEXTURE) {
742 return (void*)((uintptr_t)mTexture);
743 }
745 return nullptr;
746 }
749 TemporaryRef<PathBuilder>
750 DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const
751 {
752 RefPtr<PathBuilderSkia> pb = new PathBuilderSkia(aFillRule);
753 return pb;
754 }
756 void
757 DrawTargetSkia::ClearRect(const Rect &aRect)
758 {
759 MarkChanged();
760 SkPaint paint;
761 mCanvas->save();
762 mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, true);
763 paint.setColor(SkColorSetARGB(0, 0, 0, 0));
764 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
765 mCanvas->drawPaint(paint);
766 mCanvas->restore();
767 }
769 void
770 DrawTargetSkia::PushClip(const Path *aPath)
771 {
772 if (aPath->GetBackendType() != BackendType::SKIA) {
773 return;
774 }
776 const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
777 mCanvas->save(SkCanvas::kClip_SaveFlag);
778 mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, true);
779 }
781 void
782 DrawTargetSkia::PushClipRect(const Rect& aRect)
783 {
784 SkRect rect = RectToSkRect(aRect);
786 mCanvas->save(SkCanvas::kClip_SaveFlag);
787 mCanvas->clipRect(rect, SkRegion::kIntersect_Op, true);
788 }
790 void
791 DrawTargetSkia::PopClip()
792 {
793 mCanvas->restore();
794 }
796 TemporaryRef<GradientStops>
797 DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const
798 {
799 std::vector<GradientStop> stops;
800 stops.resize(aNumStops);
801 for (uint32_t i = 0; i < aNumStops; i++) {
802 stops[i] = aStops[i];
803 }
804 std::stable_sort(stops.begin(), stops.end());
806 return new GradientStopsSkia(stops, aNumStops, aExtendMode);
807 }
809 TemporaryRef<FilterNode>
810 DrawTargetSkia::CreateFilter(FilterType aType)
811 {
812 return FilterNodeSoftware::Create(aType);
813 }
815 void
816 DrawTargetSkia::MarkChanged()
817 {
818 if (mSnapshot) {
819 mSnapshot->DrawTargetWillChange();
820 mSnapshot = nullptr;
821 }
822 }
824 // Return a rect (in user space) that covers the entire surface by applying
825 // the inverse of GetTransform() to (0, 0, mSize.width, mSize.height).
826 SkRect
827 DrawTargetSkia::SkRectCoveringWholeSurface() const
828 {
829 return RectToSkRect(mTransform.TransformBounds(Rect(0, 0, mSize.width, mSize.height)));
830 }
832 void
833 DrawTargetSkia::SnapshotDestroyed()
834 {
835 mSnapshot = nullptr;
836 }
838 }
839 }