gfx/2d/DrawTargetD2D1.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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 <initguid.h>
michael@0 7 #include "DrawTargetD2D1.h"
michael@0 8 #include "DrawTargetD2D.h"
michael@0 9 #include "FilterNodeSoftware.h"
michael@0 10 #include "GradientStopsD2D.h"
michael@0 11 #include "SourceSurfaceD2D1.h"
michael@0 12 #include "SourceSurfaceD2D.h"
michael@0 13 #include "RadialGradientEffectD2D1.h"
michael@0 14
michael@0 15 #include "HelpersD2D.h"
michael@0 16 #include "FilterNodeD2D1.h"
michael@0 17 #include "Tools.h"
michael@0 18
michael@0 19 using namespace std;
michael@0 20
michael@0 21 namespace mozilla {
michael@0 22 namespace gfx {
michael@0 23
michael@0 24 uint64_t DrawTargetD2D1::mVRAMUsageDT;
michael@0 25 uint64_t DrawTargetD2D1::mVRAMUsageSS;
michael@0 26 ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr;
michael@0 27
michael@0 28 ID2D1Factory1 *D2DFactory1()
michael@0 29 {
michael@0 30 return DrawTargetD2D1::factory();
michael@0 31 }
michael@0 32
michael@0 33 DrawTargetD2D1::DrawTargetD2D1()
michael@0 34 : mClipsArePushed(false)
michael@0 35 {
michael@0 36 }
michael@0 37
michael@0 38 DrawTargetD2D1::~DrawTargetD2D1()
michael@0 39 {
michael@0 40 PopAllClips();
michael@0 41
michael@0 42 mDC->EndDraw();
michael@0 43 }
michael@0 44
michael@0 45 TemporaryRef<SourceSurface>
michael@0 46 DrawTargetD2D1::Snapshot()
michael@0 47 {
michael@0 48 if (mSnapshot) {
michael@0 49 return mSnapshot;
michael@0 50 }
michael@0 51 PopAllClips();
michael@0 52
michael@0 53 mDC->Flush();
michael@0 54
michael@0 55 mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this);
michael@0 56
michael@0 57 return mSnapshot;
michael@0 58 }
michael@0 59
michael@0 60 void
michael@0 61 DrawTargetD2D1::Flush()
michael@0 62 {
michael@0 63 mDC->Flush();
michael@0 64 }
michael@0 65
michael@0 66 void
michael@0 67 DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
michael@0 68 const Rect &aDest,
michael@0 69 const Rect &aSource,
michael@0 70 const DrawSurfaceOptions &aSurfOptions,
michael@0 71 const DrawOptions &aOptions)
michael@0 72 {
michael@0 73 RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, ExtendMode::CLAMP);
michael@0 74
michael@0 75 if (!image) {
michael@0 76 gfxWarning() << *this << ": Unable to get D2D image for surface.";
michael@0 77 return;
michael@0 78 }
michael@0 79
michael@0 80 PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
michael@0 81
michael@0 82 D2D1_RECT_F samplingBounds;
michael@0 83
michael@0 84 if (aSurfOptions.mSamplingBounds == SamplingBounds::BOUNDED) {
michael@0 85 samplingBounds = D2DRect(aSource);
michael@0 86 } else {
michael@0 87 samplingBounds = D2D1::RectF(0, 0, Float(aSurface->GetSize().width), Float(aSurface->GetSize().height));
michael@0 88 }
michael@0 89
michael@0 90 Float xScale = aDest.width / aSource.width;
michael@0 91 Float yScale = aDest.height / aSource.height;
michael@0 92
michael@0 93 RefPtr<ID2D1ImageBrush> brush;
michael@0 94
michael@0 95 // Here we scale the source pattern up to the size and position where we want
michael@0 96 // it to be.
michael@0 97 Matrix transform;
michael@0 98 transform.Translate(aDest.x, aDest.y);
michael@0 99 transform.Scale(xScale, yScale);
michael@0 100
michael@0 101 mDC->CreateImageBrush(image, D2D1::ImageBrushProperties(samplingBounds),
michael@0 102 D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
michael@0 103 byRef(brush));
michael@0 104 mDC->FillRectangle(D2DRect(aDest), brush);
michael@0 105
michael@0 106 FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
michael@0 107 }
michael@0 108
michael@0 109 void
michael@0 110 DrawTargetD2D1::DrawFilter(FilterNode *aNode,
michael@0 111 const Rect &aSourceRect,
michael@0 112 const Point &aDestPoint,
michael@0 113 const DrawOptions &aOptions)
michael@0 114 {
michael@0 115 if (aNode->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
michael@0 116 gfxWarning() << *this << ": Incompatible filter passed to DrawFilter.";
michael@0 117 return;
michael@0 118 }
michael@0 119
michael@0 120 PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
michael@0 121
michael@0 122 mDC->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
michael@0 123 }
michael@0 124
michael@0 125 void
michael@0 126 DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
michael@0 127 const Point &aDest,
michael@0 128 const Color &aColor,
michael@0 129 const Point &aOffset,
michael@0 130 Float aSigma,
michael@0 131 CompositionOp aOperator)
michael@0 132 {
michael@0 133 MarkChanged();
michael@0 134 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 135 mTransformDirty = true;
michael@0 136
michael@0 137 Matrix mat;
michael@0 138 RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
michael@0 139
michael@0 140 if (!mat.IsIdentity()) {
michael@0 141 gfxDebug() << *this << ": At this point complex partial uploads are not supported for Shadow surfaces.";
michael@0 142 return;
michael@0 143 }
michael@0 144
michael@0 145 // Step 1, create the shadow effect.
michael@0 146 RefPtr<ID2D1Effect> shadowEffect;
michael@0 147 mDC->CreateEffect(CLSID_D2D1Shadow, byRef(shadowEffect));
michael@0 148 shadowEffect->SetInput(0, image);
michael@0 149 shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
michael@0 150 D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a };
michael@0 151 shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
michael@0 152
michael@0 153 // Step 2, move the shadow effect into place.
michael@0 154 RefPtr<ID2D1Effect> affineTransformEffect;
michael@0 155 mDC->CreateEffect(CLSID_D2D12DAffineTransform, byRef(affineTransformEffect));
michael@0 156 affineTransformEffect->SetInputEffect(0, shadowEffect);
michael@0 157 D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation(aOffset.x, aOffset.y);
michael@0 158 affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix);
michael@0 159
michael@0 160 // Step 3, create an effect that combines shadow and bitmap in one image.
michael@0 161 RefPtr<ID2D1Effect> compositeEffect;
michael@0 162 mDC->CreateEffect(CLSID_D2D1Composite, byRef(compositeEffect));
michael@0 163 compositeEffect->SetInputEffect(0, affineTransformEffect);
michael@0 164 compositeEffect->SetInput(1, image);
michael@0 165 compositeEffect->SetValue(D2D1_COMPOSITE_PROP_MODE, D2DCompositionMode(aOperator));
michael@0 166
michael@0 167 D2D1_POINT_2F surfPoint = D2DPoint(aDest);
michael@0 168 mDC->DrawImage(compositeEffect, &surfPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
michael@0 169 }
michael@0 170
michael@0 171 void
michael@0 172 DrawTargetD2D1::ClearRect(const Rect &aRect)
michael@0 173 {
michael@0 174 MarkChanged();
michael@0 175
michael@0 176 mDC->PushAxisAlignedClip(D2DRect(aRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
michael@0 177 mDC->Clear();
michael@0 178 mDC->PopAxisAlignedClip();
michael@0 179 }
michael@0 180
michael@0 181 void
michael@0 182 DrawTargetD2D1::MaskSurface(const Pattern &aSource,
michael@0 183 SourceSurface *aMask,
michael@0 184 Point aOffset,
michael@0 185 const DrawOptions &aOptions)
michael@0 186 {
michael@0 187 RefPtr<ID2D1Bitmap> bitmap;
michael@0 188
michael@0 189 RefPtr<ID2D1Image> image = GetImageForSurface(aMask, ExtendMode::CLAMP);
michael@0 190
michael@0 191 PrepareForDrawing(aOptions.mCompositionOp, aSource);
michael@0 192
michael@0 193 // FillOpacityMask only works if the antialias mode is MODE_ALIASED
michael@0 194 mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
michael@0 195
michael@0 196 IntSize size = aMask->GetSize();
michael@0 197 Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
michael@0 198 image->QueryInterface((ID2D1Bitmap**)&bitmap);
michael@0 199 if (!bitmap) {
michael@0 200 gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
michael@0 201 return;
michael@0 202 }
michael@0 203
michael@0 204 Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
michael@0 205 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
michael@0 206 mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
michael@0 207
michael@0 208 mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
michael@0 209
michael@0 210 FinalizeDrawing(aOptions.mCompositionOp, aSource);
michael@0 211 }
michael@0 212
michael@0 213 void
michael@0 214 DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
michael@0 215 const IntRect &aSourceRect,
michael@0 216 const IntPoint &aDestination)
michael@0 217 {
michael@0 218 MarkChanged();
michael@0 219
michael@0 220 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 221 mTransformDirty = true;
michael@0 222
michael@0 223 Matrix mat;
michael@0 224 RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
michael@0 225
michael@0 226 if (!mat.IsIdentity()) {
michael@0 227 gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface.";
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)),
michael@0 232 D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y),
michael@0 233 Float(aSourceRect.XMost()), Float(aSourceRect.YMost())),
michael@0 234 D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
michael@0 235 }
michael@0 236
michael@0 237 void
michael@0 238 DrawTargetD2D1::FillRect(const Rect &aRect,
michael@0 239 const Pattern &aPattern,
michael@0 240 const DrawOptions &aOptions)
michael@0 241 {
michael@0 242 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 243
michael@0 244 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 245 mDC->FillRectangle(D2DRect(aRect), brush);
michael@0 246
michael@0 247 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 248 }
michael@0 249
michael@0 250 void
michael@0 251 DrawTargetD2D1::StrokeRect(const Rect &aRect,
michael@0 252 const Pattern &aPattern,
michael@0 253 const StrokeOptions &aStrokeOptions,
michael@0 254 const DrawOptions &aOptions)
michael@0 255 {
michael@0 256 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 257
michael@0 258 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 259 RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
michael@0 260
michael@0 261 mDC->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle);
michael@0 262
michael@0 263 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 264 }
michael@0 265
michael@0 266 void
michael@0 267 DrawTargetD2D1::StrokeLine(const Point &aStart,
michael@0 268 const Point &aEnd,
michael@0 269 const Pattern &aPattern,
michael@0 270 const StrokeOptions &aStrokeOptions,
michael@0 271 const DrawOptions &aOptions)
michael@0 272 {
michael@0 273 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 274
michael@0 275 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 276 RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
michael@0 277
michael@0 278 mDC->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle);
michael@0 279
michael@0 280 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 281 }
michael@0 282
michael@0 283 void
michael@0 284 DrawTargetD2D1::Stroke(const Path *aPath,
michael@0 285 const Pattern &aPattern,
michael@0 286 const StrokeOptions &aStrokeOptions,
michael@0 287 const DrawOptions &aOptions)
michael@0 288 {
michael@0 289 if (aPath->GetBackendType() != BackendType::DIRECT2D) {
michael@0 290 gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
michael@0 291 return;
michael@0 292 }
michael@0 293 const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
michael@0 294
michael@0 295 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 296
michael@0 297 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 298 RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
michael@0 299
michael@0 300 mDC->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle);
michael@0 301
michael@0 302 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 303 }
michael@0 304
michael@0 305 void
michael@0 306 DrawTargetD2D1::Fill(const Path *aPath,
michael@0 307 const Pattern &aPattern,
michael@0 308 const DrawOptions &aOptions)
michael@0 309 {
michael@0 310 if (aPath->GetBackendType() != BackendType::DIRECT2D) {
michael@0 311 gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
michael@0 312 return;
michael@0 313 }
michael@0 314 const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
michael@0 315
michael@0 316 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 317
michael@0 318 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 319
michael@0 320 mDC->FillGeometry(d2dPath->mGeometry, brush);
michael@0 321
michael@0 322 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 323 }
michael@0 324
michael@0 325 void
michael@0 326 DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
michael@0 327 const GlyphBuffer &aBuffer,
michael@0 328 const Pattern &aPattern,
michael@0 329 const DrawOptions &aOptions,
michael@0 330 const GlyphRenderingOptions *aRenderingOptions)
michael@0 331 {
michael@0 332 if (aFont->GetType() != FontType::DWRITE) {
michael@0 333 gfxDebug() << *this << ": Ignoring drawing call for incompatible font.";
michael@0 334 return;
michael@0 335 }
michael@0 336
michael@0 337 ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont);
michael@0 338
michael@0 339 IDWriteRenderingParams *params = nullptr;
michael@0 340 if (aRenderingOptions) {
michael@0 341 if (aRenderingOptions->GetType() != FontType::DWRITE) {
michael@0 342 gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions.";
michael@0 343 // This should never happen.
michael@0 344 MOZ_ASSERT(false);
michael@0 345 } else {
michael@0 346 params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderingOptions)->mParams;
michael@0 347 }
michael@0 348 }
michael@0 349
michael@0 350 AntialiasMode aaMode = font->GetDefaultAAMode();
michael@0 351
michael@0 352 if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
michael@0 353 aaMode = aOptions.mAntialiasMode;
michael@0 354 }
michael@0 355
michael@0 356 PrepareForDrawing(aOptions.mCompositionOp, aPattern);
michael@0 357
michael@0 358 bool forceClearType = false;
michael@0 359 if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA &&
michael@0 360 aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) {
michael@0 361 forceClearType = true;
michael@0 362 }
michael@0 363
michael@0 364
michael@0 365 D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
michael@0 366
michael@0 367 switch (aaMode) {
michael@0 368 case AntialiasMode::NONE:
michael@0 369 d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
michael@0 370 break;
michael@0 371 case AntialiasMode::GRAY:
michael@0 372 d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
michael@0 373 break;
michael@0 374 case AntialiasMode::SUBPIXEL:
michael@0 375 d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
michael@0 376 break;
michael@0 377 default:
michael@0 378 d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
michael@0 379 }
michael@0 380
michael@0 381 if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
michael@0 382 mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) {
michael@0 383 d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
michael@0 384 }
michael@0 385
michael@0 386 mDC->SetTextAntialiasMode(d2dAAMode);
michael@0 387
michael@0 388 if (params != mTextRenderingParams) {
michael@0 389 mDC->SetTextRenderingParams(params);
michael@0 390 mTextRenderingParams = params;
michael@0 391 }
michael@0 392
michael@0 393 RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
michael@0 394
michael@0 395 AutoDWriteGlyphRun autoRun;
michael@0 396 DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
michael@0 397
michael@0 398 if (brush) {
michael@0 399 mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
michael@0 400 }
michael@0 401
michael@0 402 FinalizeDrawing(aOptions.mCompositionOp, aPattern);
michael@0 403 }
michael@0 404
michael@0 405 void
michael@0 406 DrawTargetD2D1::Mask(const Pattern &aSource,
michael@0 407 const Pattern &aMask,
michael@0 408 const DrawOptions &aOptions)
michael@0 409 {
michael@0 410 PrepareForDrawing(aOptions.mCompositionOp, aSource);
michael@0 411
michael@0 412 RefPtr<ID2D1Brush> source = CreateBrushForPattern(aSource, aOptions.mAlpha);
michael@0 413 RefPtr<ID2D1Brush> mask = CreateBrushForPattern(aMask, 1.0f);
michael@0 414 mDC->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr,
michael@0 415 D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
michael@0 416 D2D1::IdentityMatrix(),
michael@0 417 1.0f, mask),
michael@0 418 nullptr);
michael@0 419
michael@0 420 Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height);
michael@0 421 Matrix mat = mTransform;
michael@0 422 mat.Invert();
michael@0 423
michael@0 424 mDC->FillRectangle(D2DRect(mat.TransformBounds(rect)), source);
michael@0 425
michael@0 426 mDC->PopLayer();
michael@0 427
michael@0 428 FinalizeDrawing(aOptions.mCompositionOp, aSource);
michael@0 429 }
michael@0 430
michael@0 431 void
michael@0 432 DrawTargetD2D1::PushClip(const Path *aPath)
michael@0 433 {
michael@0 434 if (aPath->GetBackendType() != BackendType::DIRECT2D) {
michael@0 435 gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
michael@0 436 return;
michael@0 437 }
michael@0 438
michael@0 439 RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
michael@0 440
michael@0 441 PushedClip clip;
michael@0 442 clip.mTransform = D2DMatrix(mTransform);
michael@0 443 clip.mPath = pathD2D;
michael@0 444
michael@0 445 pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
michael@0 446
michael@0 447 mPushedClips.push_back(clip);
michael@0 448
michael@0 449 // The transform of clips is relative to the world matrix, since we use the total
michael@0 450 // transform for the clips, make the world matrix identity.
michael@0 451 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 452 mTransformDirty = true;
michael@0 453
michael@0 454 if (mClipsArePushed) {
michael@0 455 PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform);
michael@0 456 }
michael@0 457 }
michael@0 458
michael@0 459 void
michael@0 460 DrawTargetD2D1::PushClipRect(const Rect &aRect)
michael@0 461 {
michael@0 462 if (!mTransform.IsRectilinear()) {
michael@0 463 // Whoops, this isn't a rectangle in device space, Direct2D will not deal
michael@0 464 // with this transform the way we want it to.
michael@0 465 // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
michael@0 466
michael@0 467 RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
michael@0 468 pathBuilder->MoveTo(aRect.TopLeft());
michael@0 469 pathBuilder->LineTo(aRect.TopRight());
michael@0 470 pathBuilder->LineTo(aRect.BottomRight());
michael@0 471 pathBuilder->LineTo(aRect.BottomLeft());
michael@0 472 pathBuilder->Close();
michael@0 473 RefPtr<Path> path = pathBuilder->Finish();
michael@0 474 return PushClip(path);
michael@0 475 }
michael@0 476
michael@0 477 PushedClip clip;
michael@0 478 Rect rect = mTransform.TransformBounds(aRect);
michael@0 479 IntRect intRect;
michael@0 480 clip.mIsPixelAligned = rect.ToIntRect(&intRect);
michael@0 481
michael@0 482 // Do not store the transform, just store the device space rectangle directly.
michael@0 483 clip.mBounds = D2DRect(rect);
michael@0 484
michael@0 485 mPushedClips.push_back(clip);
michael@0 486
michael@0 487 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 488 mTransformDirty = true;
michael@0 489
michael@0 490 if (mClipsArePushed) {
michael@0 491 mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
michael@0 492 }
michael@0 493 }
michael@0 494
michael@0 495 void
michael@0 496 DrawTargetD2D1::PopClip()
michael@0 497 {
michael@0 498 if (mClipsArePushed) {
michael@0 499 if (mPushedClips.back().mPath) {
michael@0 500 mDC->PopLayer();
michael@0 501 } else {
michael@0 502 mDC->PopAxisAlignedClip();
michael@0 503 }
michael@0 504 }
michael@0 505 mPushedClips.pop_back();
michael@0 506 }
michael@0 507
michael@0 508 TemporaryRef<SourceSurface>
michael@0 509 DrawTargetD2D1::CreateSourceSurfaceFromData(unsigned char *aData,
michael@0 510 const IntSize &aSize,
michael@0 511 int32_t aStride,
michael@0 512 SurfaceFormat aFormat) const
michael@0 513 {
michael@0 514 RefPtr<ID2D1Bitmap1> bitmap;
michael@0 515
michael@0 516 HRESULT hr = mDC->CreateBitmap(D2DIntSize(aSize), aData, aStride,
michael@0 517 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(aFormat)),
michael@0 518 byRef(bitmap));
michael@0 519
michael@0 520 if (!bitmap) {
michael@0 521 return nullptr;
michael@0 522 }
michael@0 523
michael@0 524 return new SourceSurfaceD2D1(bitmap.get(), mDC, aFormat, aSize);
michael@0 525 }
michael@0 526
michael@0 527 TemporaryRef<DrawTarget>
michael@0 528 DrawTargetD2D1::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
michael@0 529 {
michael@0 530 RefPtr<DrawTargetD2D1> dt = new DrawTargetD2D1();
michael@0 531
michael@0 532 if (!dt->Init(aSize, aFormat)) {
michael@0 533 return nullptr;
michael@0 534 }
michael@0 535
michael@0 536 return dt;
michael@0 537 }
michael@0 538
michael@0 539 TemporaryRef<PathBuilder>
michael@0 540 DrawTargetD2D1::CreatePathBuilder(FillRule aFillRule) const
michael@0 541 {
michael@0 542 RefPtr<ID2D1PathGeometry> path;
michael@0 543 HRESULT hr = factory()->CreatePathGeometry(byRef(path));
michael@0 544
michael@0 545 if (FAILED(hr)) {
michael@0 546 gfxWarning() << *this << ": Failed to create Direct2D Path Geometry. Code: " << hr;
michael@0 547 return nullptr;
michael@0 548 }
michael@0 549
michael@0 550 RefPtr<ID2D1GeometrySink> sink;
michael@0 551 hr = path->Open(byRef(sink));
michael@0 552 if (FAILED(hr)) {
michael@0 553 gfxWarning() << *this << ": Failed to access Direct2D Path Geometry. Code: " << hr;
michael@0 554 return nullptr;
michael@0 555 }
michael@0 556
michael@0 557 if (aFillRule == FillRule::FILL_WINDING) {
michael@0 558 sink->SetFillMode(D2D1_FILL_MODE_WINDING);
michael@0 559 }
michael@0 560
michael@0 561 return new PathBuilderD2D(sink, path, aFillRule);
michael@0 562 }
michael@0 563
michael@0 564 TemporaryRef<GradientStops>
michael@0 565 DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
michael@0 566 {
michael@0 567 D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
michael@0 568
michael@0 569 for (uint32_t i = 0; i < aNumStops; i++) {
michael@0 570 stops[i].position = rawStops[i].offset;
michael@0 571 stops[i].color = D2DColor(rawStops[i].color);
michael@0 572 }
michael@0 573
michael@0 574 RefPtr<ID2D1GradientStopCollection> stopCollection;
michael@0 575
michael@0 576 HRESULT hr =
michael@0 577 mDC->CreateGradientStopCollection(stops, aNumStops,
michael@0 578 D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
michael@0 579 byRef(stopCollection));
michael@0 580 delete [] stops;
michael@0 581
michael@0 582 if (FAILED(hr)) {
michael@0 583 gfxWarning() << *this << ": Failed to create GradientStopCollection. Code: " << hr;
michael@0 584 return nullptr;
michael@0 585 }
michael@0 586
michael@0 587 return new GradientStopsD2D(stopCollection);
michael@0 588 }
michael@0 589
michael@0 590 TemporaryRef<FilterNode>
michael@0 591 DrawTargetD2D1::CreateFilter(FilterType aType)
michael@0 592 {
michael@0 593 return FilterNodeD2D1::Create(this, mDC, aType);
michael@0 594 }
michael@0 595
michael@0 596 bool
michael@0 597 DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
michael@0 598 {
michael@0 599 HRESULT hr;
michael@0 600
michael@0 601 hr = Factory::GetD2D1Device()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, byRef(mDC));
michael@0 602
michael@0 603 if (FAILED(hr)) {
michael@0 604 gfxWarning() << *this << ": Error " << hr << " failed to initialize new DeviceContext.";
michael@0 605 return false;
michael@0 606 }
michael@0 607
michael@0 608 D2D1_BITMAP_PROPERTIES1 props;
michael@0 609 props.dpiX = 96;
michael@0 610 props.dpiY = 96;
michael@0 611 props.pixelFormat = D2DPixelFormat(aFormat);
michael@0 612 props.colorContext = nullptr;
michael@0 613 props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
michael@0 614 mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mBitmap));
michael@0 615
michael@0 616 if (FAILED(hr)) {
michael@0 617 gfxWarning() << *this << ": Error " << hr << " failed to create new CommandList.";
michael@0 618 return false;
michael@0 619 }
michael@0 620
michael@0 621 mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mTempBitmap));
michael@0 622
michael@0 623 mDC->SetTarget(mBitmap);
michael@0 624
michael@0 625 mDC->BeginDraw();
michael@0 626
michael@0 627 mFormat = aFormat;
michael@0 628 mSize = aSize;
michael@0 629
michael@0 630 return true;
michael@0 631 }
michael@0 632
michael@0 633 /**
michael@0 634 * Private helpers.
michael@0 635 */
michael@0 636 uint32_t
michael@0 637 DrawTargetD2D1::GetByteSize() const
michael@0 638 {
michael@0 639 return mSize.width * mSize.height * BytesPerPixel(mFormat);
michael@0 640 }
michael@0 641
michael@0 642 ID2D1Factory1*
michael@0 643 DrawTargetD2D1::factory()
michael@0 644 {
michael@0 645 if (mFactory) {
michael@0 646 return mFactory;
michael@0 647 }
michael@0 648
michael@0 649 HRESULT hr = D2DFactory()->QueryInterface((ID2D1Factory1**)&mFactory);
michael@0 650
michael@0 651 if (FAILED(hr)) {
michael@0 652 return nullptr;
michael@0 653 }
michael@0 654
michael@0 655 RadialGradientEffectD2D1::Register(mFactory);
michael@0 656
michael@0 657 return mFactory;
michael@0 658 }
michael@0 659
michael@0 660 void
michael@0 661 DrawTargetD2D1::MarkChanged()
michael@0 662 {
michael@0 663 if (mSnapshot) {
michael@0 664 if (mSnapshot->hasOneRef()) {
michael@0 665 // Just destroy it, since no-one else knows about it.
michael@0 666 mSnapshot = nullptr;
michael@0 667 } else {
michael@0 668 mSnapshot->DrawTargetWillChange();
michael@0 669 // The snapshot will no longer depend on this target.
michael@0 670 MOZ_ASSERT(!mSnapshot);
michael@0 671 }
michael@0 672 }
michael@0 673 if (mDependentTargets.size()) {
michael@0 674 // Copy mDependentTargets since the Flush()es below will modify it.
michael@0 675 TargetSet tmpTargets = mDependentTargets;
michael@0 676 for (TargetSet::iterator iter = tmpTargets.begin();
michael@0 677 iter != tmpTargets.end(); iter++) {
michael@0 678 (*iter)->Flush();
michael@0 679 }
michael@0 680 // The Flush() should have broken all dependencies on this target.
michael@0 681 MOZ_ASSERT(!mDependentTargets.size());
michael@0 682 }
michael@0 683 }
michael@0 684
michael@0 685 void
michael@0 686 DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
michael@0 687 {
michael@0 688 MarkChanged();
michael@0 689
michael@0 690 // It's important to do this before FlushTransformToDC! As this will cause
michael@0 691 // the transform to become dirty.
michael@0 692 if (!mClipsArePushed) {
michael@0 693 mClipsArePushed = true;
michael@0 694 PushClipsToDC(mDC);
michael@0 695 }
michael@0 696
michael@0 697 FlushTransformToDC();
michael@0 698
michael@0 699 if (aOp == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
michael@0 700 return;
michael@0 701 }
michael@0 702
michael@0 703 mDC->SetTarget(mTempBitmap);
michael@0 704 mDC->Clear(D2D1::ColorF(0, 0));
michael@0 705 }
michael@0 706
michael@0 707 void
michael@0 708 DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
michael@0 709 {
michael@0 710 bool patternSupported = IsPatternSupportedByD2D(aPattern);
michael@0 711
michael@0 712 if (aOp == CompositionOp::OP_OVER && patternSupported) {
michael@0 713 return;
michael@0 714 }
michael@0 715
michael@0 716 RefPtr<ID2D1Image> image;
michael@0 717 mDC->GetTarget(byRef(image));
michael@0 718
michael@0 719 mDC->SetTarget(mBitmap);
michael@0 720
michael@0 721 if (patternSupported) {
michael@0 722 mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
michael@0 723 return;
michael@0 724 }
michael@0 725
michael@0 726 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 727 mTransformDirty = true;
michael@0 728
michael@0 729 RefPtr<ID2D1Effect> radialGradientEffect;
michael@0 730
michael@0 731 mDC->CreateEffect(CLSID_RadialGradientEffect, byRef(radialGradientEffect));
michael@0 732 const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
michael@0 733
michael@0 734 radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION,
michael@0 735 static_cast<const GradientStopsD2D*>(pat->mStops.get())->mStopCollection);
michael@0 736 radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y));
michael@0 737 radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y));
michael@0 738 radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1);
michael@0 739 radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
michael@0 740 radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
michael@0 741 radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform));
michael@0 742 radialGradientEffect->SetInput(0, image);
michael@0 743
michael@0 744 mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
michael@0 745 }
michael@0 746
michael@0 747 void
michael@0 748 DrawTargetD2D1::AddDependencyOnSource(SourceSurfaceD2D1* aSource)
michael@0 749 {
michael@0 750 if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
michael@0 751 aSource->mDrawTarget->mDependentTargets.insert(this);
michael@0 752 mDependingOnTargets.insert(aSource->mDrawTarget);
michael@0 753 }
michael@0 754 }
michael@0 755
michael@0 756 void
michael@0 757 DrawTargetD2D1::PopAllClips()
michael@0 758 {
michael@0 759 if (mClipsArePushed) {
michael@0 760 PopClipsFromDC(mDC);
michael@0 761
michael@0 762 mClipsArePushed = false;
michael@0 763 }
michael@0 764 }
michael@0 765
michael@0 766 void
michael@0 767 DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC)
michael@0 768 {
michael@0 769 mDC->SetTransform(D2D1::IdentityMatrix());
michael@0 770 mTransformDirty = true;
michael@0 771
michael@0 772 for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
michael@0 773 iter != mPushedClips.end(); iter++) {
michael@0 774 if (iter->mPath) {
michael@0 775 PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform);
michael@0 776 } else {
michael@0 777 mDC->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
michael@0 778 }
michael@0 779 }
michael@0 780 }
michael@0 781
michael@0 782 void
michael@0 783 DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC)
michael@0 784 {
michael@0 785 for (int i = mPushedClips.size() - 1; i >= 0; i--) {
michael@0 786 if (mPushedClips[i].mPath) {
michael@0 787 aDC->PopLayer();
michael@0 788 } else {
michael@0 789 aDC->PopAxisAlignedClip();
michael@0 790 }
michael@0 791 }
michael@0 792 }
michael@0 793
michael@0 794 TemporaryRef<ID2D1Brush>
michael@0 795 DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
michael@0 796 {
michael@0 797 if (!IsPatternSupportedByD2D(aPattern)) {
michael@0 798 RefPtr<ID2D1SolidColorBrush> colBrush;
michael@0 799 mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
michael@0 800 return colBrush;
michael@0 801 }
michael@0 802
michael@0 803 if (aPattern.GetType() == PatternType::COLOR) {
michael@0 804 RefPtr<ID2D1SolidColorBrush> colBrush;
michael@0 805 Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
michael@0 806 mDC->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g,
michael@0 807 color.b, color.a),
michael@0 808 D2D1::BrushProperties(aAlpha),
michael@0 809 byRef(colBrush));
michael@0 810 return colBrush;
michael@0 811 } else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
michael@0 812 RefPtr<ID2D1LinearGradientBrush> gradBrush;
michael@0 813 const LinearGradientPattern *pat =
michael@0 814 static_cast<const LinearGradientPattern*>(&aPattern);
michael@0 815
michael@0 816 GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
michael@0 817
michael@0 818 if (!stops) {
michael@0 819 gfxDebug() << "No stops specified for gradient pattern.";
michael@0 820 return nullptr;
michael@0 821 }
michael@0 822
michael@0 823 if (pat->mBegin == pat->mEnd) {
michael@0 824 RefPtr<ID2D1SolidColorBrush> colBrush;
michael@0 825 uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
michael@0 826 vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
michael@0 827 stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
michael@0 828 mDC->CreateSolidColorBrush(d2dStops.back().color,
michael@0 829 D2D1::BrushProperties(aAlpha),
michael@0 830 byRef(colBrush));
michael@0 831 return colBrush;
michael@0 832 }
michael@0 833
michael@0 834 mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
michael@0 835 D2DPoint(pat->mEnd)),
michael@0 836 D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
michael@0 837 stops->mStopCollection,
michael@0 838 byRef(gradBrush));
michael@0 839 return gradBrush;
michael@0 840 } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
michael@0 841 RefPtr<ID2D1RadialGradientBrush> gradBrush;
michael@0 842 const RadialGradientPattern *pat =
michael@0 843 static_cast<const RadialGradientPattern*>(&aPattern);
michael@0 844
michael@0 845 GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
michael@0 846
michael@0 847 if (!stops) {
michael@0 848 gfxDebug() << "No stops specified for gradient pattern.";
michael@0 849 return nullptr;
michael@0 850 }
michael@0 851
michael@0 852 // This will not be a complex radial gradient brush.
michael@0 853 mDC->CreateRadialGradientBrush(
michael@0 854 D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2),
michael@0 855 D2DPoint(pat->mCenter1 - pat->mCenter2),
michael@0 856 pat->mRadius2, pat->mRadius2),
michael@0 857 D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
michael@0 858 stops->mStopCollection,
michael@0 859 byRef(gradBrush));
michael@0 860
michael@0 861 return gradBrush;
michael@0 862 } else if (aPattern.GetType() == PatternType::SURFACE) {
michael@0 863 const SurfacePattern *pat =
michael@0 864 static_cast<const SurfacePattern*>(&aPattern);
michael@0 865
michael@0 866 if (!pat->mSurface) {
michael@0 867 gfxDebug() << "No source surface specified for surface pattern";
michael@0 868 return nullptr;
michael@0 869 }
michael@0 870
michael@0 871
michael@0 872 Matrix mat = pat->mMatrix;
michael@0 873
michael@0 874 RefPtr<ID2D1ImageBrush> imageBrush;
michael@0 875 RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode);
michael@0 876 mDC->CreateImageBrush(image,
michael@0 877 D2D1::ImageBrushProperties(D2D1::RectF(0, 0,
michael@0 878 Float(pat->mSurface->GetSize().width),
michael@0 879 Float(pat->mSurface->GetSize().height)),
michael@0 880 D2DExtend(pat->mExtendMode), D2DExtend(pat->mExtendMode),
michael@0 881 D2DInterpolationMode(pat->mFilter)),
michael@0 882 D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
michael@0 883 byRef(imageBrush));
michael@0 884 return imageBrush;
michael@0 885 }
michael@0 886
michael@0 887 gfxWarning() << "Invalid pattern type detected.";
michael@0 888 return nullptr;
michael@0 889 }
michael@0 890
michael@0 891 TemporaryRef<ID2D1Image>
michael@0 892 DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform,
michael@0 893 ExtendMode aExtendMode)
michael@0 894 {
michael@0 895 RefPtr<ID2D1Image> image;
michael@0 896
michael@0 897 switch (aSurface->GetType()) {
michael@0 898 case SurfaceType::D2D1_1_IMAGE:
michael@0 899 {
michael@0 900 SourceSurfaceD2D1 *surf = static_cast<SourceSurfaceD2D1*>(aSurface);
michael@0 901 image = surf->GetImage();
michael@0 902 AddDependencyOnSource(surf);
michael@0 903 }
michael@0 904 break;
michael@0 905 default:
michael@0 906 {
michael@0 907 RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface();
michael@0 908 if (!dataSurf) {
michael@0 909 gfxWarning() << "Invalid surface type.";
michael@0 910 return nullptr;
michael@0 911 }
michael@0 912
michael@0 913 image = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode,
michael@0 914 aSourceTransform, mDC);
michael@0 915
michael@0 916 return image;
michael@0 917 }
michael@0 918 break;
michael@0 919 }
michael@0 920
michael@0 921 return image;
michael@0 922 }
michael@0 923
michael@0 924 TemporaryRef<SourceSurface>
michael@0 925 DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
michael@0 926 {
michael@0 927 if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
michael@0 928 return aSurface;
michael@0 929 }
michael@0 930
michael@0 931 RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
michael@0 932
michael@0 933 DataSourceSurface::MappedSurface map;
michael@0 934 if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
michael@0 935 return nullptr;
michael@0 936 }
michael@0 937
michael@0 938 RefPtr<ID2D1Bitmap1> bitmap;
michael@0 939 HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride,
michael@0 940 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
michael@0 941 byRef(bitmap));
michael@0 942
michael@0 943 data->Unmap();
michael@0 944
michael@0 945 if (!bitmap) {
michael@0 946 return data;
michael@0 947 }
michael@0 948
michael@0 949 return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
michael@0 950 }
michael@0 951
michael@0 952 void
michael@0 953 DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
michael@0 954 {
michael@0 955 D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
michael@0 956
michael@0 957 if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
michael@0 958 options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
michael@0 959 }
michael@0 960
michael@0 961 mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry,
michael@0 962 D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
michael@0 963 1.0, nullptr, options), nullptr);
michael@0 964 }
michael@0 965
michael@0 966 }
michael@0 967 }

mercurial