gfx/2d/DrawTargetD2D1.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/2d/DrawTargetD2D1.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,967 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include <initguid.h>
    1.10 +#include "DrawTargetD2D1.h"
    1.11 +#include "DrawTargetD2D.h"
    1.12 +#include "FilterNodeSoftware.h"
    1.13 +#include "GradientStopsD2D.h"
    1.14 +#include "SourceSurfaceD2D1.h"
    1.15 +#include "SourceSurfaceD2D.h"
    1.16 +#include "RadialGradientEffectD2D1.h"
    1.17 +
    1.18 +#include "HelpersD2D.h"
    1.19 +#include "FilterNodeD2D1.h"
    1.20 +#include "Tools.h"
    1.21 +
    1.22 +using namespace std;
    1.23 +
    1.24 +namespace mozilla {
    1.25 +namespace gfx {
    1.26 +
    1.27 +uint64_t DrawTargetD2D1::mVRAMUsageDT;
    1.28 +uint64_t DrawTargetD2D1::mVRAMUsageSS;
    1.29 +ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr;
    1.30 +
    1.31 +ID2D1Factory1 *D2DFactory1()
    1.32 +{
    1.33 +  return DrawTargetD2D1::factory();
    1.34 +}
    1.35 +
    1.36 +DrawTargetD2D1::DrawTargetD2D1()
    1.37 +  : mClipsArePushed(false)
    1.38 +{
    1.39 +}
    1.40 +
    1.41 +DrawTargetD2D1::~DrawTargetD2D1()
    1.42 +{
    1.43 +  PopAllClips();
    1.44 +
    1.45 +  mDC->EndDraw();
    1.46 +}
    1.47 +
    1.48 +TemporaryRef<SourceSurface>
    1.49 +DrawTargetD2D1::Snapshot()
    1.50 +{
    1.51 +  if (mSnapshot) {
    1.52 +    return mSnapshot;
    1.53 +  }
    1.54 +  PopAllClips();
    1.55 +
    1.56 +  mDC->Flush();
    1.57 +
    1.58 +  mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this);
    1.59 +
    1.60 +  return mSnapshot;
    1.61 +}
    1.62 +
    1.63 +void
    1.64 +DrawTargetD2D1::Flush()
    1.65 +{
    1.66 +  mDC->Flush();
    1.67 +}
    1.68 +
    1.69 +void
    1.70 +DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
    1.71 +                            const Rect &aDest,
    1.72 +                            const Rect &aSource,
    1.73 +                            const DrawSurfaceOptions &aSurfOptions,
    1.74 +                            const DrawOptions &aOptions)
    1.75 +{
    1.76 +  RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, ExtendMode::CLAMP);
    1.77 +
    1.78 +  if (!image) {
    1.79 +    gfxWarning() << *this << ": Unable to get D2D image for surface.";
    1.80 +    return;
    1.81 +  }
    1.82 +
    1.83 +  PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
    1.84 +
    1.85 +  D2D1_RECT_F samplingBounds;
    1.86 +
    1.87 +  if (aSurfOptions.mSamplingBounds == SamplingBounds::BOUNDED) {
    1.88 +    samplingBounds = D2DRect(aSource);
    1.89 +  } else {
    1.90 +    samplingBounds = D2D1::RectF(0, 0, Float(aSurface->GetSize().width), Float(aSurface->GetSize().height));
    1.91 +  }
    1.92 +
    1.93 +  Float xScale = aDest.width / aSource.width;
    1.94 +  Float yScale = aDest.height / aSource.height;
    1.95 +
    1.96 +  RefPtr<ID2D1ImageBrush> brush;
    1.97 +
    1.98 +  // Here we scale the source pattern up to the size and position where we want
    1.99 +  // it to be.
   1.100 +  Matrix transform;
   1.101 +  transform.Translate(aDest.x, aDest.y);
   1.102 +  transform.Scale(xScale, yScale);
   1.103 +
   1.104 +  mDC->CreateImageBrush(image, D2D1::ImageBrushProperties(samplingBounds),
   1.105 +                        D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)),
   1.106 +                        byRef(brush));
   1.107 +  mDC->FillRectangle(D2DRect(aDest), brush);
   1.108 +
   1.109 +  FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
   1.110 +}
   1.111 +
   1.112 +void
   1.113 +DrawTargetD2D1::DrawFilter(FilterNode *aNode,
   1.114 +                           const Rect &aSourceRect,
   1.115 +                           const Point &aDestPoint,
   1.116 +                           const DrawOptions &aOptions)
   1.117 +{
   1.118 +  if (aNode->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) {
   1.119 +    gfxWarning() << *this << ": Incompatible filter passed to DrawFilter.";
   1.120 +    return;
   1.121 +  }
   1.122 +
   1.123 +  PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
   1.124 +
   1.125 +  mDC->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
   1.126 +}
   1.127 +
   1.128 +void
   1.129 +DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
   1.130 +                                      const Point &aDest,
   1.131 +                                      const Color &aColor,
   1.132 +                                      const Point &aOffset,
   1.133 +                                      Float aSigma,
   1.134 +                                      CompositionOp aOperator)
   1.135 +{
   1.136 +  MarkChanged();
   1.137 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.138 +  mTransformDirty = true;
   1.139 +
   1.140 +  Matrix mat;
   1.141 +  RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
   1.142 +
   1.143 +  if (!mat.IsIdentity()) {
   1.144 +    gfxDebug() << *this << ": At this point complex partial uploads are not supported for Shadow surfaces.";
   1.145 +    return;
   1.146 +  }
   1.147 +
   1.148 +  // Step 1, create the shadow effect.
   1.149 +  RefPtr<ID2D1Effect> shadowEffect;
   1.150 +  mDC->CreateEffect(CLSID_D2D1Shadow, byRef(shadowEffect));
   1.151 +  shadowEffect->SetInput(0, image);
   1.152 +  shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma);
   1.153 +  D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a };
   1.154 +  shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color);
   1.155 +
   1.156 +  // Step 2, move the shadow effect into place.
   1.157 +  RefPtr<ID2D1Effect> affineTransformEffect;
   1.158 +  mDC->CreateEffect(CLSID_D2D12DAffineTransform, byRef(affineTransformEffect));
   1.159 +  affineTransformEffect->SetInputEffect(0, shadowEffect);
   1.160 +  D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation(aOffset.x, aOffset.y);
   1.161 +  affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix);
   1.162 +
   1.163 +  // Step 3, create an effect that combines shadow and bitmap in one image.
   1.164 +  RefPtr<ID2D1Effect> compositeEffect;
   1.165 +  mDC->CreateEffect(CLSID_D2D1Composite, byRef(compositeEffect));
   1.166 +  compositeEffect->SetInputEffect(0, affineTransformEffect);
   1.167 +  compositeEffect->SetInput(1, image);
   1.168 +  compositeEffect->SetValue(D2D1_COMPOSITE_PROP_MODE, D2DCompositionMode(aOperator));
   1.169 +
   1.170 +  D2D1_POINT_2F surfPoint = D2DPoint(aDest);
   1.171 +  mDC->DrawImage(compositeEffect, &surfPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator));
   1.172 +}
   1.173 +
   1.174 +void
   1.175 +DrawTargetD2D1::ClearRect(const Rect &aRect)
   1.176 +{
   1.177 +  MarkChanged();
   1.178 +
   1.179 +  mDC->PushAxisAlignedClip(D2DRect(aRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   1.180 +  mDC->Clear();
   1.181 +  mDC->PopAxisAlignedClip();
   1.182 +}
   1.183 +
   1.184 +void
   1.185 +DrawTargetD2D1::MaskSurface(const Pattern &aSource,
   1.186 +                            SourceSurface *aMask,
   1.187 +                            Point aOffset,
   1.188 +                            const DrawOptions &aOptions)
   1.189 +{
   1.190 +  RefPtr<ID2D1Bitmap> bitmap;
   1.191 +
   1.192 +  RefPtr<ID2D1Image> image = GetImageForSurface(aMask, ExtendMode::CLAMP);
   1.193 +
   1.194 +  PrepareForDrawing(aOptions.mCompositionOp, aSource);
   1.195 +
   1.196 +  // FillOpacityMask only works if the antialias mode is MODE_ALIASED
   1.197 +  mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   1.198 +
   1.199 +  IntSize size = aMask->GetSize();
   1.200 +  Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
   1.201 +  image->QueryInterface((ID2D1Bitmap**)&bitmap);
   1.202 +  if (!bitmap) {
   1.203 +    gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
   1.204 +    return;
   1.205 +  }
   1.206 +
   1.207 +  Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
   1.208 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
   1.209 +  mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
   1.210 +
   1.211 +  mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   1.212 +
   1.213 +  FinalizeDrawing(aOptions.mCompositionOp, aSource);
   1.214 +}
   1.215 +
   1.216 +void
   1.217 +DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
   1.218 +                            const IntRect &aSourceRect,
   1.219 +                            const IntPoint &aDestination)
   1.220 +{
   1.221 +  MarkChanged();
   1.222 +
   1.223 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.224 +  mTransformDirty = true;
   1.225 +
   1.226 +  Matrix mat;
   1.227 +  RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP);
   1.228 +
   1.229 +  if (!mat.IsIdentity()) {
   1.230 +    gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface.";
   1.231 +    return;
   1.232 +  }
   1.233 +
   1.234 +  mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)),
   1.235 +                 D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y), 
   1.236 +                             Float(aSourceRect.XMost()), Float(aSourceRect.YMost())),
   1.237 +                 D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
   1.238 +}
   1.239 +
   1.240 +void
   1.241 +DrawTargetD2D1::FillRect(const Rect &aRect,
   1.242 +                         const Pattern &aPattern,
   1.243 +                         const DrawOptions &aOptions)
   1.244 +{
   1.245 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.246 +
   1.247 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.248 +  mDC->FillRectangle(D2DRect(aRect), brush);
   1.249 +
   1.250 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.251 +}
   1.252 +
   1.253 +void
   1.254 +DrawTargetD2D1::StrokeRect(const Rect &aRect,
   1.255 +                           const Pattern &aPattern,
   1.256 +                           const StrokeOptions &aStrokeOptions,
   1.257 +                           const DrawOptions &aOptions)
   1.258 +{
   1.259 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.260 +
   1.261 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.262 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.263 +
   1.264 +  mDC->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.265 +
   1.266 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.267 +}
   1.268 +
   1.269 +void
   1.270 +DrawTargetD2D1::StrokeLine(const Point &aStart,
   1.271 +                           const Point &aEnd,
   1.272 +                           const Pattern &aPattern,
   1.273 +                           const StrokeOptions &aStrokeOptions,
   1.274 +                           const DrawOptions &aOptions)
   1.275 +{
   1.276 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.277 +
   1.278 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.279 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.280 +
   1.281 +  mDC->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.282 +
   1.283 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.284 +}
   1.285 +
   1.286 +void
   1.287 +DrawTargetD2D1::Stroke(const Path *aPath,
   1.288 +                       const Pattern &aPattern,
   1.289 +                       const StrokeOptions &aStrokeOptions,
   1.290 +                       const DrawOptions &aOptions)
   1.291 +{
   1.292 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   1.293 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   1.294 +    return;
   1.295 +  }
   1.296 +  const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   1.297 +
   1.298 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.299 +
   1.300 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.301 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.302 +
   1.303 +  mDC->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.304 +
   1.305 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.306 +}
   1.307 +
   1.308 +void
   1.309 +DrawTargetD2D1::Fill(const Path *aPath,
   1.310 +                     const Pattern &aPattern,
   1.311 +                     const DrawOptions &aOptions)
   1.312 +{
   1.313 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   1.314 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   1.315 +    return;
   1.316 +  }
   1.317 +  const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   1.318 +
   1.319 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.320 +
   1.321 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.322 +
   1.323 +  mDC->FillGeometry(d2dPath->mGeometry, brush);
   1.324 +
   1.325 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.326 +}
   1.327 +
   1.328 +void
   1.329 +DrawTargetD2D1::FillGlyphs(ScaledFont *aFont,
   1.330 +                           const GlyphBuffer &aBuffer,
   1.331 +                           const Pattern &aPattern,
   1.332 +                           const DrawOptions &aOptions,
   1.333 +                           const GlyphRenderingOptions *aRenderingOptions)
   1.334 +{
   1.335 +  if (aFont->GetType() != FontType::DWRITE) {
   1.336 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible font.";
   1.337 +    return;
   1.338 +  }
   1.339 +
   1.340 +  ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont);
   1.341 +
   1.342 +  IDWriteRenderingParams *params = nullptr;
   1.343 +  if (aRenderingOptions) {
   1.344 +    if (aRenderingOptions->GetType() != FontType::DWRITE) {
   1.345 +      gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions.";
   1.346 +      // This should never happen.
   1.347 +      MOZ_ASSERT(false);
   1.348 +    } else {
   1.349 +      params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderingOptions)->mParams;
   1.350 +    }
   1.351 +  }
   1.352 +
   1.353 +  AntialiasMode aaMode = font->GetDefaultAAMode();
   1.354 +
   1.355 +  if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
   1.356 +    aaMode = aOptions.mAntialiasMode;
   1.357 +  }
   1.358 +
   1.359 +  PrepareForDrawing(aOptions.mCompositionOp, aPattern);
   1.360 +
   1.361 +  bool forceClearType = false;
   1.362 +  if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA &&
   1.363 +      aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) {
   1.364 +    forceClearType = true;    
   1.365 +  }
   1.366 +
   1.367 +
   1.368 +  D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
   1.369 +
   1.370 +  switch (aaMode) {
   1.371 +  case AntialiasMode::NONE:
   1.372 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
   1.373 +    break;
   1.374 +  case AntialiasMode::GRAY:
   1.375 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
   1.376 +    break;
   1.377 +  case AntialiasMode::SUBPIXEL:
   1.378 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
   1.379 +    break;
   1.380 +  default:
   1.381 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
   1.382 +  }
   1.383 +
   1.384 +  if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
   1.385 +      mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) {
   1.386 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
   1.387 +  }
   1.388 +
   1.389 +  mDC->SetTextAntialiasMode(d2dAAMode);
   1.390 +
   1.391 +  if (params != mTextRenderingParams) {
   1.392 +    mDC->SetTextRenderingParams(params);
   1.393 +    mTextRenderingParams = params;
   1.394 +  }
   1.395 +
   1.396 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.397 +
   1.398 +  AutoDWriteGlyphRun autoRun;
   1.399 +  DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
   1.400 +
   1.401 +  if (brush) {
   1.402 +    mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
   1.403 +  }
   1.404 +
   1.405 +  FinalizeDrawing(aOptions.mCompositionOp, aPattern);
   1.406 +}
   1.407 +
   1.408 +void
   1.409 +DrawTargetD2D1::Mask(const Pattern &aSource,
   1.410 +                     const Pattern &aMask,
   1.411 +                     const DrawOptions &aOptions)
   1.412 +{
   1.413 +  PrepareForDrawing(aOptions.mCompositionOp, aSource);
   1.414 +
   1.415 +  RefPtr<ID2D1Brush> source = CreateBrushForPattern(aSource, aOptions.mAlpha);
   1.416 +  RefPtr<ID2D1Brush> mask = CreateBrushForPattern(aMask, 1.0f);
   1.417 +  mDC->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr,
   1.418 +                                       D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
   1.419 +                                       D2D1::IdentityMatrix(),
   1.420 +                                       1.0f, mask),
   1.421 +                 nullptr);
   1.422 +
   1.423 +  Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height);
   1.424 +  Matrix mat = mTransform;
   1.425 +  mat.Invert();
   1.426 +  
   1.427 +  mDC->FillRectangle(D2DRect(mat.TransformBounds(rect)), source);
   1.428 +
   1.429 +  mDC->PopLayer();
   1.430 +
   1.431 +  FinalizeDrawing(aOptions.mCompositionOp, aSource);
   1.432 +}
   1.433 +
   1.434 +void
   1.435 +DrawTargetD2D1::PushClip(const Path *aPath)
   1.436 +{
   1.437 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   1.438 +    gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
   1.439 +    return;
   1.440 +  }
   1.441 +
   1.442 +  RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
   1.443 +
   1.444 +  PushedClip clip;
   1.445 +  clip.mTransform = D2DMatrix(mTransform);
   1.446 +  clip.mPath = pathD2D;
   1.447 +  
   1.448 +  pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
   1.449 +
   1.450 +  mPushedClips.push_back(clip);
   1.451 +
   1.452 +  // The transform of clips is relative to the world matrix, since we use the total
   1.453 +  // transform for the clips, make the world matrix identity.
   1.454 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.455 +  mTransformDirty = true;
   1.456 +
   1.457 +  if (mClipsArePushed) {
   1.458 +    PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform);
   1.459 +  }
   1.460 +}
   1.461 +
   1.462 +void
   1.463 +DrawTargetD2D1::PushClipRect(const Rect &aRect)
   1.464 +{
   1.465 +  if (!mTransform.IsRectilinear()) {
   1.466 +    // Whoops, this isn't a rectangle in device space, Direct2D will not deal
   1.467 +    // with this transform the way we want it to.
   1.468 +    // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
   1.469 +
   1.470 +    RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
   1.471 +    pathBuilder->MoveTo(aRect.TopLeft());
   1.472 +    pathBuilder->LineTo(aRect.TopRight());
   1.473 +    pathBuilder->LineTo(aRect.BottomRight());
   1.474 +    pathBuilder->LineTo(aRect.BottomLeft());
   1.475 +    pathBuilder->Close();
   1.476 +    RefPtr<Path> path = pathBuilder->Finish();
   1.477 +    return PushClip(path);
   1.478 +  }
   1.479 +
   1.480 +  PushedClip clip;
   1.481 +  Rect rect = mTransform.TransformBounds(aRect);
   1.482 +  IntRect intRect;
   1.483 +  clip.mIsPixelAligned = rect.ToIntRect(&intRect);
   1.484 +
   1.485 +  // Do not store the transform, just store the device space rectangle directly.
   1.486 +  clip.mBounds = D2DRect(rect);
   1.487 +
   1.488 +  mPushedClips.push_back(clip);
   1.489 +
   1.490 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.491 +  mTransformDirty = true;
   1.492 +
   1.493 +  if (mClipsArePushed) {
   1.494 +    mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   1.495 +  }
   1.496 +}
   1.497 +
   1.498 +void
   1.499 +DrawTargetD2D1::PopClip()
   1.500 +{
   1.501 +  if (mClipsArePushed) {
   1.502 +    if (mPushedClips.back().mPath) {
   1.503 +      mDC->PopLayer();
   1.504 +    } else {
   1.505 +      mDC->PopAxisAlignedClip();
   1.506 +    }
   1.507 +  }
   1.508 +  mPushedClips.pop_back();
   1.509 +}
   1.510 +
   1.511 +TemporaryRef<SourceSurface>
   1.512 +DrawTargetD2D1::CreateSourceSurfaceFromData(unsigned char *aData,
   1.513 +                                            const IntSize &aSize,
   1.514 +                                            int32_t aStride,
   1.515 +                                            SurfaceFormat aFormat) const
   1.516 +{
   1.517 +  RefPtr<ID2D1Bitmap1> bitmap;
   1.518 +
   1.519 +  HRESULT hr = mDC->CreateBitmap(D2DIntSize(aSize), aData, aStride,
   1.520 +                                 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(aFormat)),
   1.521 +                                 byRef(bitmap));
   1.522 +
   1.523 +  if (!bitmap) {
   1.524 +    return nullptr;
   1.525 +  }
   1.526 +
   1.527 +  return new SourceSurfaceD2D1(bitmap.get(), mDC, aFormat, aSize);
   1.528 +}
   1.529 +
   1.530 +TemporaryRef<DrawTarget>
   1.531 +DrawTargetD2D1::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
   1.532 +{
   1.533 +  RefPtr<DrawTargetD2D1> dt = new DrawTargetD2D1();
   1.534 +
   1.535 +  if (!dt->Init(aSize, aFormat)) {
   1.536 +    return nullptr;
   1.537 +  }
   1.538 +
   1.539 +  return dt;
   1.540 +}
   1.541 +
   1.542 +TemporaryRef<PathBuilder>
   1.543 +DrawTargetD2D1::CreatePathBuilder(FillRule aFillRule) const
   1.544 +{
   1.545 +  RefPtr<ID2D1PathGeometry> path;
   1.546 +  HRESULT hr = factory()->CreatePathGeometry(byRef(path));
   1.547 +
   1.548 +  if (FAILED(hr)) {
   1.549 +    gfxWarning() << *this << ": Failed to create Direct2D Path Geometry. Code: " << hr;
   1.550 +    return nullptr;
   1.551 +  }
   1.552 +
   1.553 +  RefPtr<ID2D1GeometrySink> sink;
   1.554 +  hr = path->Open(byRef(sink));
   1.555 +  if (FAILED(hr)) {
   1.556 +    gfxWarning() << *this << ": Failed to access Direct2D Path Geometry. Code: " << hr;
   1.557 +    return nullptr;
   1.558 +  }
   1.559 +
   1.560 +  if (aFillRule == FillRule::FILL_WINDING) {
   1.561 +    sink->SetFillMode(D2D1_FILL_MODE_WINDING);
   1.562 +  }
   1.563 +
   1.564 +  return new PathBuilderD2D(sink, path, aFillRule);
   1.565 +}
   1.566 +
   1.567 +TemporaryRef<GradientStops>
   1.568 +DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
   1.569 +{
   1.570 +  D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
   1.571 +
   1.572 +  for (uint32_t i = 0; i < aNumStops; i++) {
   1.573 +    stops[i].position = rawStops[i].offset;
   1.574 +    stops[i].color = D2DColor(rawStops[i].color);
   1.575 +  }
   1.576 +
   1.577 +  RefPtr<ID2D1GradientStopCollection> stopCollection;
   1.578 +
   1.579 +  HRESULT hr =
   1.580 +    mDC->CreateGradientStopCollection(stops, aNumStops,
   1.581 +                                      D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
   1.582 +                                      byRef(stopCollection));
   1.583 +  delete [] stops;
   1.584 +
   1.585 +  if (FAILED(hr)) {
   1.586 +    gfxWarning() << *this << ": Failed to create GradientStopCollection. Code: " << hr;
   1.587 +    return nullptr;
   1.588 +  }
   1.589 +
   1.590 +  return new GradientStopsD2D(stopCollection);
   1.591 +}
   1.592 +
   1.593 +TemporaryRef<FilterNode>
   1.594 +DrawTargetD2D1::CreateFilter(FilterType aType)
   1.595 +{
   1.596 +  return FilterNodeD2D1::Create(this, mDC, aType);
   1.597 +}
   1.598 +
   1.599 +bool
   1.600 +DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
   1.601 +{
   1.602 +  HRESULT hr;
   1.603 +  
   1.604 +  hr = Factory::GetD2D1Device()->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, byRef(mDC));
   1.605 +
   1.606 +  if (FAILED(hr)) {
   1.607 +    gfxWarning() << *this << ": Error " << hr << " failed to initialize new DeviceContext.";
   1.608 +    return false;
   1.609 +  }
   1.610 +
   1.611 +  D2D1_BITMAP_PROPERTIES1 props;
   1.612 +  props.dpiX = 96;
   1.613 +  props.dpiY = 96;
   1.614 +  props.pixelFormat = D2DPixelFormat(aFormat);
   1.615 +  props.colorContext = nullptr;
   1.616 +  props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
   1.617 +  mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mBitmap));
   1.618 +
   1.619 +  if (FAILED(hr)) {
   1.620 +    gfxWarning() << *this << ": Error " << hr << " failed to create new CommandList.";
   1.621 +    return false;
   1.622 +  }
   1.623 +
   1.624 +  mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(mTempBitmap));
   1.625 +
   1.626 +  mDC->SetTarget(mBitmap);
   1.627 +
   1.628 +  mDC->BeginDraw();
   1.629 +
   1.630 +  mFormat = aFormat;
   1.631 +  mSize = aSize;
   1.632 +
   1.633 +  return true;
   1.634 +}
   1.635 +
   1.636 +/**
   1.637 + * Private helpers.
   1.638 + */
   1.639 +uint32_t
   1.640 +DrawTargetD2D1::GetByteSize() const
   1.641 +{
   1.642 +  return mSize.width * mSize.height * BytesPerPixel(mFormat);
   1.643 +}
   1.644 +
   1.645 +ID2D1Factory1*
   1.646 +DrawTargetD2D1::factory()
   1.647 +{
   1.648 +  if (mFactory) {
   1.649 +    return mFactory;
   1.650 +  }
   1.651 +
   1.652 +  HRESULT hr = D2DFactory()->QueryInterface((ID2D1Factory1**)&mFactory);
   1.653 +
   1.654 +  if (FAILED(hr)) {
   1.655 +    return nullptr;
   1.656 +  }
   1.657 +
   1.658 +  RadialGradientEffectD2D1::Register(mFactory);
   1.659 +
   1.660 +  return mFactory;
   1.661 +}
   1.662 +
   1.663 +void
   1.664 +DrawTargetD2D1::MarkChanged()
   1.665 +{
   1.666 +  if (mSnapshot) {
   1.667 +    if (mSnapshot->hasOneRef()) {
   1.668 +      // Just destroy it, since no-one else knows about it.
   1.669 +      mSnapshot = nullptr;
   1.670 +    } else {
   1.671 +      mSnapshot->DrawTargetWillChange();
   1.672 +      // The snapshot will no longer depend on this target.
   1.673 +      MOZ_ASSERT(!mSnapshot);
   1.674 +    }
   1.675 +  }
   1.676 +  if (mDependentTargets.size()) {
   1.677 +    // Copy mDependentTargets since the Flush()es below will modify it.
   1.678 +    TargetSet tmpTargets = mDependentTargets;
   1.679 +    for (TargetSet::iterator iter = tmpTargets.begin();
   1.680 +         iter != tmpTargets.end(); iter++) {
   1.681 +      (*iter)->Flush();
   1.682 +    }
   1.683 +    // The Flush() should have broken all dependencies on this target.
   1.684 +    MOZ_ASSERT(!mDependentTargets.size());
   1.685 +  }
   1.686 +}
   1.687 +
   1.688 +void
   1.689 +DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
   1.690 +{
   1.691 +  MarkChanged();
   1.692 +
   1.693 +  // It's important to do this before FlushTransformToDC! As this will cause
   1.694 +  // the transform to become dirty.
   1.695 +  if (!mClipsArePushed) {
   1.696 +    mClipsArePushed = true;
   1.697 +    PushClipsToDC(mDC);
   1.698 +  }
   1.699 +
   1.700 +  FlushTransformToDC();
   1.701 +
   1.702 +  if (aOp == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
   1.703 +    return;
   1.704 +  }
   1.705 +
   1.706 +  mDC->SetTarget(mTempBitmap);
   1.707 +  mDC->Clear(D2D1::ColorF(0, 0));
   1.708 +}
   1.709 +
   1.710 +void
   1.711 +DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
   1.712 +{
   1.713 +  bool patternSupported = IsPatternSupportedByD2D(aPattern);
   1.714 +
   1.715 +  if (aOp == CompositionOp::OP_OVER && patternSupported) {
   1.716 +    return;
   1.717 +  }
   1.718 +
   1.719 +  RefPtr<ID2D1Image> image;
   1.720 +  mDC->GetTarget(byRef(image));
   1.721 +
   1.722 +  mDC->SetTarget(mBitmap);
   1.723 +
   1.724 +  if (patternSupported) {
   1.725 +    mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
   1.726 +    return;
   1.727 +  }
   1.728 +
   1.729 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.730 +  mTransformDirty = true;
   1.731 +
   1.732 +  RefPtr<ID2D1Effect> radialGradientEffect;
   1.733 +
   1.734 +  mDC->CreateEffect(CLSID_RadialGradientEffect, byRef(radialGradientEffect));
   1.735 +  const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
   1.736 +
   1.737 +  radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION,
   1.738 +                                 static_cast<const GradientStopsD2D*>(pat->mStops.get())->mStopCollection);
   1.739 +  radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y));
   1.740 +  radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y));
   1.741 +  radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1);
   1.742 +  radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
   1.743 +  radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
   1.744 +  radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform));
   1.745 +  radialGradientEffect->SetInput(0, image);
   1.746 +
   1.747 +  mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
   1.748 +}
   1.749 +
   1.750 +void
   1.751 +DrawTargetD2D1::AddDependencyOnSource(SourceSurfaceD2D1* aSource)
   1.752 +{
   1.753 +  if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
   1.754 +    aSource->mDrawTarget->mDependentTargets.insert(this);
   1.755 +    mDependingOnTargets.insert(aSource->mDrawTarget);
   1.756 +  }
   1.757 +}
   1.758 +
   1.759 +void
   1.760 +DrawTargetD2D1::PopAllClips()
   1.761 +{
   1.762 +  if (mClipsArePushed) {
   1.763 +    PopClipsFromDC(mDC);
   1.764 +  
   1.765 +    mClipsArePushed = false;
   1.766 +  }
   1.767 +}
   1.768 +
   1.769 +void
   1.770 +DrawTargetD2D1::PushClipsToDC(ID2D1DeviceContext *aDC)
   1.771 +{
   1.772 +  mDC->SetTransform(D2D1::IdentityMatrix());
   1.773 +  mTransformDirty = true;
   1.774 +
   1.775 +  for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
   1.776 +        iter != mPushedClips.end(); iter++) {
   1.777 +    if (iter->mPath) {
   1.778 +      PushD2DLayer(aDC, iter->mPath->mGeometry, iter->mTransform);
   1.779 +    } else {
   1.780 +      mDC->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   1.781 +    }
   1.782 +  }
   1.783 +}
   1.784 +
   1.785 +void
   1.786 +DrawTargetD2D1::PopClipsFromDC(ID2D1DeviceContext *aDC)
   1.787 +{
   1.788 +  for (int i = mPushedClips.size() - 1; i >= 0; i--) {
   1.789 +    if (mPushedClips[i].mPath) {
   1.790 +      aDC->PopLayer();
   1.791 +    } else {
   1.792 +      aDC->PopAxisAlignedClip();
   1.793 +    }
   1.794 +  }
   1.795 +}
   1.796 +
   1.797 +TemporaryRef<ID2D1Brush>
   1.798 +DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
   1.799 +{
   1.800 +  if (!IsPatternSupportedByD2D(aPattern)) {
   1.801 +    RefPtr<ID2D1SolidColorBrush> colBrush;
   1.802 +    mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
   1.803 +    return colBrush;
   1.804 +  }
   1.805 +
   1.806 +  if (aPattern.GetType() == PatternType::COLOR) {
   1.807 +    RefPtr<ID2D1SolidColorBrush> colBrush;
   1.808 +    Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
   1.809 +    mDC->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g,
   1.810 +                                            color.b, color.a),
   1.811 +                               D2D1::BrushProperties(aAlpha),
   1.812 +                               byRef(colBrush));
   1.813 +    return colBrush;
   1.814 +  } else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
   1.815 +    RefPtr<ID2D1LinearGradientBrush> gradBrush;
   1.816 +    const LinearGradientPattern *pat =
   1.817 +      static_cast<const LinearGradientPattern*>(&aPattern);
   1.818 +
   1.819 +    GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
   1.820 +
   1.821 +    if (!stops) {
   1.822 +      gfxDebug() << "No stops specified for gradient pattern.";
   1.823 +      return nullptr;
   1.824 +    }
   1.825 +
   1.826 +    if (pat->mBegin == pat->mEnd) {
   1.827 +      RefPtr<ID2D1SolidColorBrush> colBrush;
   1.828 +      uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
   1.829 +      vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
   1.830 +      stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
   1.831 +      mDC->CreateSolidColorBrush(d2dStops.back().color,
   1.832 +                                 D2D1::BrushProperties(aAlpha),
   1.833 +                                 byRef(colBrush));
   1.834 +      return colBrush;
   1.835 +    }
   1.836 +
   1.837 +    mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
   1.838 +                                                                       D2DPoint(pat->mEnd)),
   1.839 +                                   D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
   1.840 +                                   stops->mStopCollection,
   1.841 +                                   byRef(gradBrush));
   1.842 +    return gradBrush;
   1.843 +  } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
   1.844 +    RefPtr<ID2D1RadialGradientBrush> gradBrush;
   1.845 +    const RadialGradientPattern *pat =
   1.846 +      static_cast<const RadialGradientPattern*>(&aPattern);
   1.847 +
   1.848 +    GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
   1.849 +
   1.850 +    if (!stops) {
   1.851 +      gfxDebug() << "No stops specified for gradient pattern.";
   1.852 +      return nullptr;
   1.853 +    }
   1.854 +
   1.855 +    // This will not be a complex radial gradient brush.
   1.856 +    mDC->CreateRadialGradientBrush(
   1.857 +      D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2),
   1.858 +                                          D2DPoint(pat->mCenter1 - pat->mCenter2),
   1.859 +                                          pat->mRadius2, pat->mRadius2),
   1.860 +      D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
   1.861 +      stops->mStopCollection,
   1.862 +      byRef(gradBrush));
   1.863 +
   1.864 +    return gradBrush;
   1.865 +  } else if (aPattern.GetType() == PatternType::SURFACE) {
   1.866 +    const SurfacePattern *pat =
   1.867 +      static_cast<const SurfacePattern*>(&aPattern);
   1.868 +
   1.869 +    if (!pat->mSurface) {
   1.870 +      gfxDebug() << "No source surface specified for surface pattern";
   1.871 +      return nullptr;
   1.872 +    }
   1.873 +
   1.874 +
   1.875 +    Matrix mat = pat->mMatrix;
   1.876 +    
   1.877 +    RefPtr<ID2D1ImageBrush> imageBrush;
   1.878 +    RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode);
   1.879 +    mDC->CreateImageBrush(image,
   1.880 +                          D2D1::ImageBrushProperties(D2D1::RectF(0, 0,
   1.881 +                                                                  Float(pat->mSurface->GetSize().width),
   1.882 +                                                                  Float(pat->mSurface->GetSize().height)),
   1.883 +                                  D2DExtend(pat->mExtendMode), D2DExtend(pat->mExtendMode),
   1.884 +                                  D2DInterpolationMode(pat->mFilter)),
   1.885 +                          D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
   1.886 +                          byRef(imageBrush));
   1.887 +    return imageBrush;
   1.888 +  }
   1.889 +
   1.890 +  gfxWarning() << "Invalid pattern type detected.";
   1.891 +  return nullptr;
   1.892 +}
   1.893 +
   1.894 +TemporaryRef<ID2D1Image>
   1.895 +DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTransform,
   1.896 +                                   ExtendMode aExtendMode)
   1.897 +{
   1.898 +  RefPtr<ID2D1Image> image;
   1.899 +
   1.900 +  switch (aSurface->GetType()) {
   1.901 +  case SurfaceType::D2D1_1_IMAGE:
   1.902 +    {
   1.903 +      SourceSurfaceD2D1 *surf = static_cast<SourceSurfaceD2D1*>(aSurface);
   1.904 +      image = surf->GetImage();
   1.905 +      AddDependencyOnSource(surf);
   1.906 +    }
   1.907 +    break;
   1.908 +  default:
   1.909 +    {
   1.910 +      RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface();
   1.911 +      if (!dataSurf) {
   1.912 +        gfxWarning() << "Invalid surface type.";
   1.913 +        return nullptr;
   1.914 +      }
   1.915 +
   1.916 +      image = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode,
   1.917 +                                            aSourceTransform, mDC); 
   1.918 +
   1.919 +      return image;
   1.920 +    }
   1.921 +    break;
   1.922 +  }
   1.923 +
   1.924 +  return image;
   1.925 +}
   1.926 +
   1.927 +TemporaryRef<SourceSurface>
   1.928 +DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
   1.929 +{
   1.930 +  if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
   1.931 +    return aSurface;
   1.932 +  }
   1.933 +
   1.934 +  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
   1.935 +
   1.936 +  DataSourceSurface::MappedSurface map;
   1.937 +  if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
   1.938 +    return nullptr;
   1.939 +  }
   1.940 +
   1.941 +  RefPtr<ID2D1Bitmap1> bitmap;
   1.942 +  HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride,
   1.943 +                                 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
   1.944 +                                 byRef(bitmap));
   1.945 +
   1.946 +  data->Unmap();
   1.947 +
   1.948 +  if (!bitmap) {
   1.949 +    return data;
   1.950 +  }
   1.951 +
   1.952 +  return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
   1.953 +}
   1.954 +
   1.955 +void
   1.956 +DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
   1.957 +{
   1.958 +  D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
   1.959 +
   1.960 +  if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
   1.961 +    options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
   1.962 +  }
   1.963 +
   1.964 +  mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry,
   1.965 +                                        D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
   1.966 +                                        1.0, nullptr, options), nullptr);
   1.967 +}
   1.968 +
   1.969 +}
   1.970 +}

mercurial