gfx/2d/DrawTargetSkia.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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.

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

mercurial