gfx/2d/DrawTargetD2D.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/2d/DrawTargetD2D.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2762 @@
     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 "DrawTargetD2D.h"
    1.11 +#include "SourceSurfaceD2D.h"
    1.12 +#ifdef USE_D2D1_1
    1.13 +#include "SourceSurfaceD2D1.h"
    1.14 +#endif
    1.15 +#include "SourceSurfaceD2DTarget.h"
    1.16 +#include "ShadersD2D.h"
    1.17 +#include "PathD2D.h"
    1.18 +#include "GradientStopsD2D.h"
    1.19 +#include "ScaledFontDWrite.h"
    1.20 +#include "ImageScaling.h"
    1.21 +#include "Logging.h"
    1.22 +#include "Tools.h"
    1.23 +#include <algorithm>
    1.24 +#include "mozilla/Constants.h"
    1.25 +#include "FilterNodeSoftware.h"
    1.26 +
    1.27 +#ifdef USE_D2D1_1
    1.28 +#include "FilterNodeD2D1.h"
    1.29 +#endif
    1.30 +
    1.31 +#include <dwrite.h>
    1.32 +
    1.33 +// decltype is not usable for overloaded functions.
    1.34 +typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
    1.35 +    D2D1_FACTORY_TYPE factoryType,
    1.36 +    REFIID iid,
    1.37 +    CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
    1.38 +    void **factory
    1.39 +);
    1.40 +
    1.41 +using namespace std;
    1.42 +
    1.43 +namespace mozilla {
    1.44 +namespace gfx {
    1.45 +
    1.46 +struct Vertex {
    1.47 +  float x;
    1.48 +  float y;
    1.49 +};
    1.50 +
    1.51 +ID2D1Factory *DrawTargetD2D::mFactory;
    1.52 +IDWriteFactory *DrawTargetD2D::mDWriteFactory;
    1.53 +uint64_t DrawTargetD2D::mVRAMUsageDT;
    1.54 +uint64_t DrawTargetD2D::mVRAMUsageSS;
    1.55 +
    1.56 +// Helper class to restore surface contents that was clipped out but may have
    1.57 +// been altered by a drawing call.
    1.58 +class AutoSaveRestoreClippedOut
    1.59 +{
    1.60 +public:
    1.61 +  AutoSaveRestoreClippedOut(DrawTargetD2D *aDT)
    1.62 +    : mDT(aDT)
    1.63 +  {}
    1.64 +
    1.65 +  void Save() {
    1.66 +    if (!mDT->mPushedClips.size()) {
    1.67 +      return;
    1.68 +    }
    1.69 +
    1.70 +    mDT->Flush();
    1.71 +
    1.72 +    RefPtr<ID3D10Texture2D> tmpTexture;
    1.73 +    IntSize size = mDT->mSize;
    1.74 +    SurfaceFormat format = mDT->mFormat;
    1.75 +
    1.76 +    CD3D10_TEXTURE2D_DESC desc(DXGIFormat(format), size.width, size.height,
    1.77 +                               1, 1);
    1.78 +    desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    1.79 +
    1.80 +    HRESULT hr = mDT->mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpTexture));
    1.81 +    if (FAILED(hr)) {
    1.82 +      gfxWarning() << "Failed to create temporary texture to hold surface data.";
    1.83 +    }
    1.84 +    mDT->mDevice->CopyResource(tmpTexture, mDT->mTexture);
    1.85 +
    1.86 +    D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(format));
    1.87 +
    1.88 +    RefPtr<IDXGISurface> surf;
    1.89 +
    1.90 +    tmpTexture->QueryInterface((IDXGISurface**)byRef(surf));
    1.91 +
    1.92 +    hr = mDT->mRT->CreateSharedBitmap(IID_IDXGISurface, surf,
    1.93 +                                      &props, byRef(mOldSurfBitmap));
    1.94 +
    1.95 +    if (FAILED(hr)) {
    1.96 +      gfxWarning() << "Failed to create shared bitmap for old surface.";
    1.97 +    }
    1.98 +
    1.99 +    IntRect clipBounds;
   1.100 +    mClippedArea = mDT->GetClippedGeometry(&clipBounds);
   1.101 +
   1.102 +    if (!clipBounds.IsEqualEdges(IntRect(IntPoint(0, 0), mDT->mSize))) {
   1.103 +      // We still need to take into account clipBounds if it contains additional
   1.104 +      // clipping information.
   1.105 +      RefPtr<ID2D1RectangleGeometry> rectGeom;
   1.106 +      factory()->CreateRectangleGeometry(D2D1::Rect(Float(clipBounds.x),
   1.107 +                                                    Float(clipBounds.y),
   1.108 +                                                    Float(clipBounds.XMost()),
   1.109 +                                                    Float(clipBounds.YMost())),
   1.110 +                                         byRef(rectGeom));
   1.111 +
   1.112 +      mClippedArea = IntersectGeometry(mClippedArea, rectGeom);
   1.113 +    }
   1.114 +  }
   1.115 +
   1.116 +  ID2D1Factory *factory() { return mDT->factory(); }
   1.117 +
   1.118 +  ~AutoSaveRestoreClippedOut()
   1.119 +  {
   1.120 +    if (!mOldSurfBitmap) {
   1.121 +      return;
   1.122 +    }
   1.123 +
   1.124 +    ID2D1RenderTarget *rt = mDT->mRT;
   1.125 +
   1.126 +    // Write the area that was clipped out back to the surface. This all
   1.127 +    // happens in device space.
   1.128 +    rt->SetTransform(D2D1::IdentityMatrix());
   1.129 +    mDT->mTransformDirty = true;
   1.130 +
   1.131 +    RefPtr<ID2D1RectangleGeometry> rectGeom;
   1.132 +    factory()->CreateRectangleGeometry(
   1.133 +      D2D1::RectF(0, 0, float(mDT->mSize.width), float(mDT->mSize.height)),
   1.134 +      byRef(rectGeom));
   1.135 +
   1.136 +    RefPtr<ID2D1PathGeometry> invClippedArea;
   1.137 +    factory()->CreatePathGeometry(byRef(invClippedArea));
   1.138 +    RefPtr<ID2D1GeometrySink> sink;
   1.139 +    invClippedArea->Open(byRef(sink));
   1.140 +
   1.141 +    rectGeom->CombineWithGeometry(mClippedArea, D2D1_COMBINE_MODE_EXCLUDE, nullptr, sink);
   1.142 +    sink->Close();
   1.143 +
   1.144 +    RefPtr<ID2D1BitmapBrush> brush;
   1.145 +    rt->CreateBitmapBrush(mOldSurfBitmap, D2D1::BitmapBrushProperties(), D2D1::BrushProperties(), byRef(brush));                   
   1.146 +
   1.147 +    rt->FillGeometry(invClippedArea, brush);
   1.148 +  }
   1.149 +
   1.150 +private:
   1.151 +
   1.152 +  DrawTargetD2D *mDT;  
   1.153 +
   1.154 +  // If we have an operator unbound by the source, this will contain a bitmap
   1.155 +  // with the old dest surface data.
   1.156 +  RefPtr<ID2D1Bitmap> mOldSurfBitmap;
   1.157 +  // This contains the area drawing is clipped to.
   1.158 +  RefPtr<ID2D1Geometry> mClippedArea;
   1.159 +};
   1.160 +
   1.161 +ID2D1Factory *D2DFactory()
   1.162 +{
   1.163 +  return DrawTargetD2D::factory();
   1.164 +}
   1.165 +
   1.166 +DrawTargetD2D::DrawTargetD2D()
   1.167 +  : mCurrentCachedLayer(0)
   1.168 +  , mClipsArePushed(false)
   1.169 +  , mPrivateData(nullptr)
   1.170 +{
   1.171 +}
   1.172 +
   1.173 +DrawTargetD2D::~DrawTargetD2D()
   1.174 +{
   1.175 +  if (mRT) {  
   1.176 +    PopAllClips();
   1.177 +
   1.178 +    mRT->EndDraw();
   1.179 +
   1.180 +    mVRAMUsageDT -= GetByteSize();
   1.181 +  }
   1.182 +  if (mTempRT) {
   1.183 +    mTempRT->EndDraw();
   1.184 +
   1.185 +    mVRAMUsageDT -= GetByteSize();
   1.186 +  }
   1.187 +
   1.188 +  if (mSnapshot) {
   1.189 +    // We may hold the only reference. MarkIndependent will clear mSnapshot;
   1.190 +    // keep the snapshot object alive so it doesn't get destroyed while
   1.191 +    // MarkIndependent is running.
   1.192 +    RefPtr<SourceSurfaceD2DTarget> deathGrip = mSnapshot;
   1.193 +    // mSnapshot can be treated as independent of this DrawTarget since we know
   1.194 +    // this DrawTarget won't change again.
   1.195 +    deathGrip->MarkIndependent();
   1.196 +    // mSnapshot will be cleared now.
   1.197 +  }
   1.198 +
   1.199 +  for (int i = 0; i < kLayerCacheSize; i++) {
   1.200 +    if (mCachedLayers[i]) {
   1.201 +      mCachedLayers[i] = nullptr;
   1.202 +      mVRAMUsageDT -= GetByteSize();
   1.203 +    }
   1.204 +  }
   1.205 +
   1.206 +  // Targets depending on us can break that dependency, since we're obviously not going to
   1.207 +  // be modified in the future.
   1.208 +  for (TargetSet::iterator iter = mDependentTargets.begin();
   1.209 +       iter != mDependentTargets.end(); iter++) {
   1.210 +    (*iter)->mDependingOnTargets.erase(this);
   1.211 +  }
   1.212 +  // Our dependencies on other targets no longer matter.
   1.213 +  for (TargetSet::iterator iter = mDependingOnTargets.begin();
   1.214 +       iter != mDependingOnTargets.end(); iter++) {
   1.215 +    (*iter)->mDependentTargets.erase(this);
   1.216 +  }
   1.217 +}
   1.218 +
   1.219 +/*
   1.220 + * DrawTarget Implementation
   1.221 + */
   1.222 +TemporaryRef<SourceSurface>
   1.223 +DrawTargetD2D::Snapshot()
   1.224 +{
   1.225 +  if (!mSnapshot) {
   1.226 +    mSnapshot = new SourceSurfaceD2DTarget(this, mTexture, mFormat);
   1.227 +    Flush();
   1.228 +  }
   1.229 +
   1.230 +  return mSnapshot;
   1.231 +}
   1.232 +
   1.233 +void
   1.234 +DrawTargetD2D::Flush()
   1.235 +{
   1.236 +  PopAllClips();
   1.237 +
   1.238 +  HRESULT hr = mRT->Flush();
   1.239 +
   1.240 +  if (FAILED(hr)) {
   1.241 +    gfxWarning() << "Error reported when trying to flush D2D rendertarget. Code: " << hr;
   1.242 +  }
   1.243 +
   1.244 +  // We no longer depend on any target.
   1.245 +  for (TargetSet::iterator iter = mDependingOnTargets.begin();
   1.246 +       iter != mDependingOnTargets.end(); iter++) {
   1.247 +    (*iter)->mDependentTargets.erase(this);
   1.248 +  }
   1.249 +  mDependingOnTargets.clear();
   1.250 +}
   1.251 +
   1.252 +void
   1.253 +DrawTargetD2D::AddDependencyOnSource(SourceSurfaceD2DTarget* aSource)
   1.254 +{
   1.255 +  if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
   1.256 +    aSource->mDrawTarget->mDependentTargets.insert(this);
   1.257 +    mDependingOnTargets.insert(aSource->mDrawTarget);
   1.258 +  }
   1.259 +}
   1.260 +
   1.261 +TemporaryRef<ID2D1Bitmap>
   1.262 +DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface,
   1.263 +                                   Rect &aSource)
   1.264 +{
   1.265 +  RefPtr<ID2D1Bitmap> bitmap;
   1.266 +
   1.267 +  switch (aSurface->GetType()) {
   1.268 +
   1.269 +  case SurfaceType::D2D1_BITMAP:
   1.270 +    {
   1.271 +      SourceSurfaceD2D *srcSurf = static_cast<SourceSurfaceD2D*>(aSurface);
   1.272 +      bitmap = srcSurf->GetBitmap();
   1.273 +    }
   1.274 +    break;
   1.275 +  case SurfaceType::D2D1_DRAWTARGET:
   1.276 +    {
   1.277 +      SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
   1.278 +      bitmap = srcSurf->GetBitmap(mRT);
   1.279 +      AddDependencyOnSource(srcSurf);
   1.280 +    }
   1.281 +    break;
   1.282 +  default:
   1.283 +    {
   1.284 +      RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
   1.285 +
   1.286 +      if (!srcSurf) {
   1.287 +        gfxDebug() << "Not able to deal with non-data source surface.";
   1.288 +        return nullptr;
   1.289 +      }
   1.290 +
   1.291 +      // We need to include any pixels that are overlapped by aSource
   1.292 +      Rect sourceRect(aSource);
   1.293 +      sourceRect.RoundOut();
   1.294 +
   1.295 +      if (sourceRect.IsEmpty()) {
   1.296 +        gfxDebug() << "Bitmap source is empty. DrawBitmap will silently fail.";
   1.297 +        return nullptr;
   1.298 +      }
   1.299 +
   1.300 +      if (sourceRect.width > mRT->GetMaximumBitmapSize() ||
   1.301 +          sourceRect.height > mRT->GetMaximumBitmapSize()) {
   1.302 +        gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail.";
   1.303 +        // Don't know how to deal with this yet.
   1.304 +        return nullptr;
   1.305 +      }
   1.306 +
   1.307 +      int stride = srcSurf->Stride();
   1.308 +
   1.309 +      unsigned char *data = srcSurf->GetData() +
   1.310 +                            (uint32_t)sourceRect.y * stride +
   1.311 +                            (uint32_t)sourceRect.x * BytesPerPixel(srcSurf->GetFormat());
   1.312 +
   1.313 +      D2D1_BITMAP_PROPERTIES props =
   1.314 +        D2D1::BitmapProperties(D2DPixelFormat(srcSurf->GetFormat()));
   1.315 +      mRT->CreateBitmap(D2D1::SizeU(UINT32(sourceRect.width), UINT32(sourceRect.height)), data, stride, props, byRef(bitmap));
   1.316 +
   1.317 +      // subtract the integer part leaving the fractional part
   1.318 +      aSource.x -= (uint32_t)aSource.x;
   1.319 +      aSource.y -= (uint32_t)aSource.y;
   1.320 +    }
   1.321 +    break;
   1.322 +  }
   1.323 +
   1.324 +  return bitmap;
   1.325 +}
   1.326 +
   1.327 +#ifdef USE_D2D1_1
   1.328 +TemporaryRef<ID2D1Image>
   1.329 +DrawTargetD2D::GetImageForSurface(SourceSurface *aSurface)
   1.330 +{
   1.331 +  RefPtr<ID2D1Image> image;
   1.332 +
   1.333 +  if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
   1.334 +    image = static_cast<SourceSurfaceD2D1*>(aSurface)->GetImage();
   1.335 +    static_cast<SourceSurfaceD2D1*>(aSurface)->EnsureIndependent();
   1.336 +  } else {
   1.337 +    Rect r(Point(), Size(aSurface->GetSize()));
   1.338 +    image = GetBitmapForSurface(aSurface, r);
   1.339 +  }
   1.340 +
   1.341 +  return image;
   1.342 +}
   1.343 +#endif
   1.344 +
   1.345 +void
   1.346 +DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
   1.347 +                           const Rect &aDest,
   1.348 +                           const Rect &aSource,
   1.349 +                           const DrawSurfaceOptions &aSurfOptions,
   1.350 +                           const DrawOptions &aOptions)
   1.351 +{
   1.352 +  RefPtr<ID2D1Bitmap> bitmap;
   1.353 +
   1.354 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   1.355 +  
   1.356 +  PrepareForDrawing(rt);
   1.357 +
   1.358 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.359 +
   1.360 +  Rect srcRect = aSource;
   1.361 +
   1.362 +  bitmap = GetBitmapForSurface(aSurface, srcRect);
   1.363 +  if (!bitmap) {
   1.364 +      return;
   1.365 +  }
   1.366 + 
   1.367 +  rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect));
   1.368 +
   1.369 +  FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), aDest);
   1.370 +}
   1.371 +
   1.372 +void
   1.373 +DrawTargetD2D::DrawFilter(FilterNode *aNode,
   1.374 +                          const Rect &aSourceRect,
   1.375 +                          const Point &aDestPoint,
   1.376 +                          const DrawOptions &aOptions)
   1.377 +{
   1.378 +#ifdef USE_D2D1_1
   1.379 +  RefPtr<ID2D1DeviceContext> dc;
   1.380 +  HRESULT hr;
   1.381 +  
   1.382 +  hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc));
   1.383 +
   1.384 +  if (SUCCEEDED(hr) && aNode->GetBackendType() == FILTER_BACKEND_DIRECT2D1_1) {
   1.385 +    ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   1.386 +  
   1.387 +    PrepareForDrawing(rt);
   1.388 +
   1.389 +    rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.390 +    hr = rt->QueryInterface((ID2D1DeviceContext**)byRef(dc));
   1.391 +
   1.392 +    if (SUCCEEDED(hr)) {
   1.393 +      dc->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
   1.394 +
   1.395 +      Rect destRect = aSourceRect;
   1.396 +      destRect.MoveBy(aDestPoint);
   1.397 +      FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), destRect);
   1.398 +      return;
   1.399 +    }
   1.400 +  }
   1.401 +#endif
   1.402 +
   1.403 +  if (aNode->GetBackendType() != FILTER_BACKEND_SOFTWARE) {
   1.404 +    gfxWarning() << "Invalid filter backend passed to DrawTargetD2D!";
   1.405 +    return;
   1.406 +  }
   1.407 +
   1.408 +  FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode);
   1.409 +  filter->Draw(this, aSourceRect, aDestPoint, aOptions);
   1.410 +}
   1.411 +
   1.412 +void
   1.413 +DrawTargetD2D::MaskSurface(const Pattern &aSource,
   1.414 +                           SourceSurface *aMask,
   1.415 +                           Point aOffset,
   1.416 +                           const DrawOptions &aOptions)
   1.417 +{
   1.418 +  RefPtr<ID2D1Bitmap> bitmap;
   1.419 +
   1.420 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   1.421 +
   1.422 +  PrepareForDrawing(rt);
   1.423 +
   1.424 +  // FillOpacityMask only works if the antialias mode is MODE_ALIASED
   1.425 +  rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   1.426 +
   1.427 +  IntSize size = aMask->GetSize();
   1.428 +  Rect maskRect = Rect(0.f, 0.f, size.width, size.height);
   1.429 +  bitmap = GetBitmapForSurface(aMask, maskRect);
   1.430 +  if (!bitmap) {
   1.431 +       return;
   1.432 +  }
   1.433 +
   1.434 +  Rect dest = Rect(aOffset.x, aOffset.y, size.width, size.height);
   1.435 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
   1.436 +  rt->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
   1.437 +
   1.438 +  FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), dest);
   1.439 +}
   1.440 +
   1.441 +void
   1.442 +DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
   1.443 +                                     const Point &aDest,
   1.444 +                                     const Color &aColor,
   1.445 +                                     const Point &aOffset,
   1.446 +                                     Float aSigma,
   1.447 +                                     CompositionOp aOperator)
   1.448 +{
   1.449 +  RefPtr<ID3D10ShaderResourceView> srView = nullptr;
   1.450 +  if (aSurface->GetType() != SurfaceType::D2D1_DRAWTARGET) {
   1.451 +    return;
   1.452 +  }
   1.453 +
   1.454 +  SetScissorToRect(nullptr);
   1.455 +
   1.456 +  // XXX - This function is way too long, it should be split up soon to make
   1.457 +  // it more graspable!
   1.458 +
   1.459 +  Flush();
   1.460 +
   1.461 +  AutoSaveRestoreClippedOut restoreClippedOut(this);
   1.462 +
   1.463 +  if (!IsOperatorBoundByMask(aOperator)) {
   1.464 +    restoreClippedOut.Save();
   1.465 +  }
   1.466 +
   1.467 +  srView = static_cast<SourceSurfaceD2DTarget*>(aSurface)->GetSRView();
   1.468 +
   1.469 +  EnsureViews();
   1.470 +
   1.471 +  if (!mTempRTView) {
   1.472 +    // This view is only needed in this path.
   1.473 +    HRESULT hr = mDevice->CreateRenderTargetView(mTempTexture, nullptr, byRef(mTempRTView));
   1.474 +
   1.475 +    if (FAILED(hr)) {
   1.476 +      gfxWarning() << "Failure to create RenderTargetView. Code: " << hr;
   1.477 +      return;
   1.478 +    }
   1.479 +  }
   1.480 +
   1.481 +
   1.482 +  RefPtr<ID3D10RenderTargetView> destRTView = mRTView;
   1.483 +  RefPtr<ID3D10Texture2D> destTexture;
   1.484 +  HRESULT hr;
   1.485 +
   1.486 +  RefPtr<ID3D10Texture2D> maskTexture;
   1.487 +  RefPtr<ID3D10ShaderResourceView> maskSRView;
   1.488 +  IntRect clipBounds;
   1.489 +  if (mPushedClips.size()) {
   1.490 +    EnsureClipMaskTexture(&clipBounds);
   1.491 +
   1.492 +    mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(maskSRView));
   1.493 +  }
   1.494 +
   1.495 +  IntSize srcSurfSize;
   1.496 +  ID3D10RenderTargetView *rtViews;
   1.497 +  D3D10_VIEWPORT viewport;
   1.498 +
   1.499 +  UINT stride = sizeof(Vertex);
   1.500 +  UINT offset = 0;
   1.501 +  ID3D10Buffer *buff = mPrivateData->mVB;
   1.502 +
   1.503 +  mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   1.504 +  mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
   1.505 +  mDevice->IASetInputLayout(mPrivateData->mInputLayout);
   1.506 +
   1.507 +  mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   1.508 +    SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f));
   1.509 +  mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   1.510 +    SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
   1.511 +
   1.512 +  // If we create a downsampled source surface we need to correct aOffset for that.
   1.513 +  Point correctedOffset = aOffset + aDest;
   1.514 +
   1.515 +  // The 'practical' scaling factors.
   1.516 +  Float dsFactorX = 1.0f;
   1.517 +  Float dsFactorY = 1.0f;
   1.518 +
   1.519 +  if (aSigma > 1.7f) {
   1.520 +    // In this case 9 samples of our original will not cover it. Generate the
   1.521 +    // mip levels for the original and create a downsampled version from
   1.522 +    // them. We generate a version downsampled so that a kernel for a sigma
   1.523 +    // of 1.7 will produce the right results.
   1.524 +    float blurWeights[9] = { 0.234671f, 0.197389f, 0.197389f, 0.117465f, 0.117465f, 0.049456f, 0.049456f, 0.014732f, 0.014732f };
   1.525 +    mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights));
   1.526 +    
   1.527 +    CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
   1.528 +                               aSurface->GetSize().width,
   1.529 +                               aSurface->GetSize().height);
   1.530 +    desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   1.531 +    desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS;
   1.532 +
   1.533 +    RefPtr<ID3D10Texture2D> mipTexture;
   1.534 +    hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mipTexture));
   1.535 +
   1.536 +    if (FAILED(hr)) {
   1.537 +      gfxWarning() << "Failure to create temporary texture. Size: " <<
   1.538 +        aSurface->GetSize() << " Code: " << hr;
   1.539 +      return;
   1.540 +    }
   1.541 +
   1.542 +    IntSize dsSize = IntSize(int32_t(aSurface->GetSize().width * (1.7f / aSigma)),
   1.543 +                             int32_t(aSurface->GetSize().height * (1.7f / aSigma)));
   1.544 +
   1.545 +    if (dsSize.width < 1) {
   1.546 +      dsSize.width = 1;
   1.547 +    }
   1.548 +    if (dsSize.height < 1) {
   1.549 +      dsSize.height = 1;
   1.550 +    }
   1.551 +
   1.552 +    dsFactorX = dsSize.width / Float(aSurface->GetSize().width);
   1.553 +    dsFactorY = dsSize.height / Float(aSurface->GetSize().height);
   1.554 +    correctedOffset.x *= dsFactorX;
   1.555 +    correctedOffset.y *= dsFactorY;
   1.556 +
   1.557 +    desc = CD3D10_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM,
   1.558 +                                 dsSize.width,
   1.559 +                                 dsSize.height, 1, 1);
   1.560 +    desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   1.561 +    RefPtr<ID3D10Texture2D> tmpDSTexture;
   1.562 +    hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpDSTexture));
   1.563 +
   1.564 +    if (FAILED(hr)) {
   1.565 +      gfxWarning() << "Failure to create temporary texture. Size: " << dsSize << " Code: " << hr;
   1.566 +      return;
   1.567 +    }
   1.568 +
   1.569 +    D3D10_BOX box;
   1.570 +    box.left = box.top = box.front = 0;
   1.571 +    box.back = 1;
   1.572 +    box.right = aSurface->GetSize().width;
   1.573 +    box.bottom = aSurface->GetSize().height;
   1.574 +    mDevice->CopySubresourceRegion(mipTexture, 0, 0, 0, 0, static_cast<SourceSurfaceD2DTarget*>(aSurface)->mTexture, 0, &box);
   1.575 +
   1.576 +    mDevice->CreateShaderResourceView(mipTexture, nullptr,  byRef(srView));
   1.577 +    mDevice->GenerateMips(srView);
   1.578 +
   1.579 +    RefPtr<ID3D10RenderTargetView> dsRTView;
   1.580 +    RefPtr<ID3D10ShaderResourceView> dsSRView;
   1.581 +    mDevice->CreateRenderTargetView(tmpDSTexture, nullptr,  byRef(dsRTView));
   1.582 +    mDevice->CreateShaderResourceView(tmpDSTexture, nullptr,  byRef(dsSRView));
   1.583 +
   1.584 +    // We're not guaranteed the texture we created will be empty, we've
   1.585 +    // seen old content at least on NVidia drivers.
   1.586 +    float color[4] = { 0, 0, 0, 0 };
   1.587 +    mDevice->ClearRenderTargetView(dsRTView, color);
   1.588 +
   1.589 +    rtViews = dsRTView;
   1.590 +    mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   1.591 +
   1.592 +    viewport.MaxDepth = 1;
   1.593 +    viewport.MinDepth = 0;
   1.594 +    viewport.Height = dsSize.height;
   1.595 +    viewport.Width = dsSize.width;
   1.596 +    viewport.TopLeftX = 0;
   1.597 +    viewport.TopLeftY = 0;
   1.598 +
   1.599 +    mDevice->RSSetViewports(1, &viewport);
   1.600 +    mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
   1.601 +    mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
   1.602 +      GetPassByIndex(0)->Apply(0);
   1.603 +
   1.604 +    mDevice->OMSetBlendState(GetBlendStateForOperator(CompositionOp::OP_OVER), nullptr, 0xffffffff);
   1.605 +
   1.606 +    mDevice->Draw(4, 0);
   1.607 +    
   1.608 +    srcSurfSize = dsSize;
   1.609 +
   1.610 +    srView = dsSRView;
   1.611 +  } else {
   1.612 +    // In this case generate a kernel to draw the blur directly to the temp
   1.613 +    // surf in one direction and to final in the other.
   1.614 +    float blurWeights[9];
   1.615 +
   1.616 +    float normalizeFactor = 1.0f;
   1.617 +    if (aSigma != 0) {
   1.618 +      normalizeFactor = 1.0f / Float(sqrt(2 * M_PI * pow(aSigma, 2)));
   1.619 +    }
   1.620 +
   1.621 +    blurWeights[0] = normalizeFactor;
   1.622 +
   1.623 +    // XXX - We should actually optimize for Sigma = 0 here. We could use a
   1.624 +    // much simpler shader and save a lot of texture lookups.
   1.625 +    for (int i = 1; i < 9; i += 2) {
   1.626 +      if (aSigma != 0) {
   1.627 +        blurWeights[i] = blurWeights[i + 1] = normalizeFactor *
   1.628 +          exp(-pow(float((i + 1) / 2), 2) / (2 * pow(aSigma, 2)));
   1.629 +      } else {
   1.630 +        blurWeights[i] = blurWeights[i + 1] = 0;
   1.631 +      }
   1.632 +    }
   1.633 +    
   1.634 +    mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights));
   1.635 +
   1.636 +    viewport.MaxDepth = 1;
   1.637 +    viewport.MinDepth = 0;
   1.638 +    viewport.Height = aSurface->GetSize().height;
   1.639 +    viewport.Width = aSurface->GetSize().width;
   1.640 +    viewport.TopLeftX = 0;
   1.641 +    viewport.TopLeftY = 0;
   1.642 +
   1.643 +    mDevice->RSSetViewports(1, &viewport);
   1.644 +
   1.645 +    srcSurfSize = aSurface->GetSize();
   1.646 +  }
   1.647 +
   1.648 +  // We may need to draw to a different intermediate surface if our temp
   1.649 +  // texture isn't big enough.
   1.650 +  bool needBiggerTemp = srcSurfSize.width > mSize.width ||
   1.651 +                        srcSurfSize.height > mSize.height;
   1.652 +
   1.653 +  RefPtr<ID3D10RenderTargetView> tmpRTView;
   1.654 +  RefPtr<ID3D10ShaderResourceView> tmpSRView;
   1.655 +  RefPtr<ID3D10Texture2D> tmpTexture;
   1.656 +  
   1.657 +  IntSize tmpSurfSize = mSize;
   1.658 +
   1.659 +  if (!needBiggerTemp) {
   1.660 +    tmpRTView = mTempRTView;
   1.661 +    tmpSRView = mSRView;
   1.662 +
   1.663 +    // There could still be content here!
   1.664 +    float color[4] = { 0, 0, 0, 0 };
   1.665 +    mDevice->ClearRenderTargetView(tmpRTView, color);
   1.666 +  } else {
   1.667 +    CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
   1.668 +                               srcSurfSize.width,
   1.669 +                               srcSurfSize.height,
   1.670 +                               1, 1);
   1.671 +    desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   1.672 +
   1.673 +    mDevice->CreateTexture2D(&desc, nullptr,  byRef(tmpTexture));
   1.674 +    mDevice->CreateRenderTargetView(tmpTexture, nullptr,  byRef(tmpRTView));
   1.675 +    mDevice->CreateShaderResourceView(tmpTexture, nullptr,  byRef(tmpSRView));
   1.676 +
   1.677 +    tmpSurfSize = srcSurfSize;
   1.678 +  }
   1.679 +
   1.680 +  rtViews = tmpRTView;
   1.681 +  mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   1.682 +
   1.683 +  mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
   1.684 +
   1.685 +  // Premultiplied!
   1.686 +  float shadowColor[4] = { aColor.r * aColor.a, aColor.g * aColor.a,
   1.687 +                           aColor.b * aColor.a, aColor.a };
   1.688 +  mPrivateData->mEffect->GetVariableByName("ShadowColor")->AsVector()->
   1.689 +    SetFloatVector(shadowColor);
   1.690 +
   1.691 +  float pixelOffset = 1.0f / float(srcSurfSize.width);
   1.692 +  float blurOffsetsH[9] = { 0, pixelOffset, -pixelOffset,
   1.693 +                            2.0f * pixelOffset, -2.0f * pixelOffset,
   1.694 +                            3.0f * pixelOffset, -3.0f * pixelOffset,
   1.695 +                            4.0f * pixelOffset, - 4.0f * pixelOffset };
   1.696 +
   1.697 +  pixelOffset = 1.0f / float(tmpSurfSize.height);
   1.698 +  float blurOffsetsV[9] = { 0, pixelOffset, -pixelOffset,
   1.699 +                            2.0f * pixelOffset, -2.0f * pixelOffset,
   1.700 +                            3.0f * pixelOffset, -3.0f * pixelOffset,
   1.701 +                            4.0f * pixelOffset, - 4.0f * pixelOffset };
   1.702 +
   1.703 +  mPrivateData->mEffect->GetVariableByName("BlurOffsetsH")->
   1.704 +    SetRawValue(blurOffsetsH, 0, sizeof(blurOffsetsH));
   1.705 +  mPrivateData->mEffect->GetVariableByName("BlurOffsetsV")->
   1.706 +    SetRawValue(blurOffsetsV, 0, sizeof(blurOffsetsV));
   1.707 +
   1.708 +  mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   1.709 +    GetPassByIndex(0)->Apply(0);
   1.710 +
   1.711 +  mDevice->Draw(4, 0);
   1.712 +
   1.713 +  viewport.MaxDepth = 1;
   1.714 +  viewport.MinDepth = 0;
   1.715 +  viewport.Height = mSize.height;
   1.716 +  viewport.Width = mSize.width;
   1.717 +  viewport.TopLeftX = 0;
   1.718 +  viewport.TopLeftY = 0;
   1.719 +
   1.720 +  mDevice->RSSetViewports(1, &viewport);
   1.721 +
   1.722 +  mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(tmpSRView);
   1.723 +
   1.724 +  rtViews = destRTView;
   1.725 +  mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   1.726 +
   1.727 +  Point shadowDest = aDest + aOffset;
   1.728 +
   1.729 +  mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   1.730 +    SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((shadowDest.x / mSize.width) * 2.0f),
   1.731 +                                           1.0f - (shadowDest.y / mSize.height * 2.0f),
   1.732 +                                           (Float(aSurface->GetSize().width) / mSize.width) * 2.0f,
   1.733 +                                           (-Float(aSurface->GetSize().height) / mSize.height) * 2.0f));
   1.734 +  mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   1.735 +    SetFloatVector(ShaderConstantRectD3D10(0, 0, Float(srcSurfSize.width) / tmpSurfSize.width,
   1.736 +                                                 Float(srcSurfSize.height) / tmpSurfSize.height));
   1.737 +
   1.738 +  if (mPushedClips.size()) {
   1.739 +    mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(maskSRView);
   1.740 +    mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
   1.741 +      SetFloatVector(ShaderConstantRectD3D10(shadowDest.x / mSize.width, shadowDest.y / mSize.height,
   1.742 +                                             Float(aSurface->GetSize().width) / mSize.width,
   1.743 +                                             Float(aSurface->GetSize().height) / mSize.height));
   1.744 +    mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   1.745 +      GetPassByIndex(2)->Apply(0);
   1.746 +    SetScissorToRect(&clipBounds);
   1.747 +  } else {
   1.748 +    mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   1.749 +      GetPassByIndex(1)->Apply(0);
   1.750 +  }
   1.751 +
   1.752 +  mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
   1.753 +
   1.754 +  mDevice->Draw(4, 0);
   1.755 +
   1.756 +  mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   1.757 +    SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((aDest.x / mSize.width) * 2.0f),
   1.758 +                                           1.0f - (aDest.y / mSize.height * 2.0f),
   1.759 +                                           (Float(aSurface->GetSize().width) / mSize.width) * 2.0f,
   1.760 +                                           (-Float(aSurface->GetSize().height) / mSize.height) * 2.0f));
   1.761 +  mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(static_cast<SourceSurfaceD2DTarget*>(aSurface)->GetSRView());
   1.762 +  mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   1.763 +    SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
   1.764 +
   1.765 +  if (mPushedClips.size()) {
   1.766 +    mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
   1.767 +      SetFloatVector(ShaderConstantRectD3D10(aDest.x / mSize.width, aDest.y / mSize.height,
   1.768 +                                             Float(aSurface->GetSize().width) / mSize.width,
   1.769 +                                             Float(aSurface->GetSize().height) / mSize.height));
   1.770 +    mPrivateData->mEffect->GetTechniqueByName("SampleMaskedTexture")->
   1.771 +      GetPassByIndex(0)->Apply(0);
   1.772 +    // We've set the scissor rect here for the previous draw call.
   1.773 +  } else {
   1.774 +    mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
   1.775 +      GetPassByIndex(0)->Apply(0);
   1.776 +  }
   1.777 +
   1.778 +  mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
   1.779 +
   1.780 +  mDevice->Draw(4, 0);
   1.781 +}
   1.782 +
   1.783 +void
   1.784 +DrawTargetD2D::ClearRect(const Rect &aRect)
   1.785 +{
   1.786 +  MarkChanged();
   1.787 +  PushClipRect(aRect);
   1.788 +
   1.789 +  PopAllClips();
   1.790 +
   1.791 +  AutoSaveRestoreClippedOut restoreClippedOut(this);
   1.792 +
   1.793 +  D2D1_RECT_F clipRect;
   1.794 +  bool isPixelAligned;
   1.795 +  bool pushedClip = false;
   1.796 +  if (mTransform.IsRectilinear() &&
   1.797 +      GetDeviceSpaceClipRect(clipRect, isPixelAligned)) {
   1.798 +    if (mTransformDirty ||
   1.799 +        !mTransform.IsIdentity()) {
   1.800 +      mRT->SetTransform(D2D1::IdentityMatrix());
   1.801 +      mTransformDirty = true;
   1.802 +    }
   1.803 +
   1.804 +    mRT->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   1.805 +    pushedClip = true;
   1.806 +  } else {
   1.807 +    FlushTransformToRT();
   1.808 +    restoreClippedOut.Save();
   1.809 +  }
   1.810 +
   1.811 +  mRT->Clear(D2D1::ColorF(0, 0.0f));
   1.812 +
   1.813 +  if (pushedClip) {
   1.814 +    mRT->PopAxisAlignedClip();
   1.815 +  }
   1.816 +
   1.817 +  PopClip();
   1.818 +  return;
   1.819 +}
   1.820 +
   1.821 +void
   1.822 +DrawTargetD2D::CopySurface(SourceSurface *aSurface,
   1.823 +                           const IntRect &aSourceRect,
   1.824 +                           const IntPoint &aDestination)
   1.825 +{
   1.826 +  MarkChanged();
   1.827 +
   1.828 +  Rect srcRect(Float(aSourceRect.x), Float(aSourceRect.y),
   1.829 +               Float(aSourceRect.width), Float(aSourceRect.height));
   1.830 +  Rect dstRect(Float(aDestination.x), Float(aDestination.y),
   1.831 +               Float(aSourceRect.width), Float(aSourceRect.height));
   1.832 +
   1.833 +  mRT->SetTransform(D2D1::IdentityMatrix());
   1.834 +  mTransformDirty = true;
   1.835 +  mRT->PushAxisAlignedClip(D2DRect(dstRect), D2D1_ANTIALIAS_MODE_ALIASED);
   1.836 +  mRT->Clear(D2D1::ColorF(0, 0.0f));
   1.837 +  mRT->PopAxisAlignedClip();
   1.838 +
   1.839 +  RefPtr<ID2D1Bitmap> bitmap = GetBitmapForSurface(aSurface, srcRect);
   1.840 +  if (!bitmap) {
   1.841 +    return;
   1.842 +  }
   1.843 +
   1.844 +  if (aSurface->GetFormat() == SurfaceFormat::A8) {
   1.845 +    RefPtr<ID2D1SolidColorBrush> brush;
   1.846 +    mRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
   1.847 +                               D2D1::BrushProperties(), byRef(brush));
   1.848 +    mRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   1.849 +    mRT->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
   1.850 +  } else {
   1.851 +    mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f,
   1.852 +            D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
   1.853 +            D2DRect(srcRect));
   1.854 +  }
   1.855 +}
   1.856 +
   1.857 +void
   1.858 +DrawTargetD2D::FillRect(const Rect &aRect,
   1.859 +                        const Pattern &aPattern,
   1.860 +                        const DrawOptions &aOptions)
   1.861 +{
   1.862 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   1.863 +
   1.864 +  PrepareForDrawing(rt);
   1.865 +
   1.866 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.867 +
   1.868 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.869 +
   1.870 +  if (brush) {
   1.871 +    rt->FillRectangle(D2DRect(aRect), brush);
   1.872 +  }
   1.873 +
   1.874 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, aRect);
   1.875 +}
   1.876 +
   1.877 +void
   1.878 +DrawTargetD2D::StrokeRect(const Rect &aRect,
   1.879 +                          const Pattern &aPattern,
   1.880 +                          const StrokeOptions &aStrokeOptions,
   1.881 +                          const DrawOptions &aOptions)
   1.882 +{
   1.883 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   1.884 +
   1.885 +  PrepareForDrawing(rt);
   1.886 +
   1.887 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.888 +
   1.889 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.890 +
   1.891 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.892 +
   1.893 +  if (brush && strokeStyle) {
   1.894 +    rt->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.895 +  }
   1.896 +
   1.897 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, aRect);
   1.898 +}
   1.899 +
   1.900 +void
   1.901 +DrawTargetD2D::StrokeLine(const Point &aStart,
   1.902 +                          const Point &aEnd,
   1.903 +                          const Pattern &aPattern,
   1.904 +                          const StrokeOptions &aStrokeOptions,
   1.905 +                          const DrawOptions &aOptions)
   1.906 +{
   1.907 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   1.908 +
   1.909 +  PrepareForDrawing(rt);
   1.910 +
   1.911 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.912 +
   1.913 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.914 +
   1.915 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.916 +
   1.917 +  if (brush && strokeStyle) {
   1.918 +    rt->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.919 +  }
   1.920 +
   1.921 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, Float(mSize.width), Float(mSize.height)));
   1.922 +}
   1.923 +
   1.924 +void
   1.925 +DrawTargetD2D::Stroke(const Path *aPath,
   1.926 +                      const Pattern &aPattern,
   1.927 +                      const StrokeOptions &aStrokeOptions,
   1.928 +                      const DrawOptions &aOptions)
   1.929 +{
   1.930 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   1.931 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   1.932 +    return;
   1.933 +  }
   1.934 +
   1.935 +  const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   1.936 +
   1.937 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   1.938 +
   1.939 +  PrepareForDrawing(rt);
   1.940 +
   1.941 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.942 +
   1.943 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.944 +
   1.945 +  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   1.946 +
   1.947 +  if (brush && strokeStyle) {
   1.948 +    rt->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle);
   1.949 +  }
   1.950 +
   1.951 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, Float(mSize.width), Float(mSize.height)));
   1.952 +}
   1.953 +
   1.954 +void
   1.955 +DrawTargetD2D::Fill(const Path *aPath,
   1.956 +                    const Pattern &aPattern,
   1.957 +                    const DrawOptions &aOptions)
   1.958 +{
   1.959 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   1.960 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   1.961 +    return;
   1.962 +  }
   1.963 +
   1.964 +  const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   1.965 +
   1.966 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   1.967 +
   1.968 +  PrepareForDrawing(rt);
   1.969 +
   1.970 +  rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   1.971 +
   1.972 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   1.973 +
   1.974 +  if (brush) {
   1.975 +    rt->FillGeometry(d2dPath->mGeometry, brush);
   1.976 +  }
   1.977 +
   1.978 +  Rect bounds;
   1.979 +  if (aOptions.mCompositionOp != CompositionOp::OP_OVER) {
   1.980 +    D2D1_RECT_F d2dbounds;
   1.981 +    d2dPath->mGeometry->GetBounds(D2D1::IdentityMatrix(), &d2dbounds);
   1.982 +    bounds = ToRect(d2dbounds);
   1.983 +  }
   1.984 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, bounds);
   1.985 +}
   1.986 +
   1.987 +void
   1.988 +DrawTargetD2D::FillGlyphs(ScaledFont *aFont,
   1.989 +                          const GlyphBuffer &aBuffer,
   1.990 +                          const Pattern &aPattern,
   1.991 +                          const DrawOptions &aOptions,
   1.992 +                          const GlyphRenderingOptions* aRenderOptions)
   1.993 +{
   1.994 +  if (aFont->GetType() != FontType::DWRITE) {
   1.995 +    gfxDebug() << *this << ": Ignoring drawing call for incompatible font.";
   1.996 +    return;
   1.997 +  }
   1.998 +
   1.999 +  ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont);
  1.1000 +
  1.1001 +  IDWriteRenderingParams *params = nullptr;
  1.1002 +  if (aRenderOptions) {
  1.1003 +    if (aRenderOptions->GetType() != FontType::DWRITE) {
  1.1004 +      gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions.";
  1.1005 +      // This should never happen.
  1.1006 +      MOZ_ASSERT(false);
  1.1007 +    } else {
  1.1008 +      params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderOptions)->mParams;
  1.1009 +    }
  1.1010 +  }
  1.1011 +
  1.1012 +  AntialiasMode aaMode = font->GetDefaultAAMode();
  1.1013 +
  1.1014 +  if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
  1.1015 +    aaMode = aOptions.mAntialiasMode;
  1.1016 +  }
  1.1017 +
  1.1018 +  if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA &&
  1.1019 +      aOptions.mCompositionOp == CompositionOp::OP_OVER && aPattern.GetType() == PatternType::COLOR &&
  1.1020 +      aaMode == AntialiasMode::SUBPIXEL) {
  1.1021 +    if (FillGlyphsManual(font, aBuffer,
  1.1022 +                         static_cast<const ColorPattern*>(&aPattern)->mColor,
  1.1023 +                         params, aOptions)) {
  1.1024 +      return;
  1.1025 +    }
  1.1026 +  }
  1.1027 +
  1.1028 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
  1.1029 +
  1.1030 +  PrepareForDrawing(rt);
  1.1031 +
  1.1032 +  D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
  1.1033 +
  1.1034 +  switch (aaMode) {
  1.1035 +  case AntialiasMode::NONE:
  1.1036 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
  1.1037 +    break;
  1.1038 +  case AntialiasMode::GRAY:
  1.1039 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
  1.1040 +    break;
  1.1041 +  case AntialiasMode::SUBPIXEL:
  1.1042 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
  1.1043 +    break;
  1.1044 +  default:
  1.1045 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
  1.1046 +  }
  1.1047 +
  1.1048 +  if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
  1.1049 +      mFormat != SurfaceFormat::B8G8R8X8) {
  1.1050 +    d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
  1.1051 +  }
  1.1052 +
  1.1053 +  rt->SetTextAntialiasMode(d2dAAMode);
  1.1054 +
  1.1055 +  if (rt != mRT || params != mTextRenderingParams) {
  1.1056 +    rt->SetTextRenderingParams(params);
  1.1057 +    if (rt == mRT) {
  1.1058 +      mTextRenderingParams = params;
  1.1059 +    }
  1.1060 +  }
  1.1061 +
  1.1062 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
  1.1063 +
  1.1064 +  AutoDWriteGlyphRun autoRun;
  1.1065 +  DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
  1.1066 +
  1.1067 +  if (brush) {
  1.1068 +    rt->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
  1.1069 +  }
  1.1070 +
  1.1071 +  FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
  1.1072 +}
  1.1073 +
  1.1074 +void
  1.1075 +DrawTargetD2D::Mask(const Pattern &aSource,
  1.1076 +                    const Pattern &aMask,
  1.1077 +                    const DrawOptions &aOptions)
  1.1078 +{
  1.1079 +  ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aSource);
  1.1080 +  
  1.1081 +  PrepareForDrawing(rt);
  1.1082 +
  1.1083 +  RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
  1.1084 +  RefPtr<ID2D1Brush> maskBrush = CreateBrushForPattern(aMask, 1.0f);
  1.1085 +
  1.1086 +  RefPtr<ID2D1Layer> layer;
  1.1087 +
  1.1088 +  layer = GetCachedLayer();
  1.1089 +
  1.1090 +  rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr,
  1.1091 +                                      D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
  1.1092 +                                      D2D1::IdentityMatrix(),
  1.1093 +                                      1.0f, maskBrush),
  1.1094 +                layer);
  1.1095 +
  1.1096 +  Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height);
  1.1097 +  Matrix mat = mTransform;
  1.1098 +  mat.Invert();
  1.1099 +  
  1.1100 +  rt->FillRectangle(D2DRect(mat.TransformBounds(rect)), brush);
  1.1101 +  PopCachedLayer(rt);
  1.1102 +
  1.1103 +  FinalizeRTForOperation(aOptions.mCompositionOp, aSource, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
  1.1104 +}
  1.1105 +
  1.1106 +void
  1.1107 +DrawTargetD2D::PushClip(const Path *aPath)
  1.1108 +{
  1.1109 +  if (aPath->GetBackendType() != BackendType::DIRECT2D) {
  1.1110 +    gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
  1.1111 +    return;
  1.1112 +  }
  1.1113 +
  1.1114 +  mCurrentClipMaskTexture = nullptr;
  1.1115 +  mCurrentClippedGeometry = nullptr;
  1.1116 +
  1.1117 +  RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
  1.1118 +
  1.1119 +  PushedClip clip;
  1.1120 +  clip.mTransform = D2DMatrix(mTransform);
  1.1121 +  clip.mPath = pathD2D;
  1.1122 +  
  1.1123 +  pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
  1.1124 +  
  1.1125 +  clip.mLayer = GetCachedLayer();
  1.1126 +
  1.1127 +  mPushedClips.push_back(clip);
  1.1128 +
  1.1129 +  // The transform of clips is relative to the world matrix, since we use the total
  1.1130 +  // transform for the clips, make the world matrix identity.
  1.1131 +  mRT->SetTransform(D2D1::IdentityMatrix());
  1.1132 +  mTransformDirty = true;
  1.1133 +
  1.1134 +  if (mClipsArePushed) {
  1.1135 +    PushD2DLayer(mRT, pathD2D->mGeometry, clip.mLayer, clip.mTransform);
  1.1136 +  }
  1.1137 +}
  1.1138 +
  1.1139 +void
  1.1140 +DrawTargetD2D::PushClipRect(const Rect &aRect)
  1.1141 +{
  1.1142 +  mCurrentClipMaskTexture = nullptr;
  1.1143 +  mCurrentClippedGeometry = nullptr;
  1.1144 +  if (!mTransform.IsRectilinear()) {
  1.1145 +    // Whoops, this isn't a rectangle in device space, Direct2D will not deal
  1.1146 +    // with this transform the way we want it to.
  1.1147 +    // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
  1.1148 +
  1.1149 +    RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
  1.1150 +    pathBuilder->MoveTo(aRect.TopLeft());
  1.1151 +    pathBuilder->LineTo(aRect.TopRight());
  1.1152 +    pathBuilder->LineTo(aRect.BottomRight());
  1.1153 +    pathBuilder->LineTo(aRect.BottomLeft());
  1.1154 +    pathBuilder->Close();
  1.1155 +    RefPtr<Path> path = pathBuilder->Finish();
  1.1156 +    return PushClip(path);
  1.1157 +  }
  1.1158 +
  1.1159 +  PushedClip clip;
  1.1160 +  Rect rect = mTransform.TransformBounds(aRect);
  1.1161 +  IntRect intRect;
  1.1162 +  clip.mIsPixelAligned = rect.ToIntRect(&intRect);
  1.1163 +
  1.1164 +  // Do not store the transform, just store the device space rectangle directly.
  1.1165 +  clip.mBounds = D2DRect(rect);
  1.1166 +
  1.1167 +  mPushedClips.push_back(clip);
  1.1168 +
  1.1169 +  mRT->SetTransform(D2D1::IdentityMatrix());
  1.1170 +  mTransformDirty = true;
  1.1171 +
  1.1172 +  if (mClipsArePushed) {
  1.1173 +    mRT->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
  1.1174 +  }
  1.1175 +}
  1.1176 +
  1.1177 +void
  1.1178 +DrawTargetD2D::PopClip()
  1.1179 +{
  1.1180 +  mCurrentClipMaskTexture = nullptr;
  1.1181 +  mCurrentClippedGeometry = nullptr;
  1.1182 +  if (mClipsArePushed) {
  1.1183 +    if (mPushedClips.back().mLayer) {
  1.1184 +      PopCachedLayer(mRT);
  1.1185 +    } else {
  1.1186 +      mRT->PopAxisAlignedClip();
  1.1187 +    }
  1.1188 +  }
  1.1189 +  mPushedClips.pop_back();
  1.1190 +}
  1.1191 +
  1.1192 +TemporaryRef<SourceSurface> 
  1.1193 +DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData,
  1.1194 +                                           const IntSize &aSize,
  1.1195 +                                           int32_t aStride,
  1.1196 +                                           SurfaceFormat aFormat) const
  1.1197 +{
  1.1198 +  RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1.1199 +
  1.1200 +  if (!newSurf->InitFromData(aData, aSize, aStride, aFormat, mRT)) {
  1.1201 +    return nullptr;
  1.1202 +  }
  1.1203 +
  1.1204 +  return newSurf;
  1.1205 +}
  1.1206 +
  1.1207 +TemporaryRef<SourceSurface> 
  1.1208 +DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const
  1.1209 +{
  1.1210 +  if (aSurface->GetType() == SurfaceType::D2D1_BITMAP ||
  1.1211 +      aSurface->GetType() == SurfaceType::D2D1_DRAWTARGET) {
  1.1212 +    return aSurface;
  1.1213 +  }
  1.1214 +
  1.1215 +  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
  1.1216 +
  1.1217 +  DataSourceSurface::MappedSurface map;
  1.1218 +  if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
  1.1219 +    return nullptr;
  1.1220 +  }
  1.1221 +
  1.1222 +  RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1.1223 +  bool success = newSurf->InitFromData(map.mData, data->GetSize(), map.mStride, data->GetFormat(), mRT);
  1.1224 +
  1.1225 +  data->Unmap();
  1.1226 +
  1.1227 +  if (!success) {
  1.1228 +    return data;
  1.1229 +  }
  1.1230 +  return newSurf;
  1.1231 +}
  1.1232 +
  1.1233 +TemporaryRef<SourceSurface>
  1.1234 +DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
  1.1235 +{
  1.1236 +  if (aSurface.mType != NativeSurfaceType::D3D10_TEXTURE) {
  1.1237 +    gfxDebug() << *this << ": Failure to create source surface from non-D3D10 texture native surface.";
  1.1238 +    return nullptr;
  1.1239 +  }
  1.1240 +  RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1.1241 +
  1.1242 +  if (!newSurf->InitFromTexture(static_cast<ID3D10Texture2D*>(aSurface.mSurface),
  1.1243 +                                aSurface.mFormat,
  1.1244 +                                mRT))
  1.1245 +  {
  1.1246 +    gfxWarning() << *this << ": Failed to create SourceSurface from texture.";
  1.1247 +    return nullptr;
  1.1248 +  }
  1.1249 +
  1.1250 +  return newSurf;
  1.1251 +}
  1.1252 +
  1.1253 +TemporaryRef<DrawTarget>
  1.1254 +DrawTargetD2D::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
  1.1255 +{
  1.1256 +  RefPtr<DrawTargetD2D> newTarget =
  1.1257 +    new DrawTargetD2D();
  1.1258 +
  1.1259 +  if (!newTarget->Init(aSize, aFormat)) {
  1.1260 +    gfxDebug() << *this << ": Failed to create optimal draw target. Size: " << aSize;
  1.1261 +    return nullptr;
  1.1262 +  }
  1.1263 +
  1.1264 +  return newTarget;
  1.1265 +}
  1.1266 +
  1.1267 +TemporaryRef<PathBuilder>
  1.1268 +DrawTargetD2D::CreatePathBuilder(FillRule aFillRule) const
  1.1269 +{
  1.1270 +  RefPtr<ID2D1PathGeometry> path;
  1.1271 +  HRESULT hr = factory()->CreatePathGeometry(byRef(path));
  1.1272 +
  1.1273 +  if (FAILED(hr)) {
  1.1274 +    gfxWarning() << "Failed to create Direct2D Path Geometry. Code: " << hr;
  1.1275 +    return nullptr;
  1.1276 +  }
  1.1277 +
  1.1278 +  RefPtr<ID2D1GeometrySink> sink;
  1.1279 +  hr = path->Open(byRef(sink));
  1.1280 +  if (FAILED(hr)) {
  1.1281 +    gfxWarning() << "Failed to access Direct2D Path Geometry. Code: " << hr;
  1.1282 +    return nullptr;
  1.1283 +  }
  1.1284 +
  1.1285 +  if (aFillRule == FillRule::FILL_WINDING) {
  1.1286 +    sink->SetFillMode(D2D1_FILL_MODE_WINDING);
  1.1287 +  }
  1.1288 +
  1.1289 +  return new PathBuilderD2D(sink, path, aFillRule);
  1.1290 +}
  1.1291 +
  1.1292 +TemporaryRef<GradientStops>
  1.1293 +DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
  1.1294 +{
  1.1295 +  D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
  1.1296 +
  1.1297 +  for (uint32_t i = 0; i < aNumStops; i++) {
  1.1298 +    stops[i].position = rawStops[i].offset;
  1.1299 +    stops[i].color = D2DColor(rawStops[i].color);
  1.1300 +  }
  1.1301 +
  1.1302 +  RefPtr<ID2D1GradientStopCollection> stopCollection;
  1.1303 +
  1.1304 +  HRESULT hr =
  1.1305 +    mRT->CreateGradientStopCollection(stops, aNumStops,
  1.1306 +                                      D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
  1.1307 +                                      byRef(stopCollection));
  1.1308 +  delete [] stops;
  1.1309 +
  1.1310 +  if (FAILED(hr)) {
  1.1311 +    gfxWarning() << "Failed to create GradientStopCollection. Code: " << hr;
  1.1312 +    return nullptr;
  1.1313 +  }
  1.1314 +
  1.1315 +  return new GradientStopsD2D(stopCollection);
  1.1316 +}
  1.1317 +
  1.1318 +TemporaryRef<FilterNode>
  1.1319 +DrawTargetD2D::CreateFilter(FilterType aType)
  1.1320 +{
  1.1321 +#ifdef USE_D2D1_1
  1.1322 +  RefPtr<ID2D1DeviceContext> dc;
  1.1323 +  HRESULT hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc));
  1.1324 +
  1.1325 +  if (SUCCEEDED(hr)) {
  1.1326 +    return FilterNodeD2D1::Create(this, dc, aType);
  1.1327 +  }
  1.1328 +#endif
  1.1329 +  return FilterNodeSoftware::Create(aType);
  1.1330 +}
  1.1331 +
  1.1332 +void*
  1.1333 +DrawTargetD2D::GetNativeSurface(NativeSurfaceType aType)
  1.1334 +{
  1.1335 +  if (aType != NativeSurfaceType::D3D10_TEXTURE) {
  1.1336 +    return nullptr;
  1.1337 +  }
  1.1338 +
  1.1339 +  return mTexture;
  1.1340 +}
  1.1341 +
  1.1342 +/*
  1.1343 + * Public functions
  1.1344 + */
  1.1345 +bool
  1.1346 +DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat)
  1.1347 +{
  1.1348 +  HRESULT hr;
  1.1349 +
  1.1350 +  mSize = aSize;
  1.1351 +  mFormat = aFormat;
  1.1352 +
  1.1353 +  if (!Factory::GetDirect3D10Device()) {
  1.1354 +    gfxDebug() << "Failed to Init Direct2D DrawTarget (No D3D10 Device set.)";
  1.1355 +    return false;
  1.1356 +  }
  1.1357 +  mDevice = Factory::GetDirect3D10Device();
  1.1358 +
  1.1359 +  CD3D10_TEXTURE2D_DESC desc(DXGIFormat(aFormat),
  1.1360 +                             mSize.width,
  1.1361 +                             mSize.height,
  1.1362 +                             1, 1);
  1.1363 +  desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1.1364 +
  1.1365 +  hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture));
  1.1366 +
  1.1367 +  if (FAILED(hr)) {
  1.1368 +    gfxDebug() << "Failed to init Direct2D DrawTarget. Size: " << mSize << " Code: " << hr;
  1.1369 +    return false;
  1.1370 +  }
  1.1371 +
  1.1372 +  if (!InitD2DRenderTarget()) {
  1.1373 +    return false;
  1.1374 +  }
  1.1375 +
  1.1376 +  mRT->Clear(D2D1::ColorF(0, 0));
  1.1377 +  return true;
  1.1378 +}
  1.1379 +
  1.1380 +bool
  1.1381 +DrawTargetD2D::Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
  1.1382 +{
  1.1383 +  HRESULT hr;
  1.1384 +
  1.1385 +  mTexture = aTexture;
  1.1386 +  mFormat = aFormat;
  1.1387 +
  1.1388 +  if (!mTexture) {
  1.1389 +    gfxDebug() << "No valid texture for Direct2D draw target initialization.";
  1.1390 +    return false;
  1.1391 +  }
  1.1392 +
  1.1393 +  RefPtr<ID3D10Device> device;
  1.1394 +  mTexture->GetDevice(byRef(device));
  1.1395 +
  1.1396 +  hr = device->QueryInterface((ID3D10Device1**)byRef(mDevice));
  1.1397 +
  1.1398 +  if (FAILED(hr)) {
  1.1399 +    gfxWarning() << "Failed to get D3D10 device from texture.";
  1.1400 +    return false;
  1.1401 +  }
  1.1402 +
  1.1403 +  D3D10_TEXTURE2D_DESC desc;
  1.1404 +  mTexture->GetDesc(&desc);
  1.1405 +  mSize.width = desc.Width;
  1.1406 +  mSize.height = desc.Height;
  1.1407 +
  1.1408 +  return InitD2DRenderTarget();
  1.1409 +}
  1.1410 +
  1.1411 +// {0D398B49-AE7B-416F-B26D-EA3C137D1CF7}
  1.1412 +static const GUID sPrivateDataD2D = 
  1.1413 +{ 0xd398b49, 0xae7b, 0x416f, { 0xb2, 0x6d, 0xea, 0x3c, 0x13, 0x7d, 0x1c, 0xf7 } };
  1.1414 +
  1.1415 +bool
  1.1416 +DrawTargetD2D::InitD3D10Data()
  1.1417 +{
  1.1418 +  HRESULT hr;
  1.1419 +  
  1.1420 +  UINT privateDataSize;
  1.1421 +  privateDataSize = sizeof(mPrivateData);
  1.1422 +  hr = mDevice->GetPrivateData(sPrivateDataD2D, &privateDataSize, &mPrivateData);
  1.1423 +
  1.1424 +  if (SUCCEEDED(hr)) {
  1.1425 +      return true;
  1.1426 +  }
  1.1427 +
  1.1428 +  mPrivateData = new PrivateD3D10DataD2D;
  1.1429 +
  1.1430 +  decltype(D3D10CreateEffectFromMemory)* createD3DEffect;
  1.1431 +  HMODULE d3dModule = LoadLibraryW(L"d3d10_1.dll");
  1.1432 +  createD3DEffect = (decltype(D3D10CreateEffectFromMemory)*)
  1.1433 +      GetProcAddress(d3dModule, "D3D10CreateEffectFromMemory");
  1.1434 +
  1.1435 +  hr = createD3DEffect((void*)d2deffect, sizeof(d2deffect), 0, mDevice, nullptr, byRef(mPrivateData->mEffect));
  1.1436 +
  1.1437 +  if (FAILED(hr)) {
  1.1438 +    gfxWarning() << "Failed to initialize Direct2D required effects. Code: " << hr;
  1.1439 +    return false;
  1.1440 +  }
  1.1441 +
  1.1442 +  privateDataSize = sizeof(mPrivateData);
  1.1443 +  mDevice->SetPrivateData(sPrivateDataD2D, privateDataSize, &mPrivateData);
  1.1444 +
  1.1445 +  D3D10_INPUT_ELEMENT_DESC layout[] =
  1.1446 +  {
  1.1447 +    { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
  1.1448 +  };
  1.1449 +  D3D10_PASS_DESC passDesc;
  1.1450 +  
  1.1451 +  mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->GetDesc(&passDesc);
  1.1452 +
  1.1453 +  hr = mDevice->CreateInputLayout(layout,
  1.1454 +                                  sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC),
  1.1455 +                                  passDesc.pIAInputSignature,
  1.1456 +                                  passDesc.IAInputSignatureSize,
  1.1457 +                                  byRef(mPrivateData->mInputLayout));
  1.1458 +
  1.1459 +  if (FAILED(hr)) {
  1.1460 +    gfxWarning() << "Failed to initialize Direct2D required InputLayout. Code: " << hr;
  1.1461 +    return false;
  1.1462 +  }
  1.1463 +
  1.1464 +  D3D10_SUBRESOURCE_DATA data;
  1.1465 +  Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
  1.1466 +  data.pSysMem = vertices;
  1.1467 +  CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
  1.1468 +
  1.1469 +  hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mPrivateData->mVB));
  1.1470 +
  1.1471 +  if (FAILED(hr)) {
  1.1472 +    gfxWarning() << "Failed to initialize Direct2D required VertexBuffer. Code: " << hr;
  1.1473 +    return false;
  1.1474 +  }
  1.1475 +
  1.1476 +  return true;
  1.1477 +}
  1.1478 +
  1.1479 +/*
  1.1480 + * Private helpers
  1.1481 + */
  1.1482 +uint32_t
  1.1483 +DrawTargetD2D::GetByteSize() const
  1.1484 +{
  1.1485 +  return mSize.width * mSize.height * BytesPerPixel(mFormat);
  1.1486 +}
  1.1487 +
  1.1488 +TemporaryRef<ID2D1Layer>
  1.1489 +DrawTargetD2D::GetCachedLayer()
  1.1490 +{
  1.1491 +  RefPtr<ID2D1Layer> layer;
  1.1492 +
  1.1493 +  if (mCurrentCachedLayer < 5) {
  1.1494 +    if (!mCachedLayers[mCurrentCachedLayer]) {
  1.1495 +      mRT->CreateLayer(byRef(mCachedLayers[mCurrentCachedLayer]));
  1.1496 +      mVRAMUsageDT += GetByteSize();
  1.1497 +    }
  1.1498 +    layer = mCachedLayers[mCurrentCachedLayer];
  1.1499 +  } else {
  1.1500 +    mRT->CreateLayer(byRef(layer));
  1.1501 +  }
  1.1502 +
  1.1503 +  mCurrentCachedLayer++;
  1.1504 +  return layer;
  1.1505 +}
  1.1506 +
  1.1507 +void
  1.1508 +DrawTargetD2D::PopCachedLayer(ID2D1RenderTarget *aRT)
  1.1509 +{
  1.1510 +  aRT->PopLayer();
  1.1511 +  mCurrentCachedLayer--;
  1.1512 +}
  1.1513 +
  1.1514 +bool
  1.1515 +DrawTargetD2D::InitD2DRenderTarget()
  1.1516 +{
  1.1517 +  if (!factory()) {
  1.1518 +    return false;
  1.1519 +  }
  1.1520 +
  1.1521 +  mRT = CreateRTForTexture(mTexture, mFormat);
  1.1522 +
  1.1523 +  if (!mRT) {
  1.1524 +    return false;
  1.1525 +  }
  1.1526 +
  1.1527 +  mRT->BeginDraw();
  1.1528 +
  1.1529 +  if (mFormat == SurfaceFormat::B8G8R8X8) {
  1.1530 +    mRT->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
  1.1531 +  }
  1.1532 +
  1.1533 +  mVRAMUsageDT += GetByteSize();
  1.1534 +
  1.1535 +  return InitD3D10Data();
  1.1536 +}
  1.1537 +
  1.1538 +void
  1.1539 +DrawTargetD2D::PrepareForDrawing(ID2D1RenderTarget *aRT)
  1.1540 +{
  1.1541 +  if (!mClipsArePushed || aRT == mTempRT) {
  1.1542 +    if (mPushedClips.size()) {
  1.1543 +      // The transform of clips is relative to the world matrix, since we use the total
  1.1544 +      // transform for the clips, make the world matrix identity.
  1.1545 +      aRT->SetTransform(D2D1::IdentityMatrix());
  1.1546 +      if (aRT == mRT) {
  1.1547 +        mTransformDirty = true;
  1.1548 +        mClipsArePushed = true;
  1.1549 +      }
  1.1550 +      PushClipsToRT(aRT);
  1.1551 +    }
  1.1552 +  }
  1.1553 +  FlushTransformToRT();
  1.1554 +  MarkChanged();
  1.1555 +
  1.1556 +  if (aRT == mTempRT) {
  1.1557 +    mTempRT->SetTransform(D2DMatrix(mTransform));
  1.1558 +  }
  1.1559 +}
  1.1560 +
  1.1561 +void
  1.1562 +DrawTargetD2D::MarkChanged()
  1.1563 +{
  1.1564 +  if (mSnapshot) {
  1.1565 +    if (mSnapshot->hasOneRef()) {
  1.1566 +      // Just destroy it, since no-one else knows about it.
  1.1567 +      mSnapshot = nullptr;
  1.1568 +    } else {
  1.1569 +      mSnapshot->DrawTargetWillChange();
  1.1570 +      // The snapshot will no longer depend on this target.
  1.1571 +      MOZ_ASSERT(!mSnapshot);
  1.1572 +    }
  1.1573 +  }
  1.1574 +  if (mDependentTargets.size()) {
  1.1575 +    // Copy mDependentTargets since the Flush()es below will modify it.
  1.1576 +    TargetSet tmpTargets = mDependentTargets;
  1.1577 +    for (TargetSet::iterator iter = tmpTargets.begin();
  1.1578 +         iter != tmpTargets.end(); iter++) {
  1.1579 +      (*iter)->Flush();
  1.1580 +    }
  1.1581 +    // The Flush() should have broken all dependencies on this target.
  1.1582 +    MOZ_ASSERT(!mDependentTargets.size());
  1.1583 +  }
  1.1584 +}
  1.1585 +
  1.1586 +ID3D10BlendState*
  1.1587 +DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator)
  1.1588 +{
  1.1589 +  size_t operatorIndex = static_cast<size_t>(aOperator);
  1.1590 +  if (mPrivateData->mBlendStates[operatorIndex]) {
  1.1591 +    return mPrivateData->mBlendStates[operatorIndex];
  1.1592 +  }
  1.1593 +
  1.1594 +  D3D10_BLEND_DESC desc;
  1.1595 +
  1.1596 +  memset(&desc, 0, sizeof(D3D10_BLEND_DESC));
  1.1597 +
  1.1598 +  desc.AlphaToCoverageEnable = FALSE;
  1.1599 +  desc.BlendEnable[0] = TRUE;
  1.1600 +  desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
  1.1601 +  desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
  1.1602 +
  1.1603 +  switch (aOperator) {
  1.1604 +  case CompositionOp::OP_ADD:
  1.1605 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1.1606 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
  1.1607 +    break;
  1.1608 +  case CompositionOp::OP_IN:
  1.1609 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
  1.1610 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1.1611 +    break;
  1.1612 +  case CompositionOp::OP_OUT:
  1.1613 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1.1614 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1.1615 +    break;
  1.1616 +  case CompositionOp::OP_ATOP:
  1.1617 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
  1.1618 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1.1619 +    break;
  1.1620 +  case CompositionOp::OP_DEST_IN:
  1.1621 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
  1.1622 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
  1.1623 +    break;
  1.1624 +  case CompositionOp::OP_DEST_OUT:
  1.1625 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
  1.1626 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1.1627 +    break;
  1.1628 +  case CompositionOp::OP_DEST_ATOP:
  1.1629 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1.1630 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
  1.1631 +    break;
  1.1632 +  case CompositionOp::OP_DEST_OVER:
  1.1633 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1.1634 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
  1.1635 +    break;
  1.1636 +  case CompositionOp::OP_XOR:
  1.1637 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1.1638 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1.1639 +    break;
  1.1640 +  case CompositionOp::OP_SOURCE:
  1.1641 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1.1642 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1.1643 +    break;
  1.1644 +  default:
  1.1645 +    desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1.1646 +    desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1.1647 +  }
  1.1648 +  
  1.1649 +  mDevice->CreateBlendState(&desc, byRef(mPrivateData->mBlendStates[operatorIndex]));
  1.1650 +
  1.1651 +  return mPrivateData->mBlendStates[operatorIndex];
  1.1652 +}
  1.1653 +
  1.1654 +/* This function prepares the temporary RT for drawing and returns it when a
  1.1655 + * drawing operation other than OVER is required.
  1.1656 + */
  1.1657 +ID2D1RenderTarget*
  1.1658 +DrawTargetD2D::GetRTForOperation(CompositionOp aOperator, const Pattern &aPattern)
  1.1659 +{
  1.1660 +  if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
  1.1661 +    return mRT;
  1.1662 +  }
  1.1663 +
  1.1664 +  PopAllClips();
  1.1665 +
  1.1666 +  if (aOperator > CompositionOp::OP_XOR) {
  1.1667 +    mRT->Flush();
  1.1668 +  }
  1.1669 +
  1.1670 +  if (mTempRT) {
  1.1671 +    mTempRT->Clear(D2D1::ColorF(0, 0));
  1.1672 +    return mTempRT;
  1.1673 +  }
  1.1674 +
  1.1675 +  EnsureViews();
  1.1676 +
  1.1677 +  if (!mRTView || !mSRView) {
  1.1678 +    gfxDebug() << *this << ": Failed to get required views. Defaulting to CompositionOp::OP_OVER.";
  1.1679 +    return mRT;
  1.1680 +  }
  1.1681 +
  1.1682 +  mTempRT = CreateRTForTexture(mTempTexture, SurfaceFormat::B8G8R8A8);
  1.1683 +
  1.1684 +  if (!mTempRT) {
  1.1685 +    return mRT;
  1.1686 +  }
  1.1687 +
  1.1688 +  mVRAMUsageDT += GetByteSize();
  1.1689 +
  1.1690 +  mTempRT->BeginDraw();
  1.1691 +
  1.1692 +  mTempRT->Clear(D2D1::ColorF(0, 0));
  1.1693 +
  1.1694 +  return mTempRT;
  1.1695 +}
  1.1696 +
  1.1697 +/* This function blends back the content of a drawing operation (drawn to an
  1.1698 + * empty surface with OVER, so the surface now contains the source operation
  1.1699 + * contents) to the rendertarget using the requested composition operation.
  1.1700 + * In order to respect clip for operations which are unbound by their mask,
  1.1701 + * the old content of the surface outside the clipped area may be blended back
  1.1702 + * to the surface.
  1.1703 + */
  1.1704 +void
  1.1705 +DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aPattern, const Rect &aBounds)
  1.1706 +{
  1.1707 +  if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
  1.1708 +    return;
  1.1709 +  }
  1.1710 +
  1.1711 +  if (!mTempRT) {
  1.1712 +    return;
  1.1713 +  }
  1.1714 +
  1.1715 +  PopClipsFromRT(mTempRT);
  1.1716 +
  1.1717 +  mRT->Flush();
  1.1718 +  mTempRT->Flush();
  1.1719 +
  1.1720 +  AutoSaveRestoreClippedOut restoreClippedOut(this);
  1.1721 +
  1.1722 +  bool needsWriteBack =
  1.1723 +    !IsOperatorBoundByMask(aOperator) && mPushedClips.size();
  1.1724 +
  1.1725 +  if (needsWriteBack) {
  1.1726 +    restoreClippedOut.Save();
  1.1727 +  }
  1.1728 +
  1.1729 +  ID3D10RenderTargetView *rtViews = mRTView;
  1.1730 +  mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
  1.1731 +
  1.1732 +  UINT stride = sizeof(Vertex);
  1.1733 +  UINT offset = 0;
  1.1734 +  ID3D10Buffer *buff = mPrivateData->mVB;
  1.1735 +
  1.1736 +  mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  1.1737 +  mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
  1.1738 +  mDevice->IASetInputLayout(mPrivateData->mInputLayout);
  1.1739 +
  1.1740 +  D3D10_VIEWPORT viewport;
  1.1741 +  viewport.MaxDepth = 1;
  1.1742 +  viewport.MinDepth = 0;
  1.1743 +  viewport.Height = mSize.height;
  1.1744 +  viewport.Width = mSize.width;
  1.1745 +  viewport.TopLeftX = 0;
  1.1746 +  viewport.TopLeftY = 0;
  1.1747 +
  1.1748 +  RefPtr<ID3D10Texture2D> tmpTexture;
  1.1749 +  RefPtr<ID3D10ShaderResourceView> mBckSRView;
  1.1750 +
  1.1751 +  mDevice->RSSetViewports(1, &viewport);
  1.1752 +  mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
  1.1753 +    SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f));
  1.1754 +
  1.1755 +  if (IsPatternSupportedByD2D(aPattern)) {
  1.1756 +    mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
  1.1757 +      SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  1.1758 +    mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(mSRView);
  1.1759 +
  1.1760 +    // Handle the case where we blend with the backdrop
  1.1761 +    if (aOperator > CompositionOp::OP_XOR) {
  1.1762 +      IntSize size = mSize;
  1.1763 +      SurfaceFormat format = mFormat;
  1.1764 +
  1.1765 +      CD3D10_TEXTURE2D_DESC desc(DXGIFormat(format), size.width, size.height, 1, 1);
  1.1766 +      desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1.1767 +
  1.1768 +      HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpTexture));
  1.1769 +      if (FAILED(hr)) {
  1.1770 +        gfxWarning() << "Failed to create temporary texture to hold surface data.";
  1.1771 +        return;
  1.1772 +      }
  1.1773 +
  1.1774 +      mDevice->CopyResource(tmpTexture, mTexture);
  1.1775 +      if (FAILED(hr)) {
  1.1776 +        gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  1.1777 +        return;
  1.1778 +      }
  1.1779 +
  1.1780 +      DrawTargetD2D::Flush();
  1.1781 +
  1.1782 +      hr = mDevice->CreateShaderResourceView(tmpTexture, nullptr, byRef(mBckSRView));
  1.1783 +
  1.1784 +      if (FAILED(hr)) {
  1.1785 +        gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  1.1786 +        return;
  1.1787 +      }
  1.1788 +
  1.1789 +      unsigned int compop = (unsigned int)aOperator - (unsigned int)CompositionOp::OP_XOR;
  1.1790 +      mPrivateData->mEffect->GetVariableByName("bcktex")->AsShaderResource()->SetResource(mBckSRView);
  1.1791 +      mPrivateData->mEffect->GetVariableByName("blendop")->AsScalar()->SetInt(compop);
  1.1792 +
  1.1793 +      if (aOperator > CompositionOp::OP_EXCLUSION)
  1.1794 +        mPrivateData->mEffect->GetTechniqueByName("SampleTextureForNonSeparableBlending")->
  1.1795 +          GetPassByIndex(0)->Apply(0);
  1.1796 +      else if (aOperator > CompositionOp::OP_COLOR_DODGE)
  1.1797 +        mPrivateData->mEffect->GetTechniqueByName("SampleTextureForSeparableBlending_2")->
  1.1798 +          GetPassByIndex(0)->Apply(0);
  1.1799 +      else
  1.1800 +        mPrivateData->mEffect->GetTechniqueByName("SampleTextureForSeparableBlending_1")->
  1.1801 +          GetPassByIndex(0)->Apply(0);
  1.1802 +    }
  1.1803 +    else {
  1.1804 +      mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->Apply(0);
  1.1805 +    }
  1.1806 +
  1.1807 +  } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
  1.1808 +    const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
  1.1809 +
  1.1810 +    if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
  1.1811 +      // Draw nothing!
  1.1812 +      return;
  1.1813 +    }
  1.1814 +
  1.1815 +    mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(mSRView);
  1.1816 +
  1.1817 +    SetupEffectForRadialGradient(pat);
  1.1818 +  }
  1.1819 +
  1.1820 +  mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
  1.1821 +  
  1.1822 +  SetScissorToRect(nullptr);
  1.1823 +  mDevice->Draw(4, 0);
  1.1824 +}
  1.1825 +
  1.1826 +static D2D1_RECT_F
  1.1827 +IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
  1.1828 +{
  1.1829 +  D2D1_RECT_F result;
  1.1830 +  result.left = max(aRect1.left, aRect2.left);
  1.1831 +  result.top = max(aRect1.top, aRect2.top);
  1.1832 +  result.right = min(aRect1.right, aRect2.right);
  1.1833 +  result.bottom = min(aRect1.bottom, aRect2.bottom);
  1.1834 +
  1.1835 +  result.right = max(result.right, result.left);
  1.1836 +  result.bottom = max(result.bottom, result.top);
  1.1837 +
  1.1838 +  return result;
  1.1839 +}
  1.1840 +
  1.1841 +bool
  1.1842 +DrawTargetD2D::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned)
  1.1843 +{
  1.1844 +  if (!mPushedClips.size()) {
  1.1845 +    return false;
  1.1846 +  }
  1.1847 +
  1.1848 +  std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
  1.1849 +  if (iter->mPath) {
  1.1850 +    return false;
  1.1851 +  }
  1.1852 +  aClipRect = iter->mBounds;
  1.1853 +  aIsPixelAligned = iter->mIsPixelAligned;
  1.1854 +
  1.1855 +  iter++;
  1.1856 +  for (;iter != mPushedClips.end(); iter++) {
  1.1857 +    if (iter->mPath) {
  1.1858 +      return false;
  1.1859 +    }
  1.1860 +    aClipRect = IntersectRect(aClipRect, iter->mBounds);
  1.1861 +    if (!iter->mIsPixelAligned) {
  1.1862 +      aIsPixelAligned = false;
  1.1863 +    }
  1.1864 +  }
  1.1865 +  return true;
  1.1866 +}
  1.1867 +
  1.1868 +TemporaryRef<ID2D1Geometry>
  1.1869 +DrawTargetD2D::GetClippedGeometry(IntRect *aClipBounds)
  1.1870 +{
  1.1871 +  if (mCurrentClippedGeometry) {
  1.1872 +    *aClipBounds = mCurrentClipBounds;
  1.1873 +    return mCurrentClippedGeometry;
  1.1874 +  }
  1.1875 +
  1.1876 +  mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
  1.1877 +
  1.1878 +  // if pathGeom is null then pathRect represents the path.
  1.1879 +  RefPtr<ID2D1Geometry> pathGeom;
  1.1880 +  D2D1_RECT_F pathRect;
  1.1881 +  bool pathRectIsAxisAligned = false;
  1.1882 +  std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
  1.1883 +  
  1.1884 +  if (iter->mPath) {
  1.1885 +    pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
  1.1886 +  } else {
  1.1887 +    pathRect = iter->mBounds;
  1.1888 +    pathRectIsAxisAligned = iter->mIsPixelAligned;
  1.1889 +  }
  1.1890 +
  1.1891 +  iter++;
  1.1892 +  for (;iter != mPushedClips.end(); iter++) {
  1.1893 +    // Do nothing but add it to the current clip bounds.
  1.1894 +    if (!iter->mPath && iter->mIsPixelAligned) {
  1.1895 +      mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
  1.1896 +        IntRect(int32_t(iter->mBounds.left), int32_t(iter->mBounds.top),
  1.1897 +                int32_t(iter->mBounds.right - iter->mBounds.left),
  1.1898 +                int32_t(iter->mBounds.bottom - iter->mBounds.top)));
  1.1899 +      continue;
  1.1900 +    }
  1.1901 +
  1.1902 +    if (!pathGeom) {
  1.1903 +      if (pathRectIsAxisAligned) {
  1.1904 +        mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
  1.1905 +          IntRect(int32_t(pathRect.left), int32_t(pathRect.top),
  1.1906 +                  int32_t(pathRect.right - pathRect.left),
  1.1907 +                  int32_t(pathRect.bottom - pathRect.top)));
  1.1908 +      }
  1.1909 +      if (iter->mPath) {
  1.1910 +        // See if pathRect needs to go into the path geometry.
  1.1911 +        if (!pathRectIsAxisAligned) {
  1.1912 +          pathGeom = ConvertRectToGeometry(pathRect);
  1.1913 +        } else {
  1.1914 +          pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
  1.1915 +        }
  1.1916 +      } else {
  1.1917 +        pathRect = IntersectRect(pathRect, iter->mBounds);
  1.1918 +        pathRectIsAxisAligned = false;
  1.1919 +        continue;
  1.1920 +      }
  1.1921 +    }
  1.1922 +
  1.1923 +    RefPtr<ID2D1PathGeometry> newGeom;
  1.1924 +    factory()->CreatePathGeometry(byRef(newGeom));
  1.1925 +
  1.1926 +    RefPtr<ID2D1GeometrySink> currentSink;
  1.1927 +    newGeom->Open(byRef(currentSink));
  1.1928 +
  1.1929 +    if (iter->mPath) {
  1.1930 +      pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
  1.1931 +                                    iter->mTransform, currentSink);
  1.1932 +    } else {
  1.1933 +      RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
  1.1934 +      pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
  1.1935 +                                    D2D1::IdentityMatrix(), currentSink);
  1.1936 +    }
  1.1937 +
  1.1938 +    currentSink->Close();
  1.1939 +
  1.1940 +    pathGeom = newGeom.forget();
  1.1941 +  }
  1.1942 +
  1.1943 +  // For now we need mCurrentClippedGeometry to always be non-nullptr. This
  1.1944 +  // method might seem a little strange but it is just fine, if pathGeom is
  1.1945 +  // nullptr pathRect will always still contain 1 clip unaccounted for
  1.1946 +  // regardless of mCurrentClipBounds.
  1.1947 +  if (!pathGeom) {
  1.1948 +    pathGeom = ConvertRectToGeometry(pathRect);
  1.1949 +  }
  1.1950 +  mCurrentClippedGeometry = pathGeom.forget();
  1.1951 +  *aClipBounds = mCurrentClipBounds;
  1.1952 +  return mCurrentClippedGeometry;
  1.1953 +}
  1.1954 +
  1.1955 +TemporaryRef<ID2D1RenderTarget>
  1.1956 +DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
  1.1957 +{
  1.1958 +  HRESULT hr;
  1.1959 +
  1.1960 +  RefPtr<IDXGISurface> surface;
  1.1961 +  RefPtr<ID2D1RenderTarget> rt;
  1.1962 +
  1.1963 +  hr = aTexture->QueryInterface((IDXGISurface**)byRef(surface));
  1.1964 +
  1.1965 +  if (FAILED(hr)) {
  1.1966 +    gfxWarning() << "Failed to QI texture to surface.";
  1.1967 +    return nullptr;
  1.1968 +  }
  1.1969 +
  1.1970 +  D3D10_TEXTURE2D_DESC desc;
  1.1971 +  aTexture->GetDesc(&desc);
  1.1972 +
  1.1973 +  D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
  1.1974 +
  1.1975 +  if (aFormat == SurfaceFormat::B8G8R8X8 && aTexture == mTexture) {
  1.1976 +    alphaMode = D2D1_ALPHA_MODE_IGNORE;
  1.1977 +  }
  1.1978 +
  1.1979 +  D2D1_RENDER_TARGET_PROPERTIES props =
  1.1980 +    D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(desc.Format, alphaMode));
  1.1981 +  hr = factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt));
  1.1982 +
  1.1983 +  if (FAILED(hr)) {
  1.1984 +    gfxWarning() << "Failed to create D2D render target for texture.";
  1.1985 +    return nullptr;
  1.1986 +  }
  1.1987 +
  1.1988 +  return rt;
  1.1989 +}
  1.1990 +
  1.1991 +void
  1.1992 +DrawTargetD2D::EnsureViews()
  1.1993 +{
  1.1994 +  if (mTempTexture && mSRView && mRTView) {
  1.1995 +    return;
  1.1996 +  }
  1.1997 +
  1.1998 +  HRESULT hr;
  1.1999 +
  1.2000 +  CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
  1.2001 +                             mSize.width,
  1.2002 +                             mSize.height,
  1.2003 +                             1, 1);
  1.2004 +  desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1.2005 +
  1.2006 +  hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mTempTexture));
  1.2007 +
  1.2008 +  if (FAILED(hr)) {
  1.2009 +    gfxWarning() << *this << "Failed to create temporary texture for rendertarget. Size: "
  1.2010 +      << mSize << " Code: " << hr;
  1.2011 +    return;
  1.2012 +  }
  1.2013 +
  1.2014 +  hr = mDevice->CreateShaderResourceView(mTempTexture, nullptr, byRef(mSRView));
  1.2015 +
  1.2016 +  if (FAILED(hr)) {
  1.2017 +    gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  1.2018 +    return;
  1.2019 +  }
  1.2020 +
  1.2021 +  hr = mDevice->CreateRenderTargetView(mTexture, nullptr, byRef(mRTView));
  1.2022 +
  1.2023 +  if (FAILED(hr)) {
  1.2024 +    gfxWarning() << *this << "Failed to create rendertarget view for temp texture. Code: " << hr;
  1.2025 +  }
  1.2026 +}
  1.2027 +
  1.2028 +void
  1.2029 +DrawTargetD2D::PopAllClips()
  1.2030 +{
  1.2031 +  if (mClipsArePushed) {
  1.2032 +    PopClipsFromRT(mRT);
  1.2033 +  
  1.2034 +    mClipsArePushed = false;
  1.2035 +  }
  1.2036 +}
  1.2037 +
  1.2038 +void
  1.2039 +DrawTargetD2D::PushClipsToRT(ID2D1RenderTarget *aRT)
  1.2040 +{
  1.2041 +  for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
  1.2042 +        iter != mPushedClips.end(); iter++) {
  1.2043 +    if (iter->mLayer) {
  1.2044 +      PushD2DLayer(aRT, iter->mPath->mGeometry, iter->mLayer, iter->mTransform);
  1.2045 +    } else {
  1.2046 +      aRT->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
  1.2047 +    }
  1.2048 +  }
  1.2049 +}
  1.2050 +
  1.2051 +void
  1.2052 +DrawTargetD2D::PopClipsFromRT(ID2D1RenderTarget *aRT)
  1.2053 +{
  1.2054 +  for (int i = mPushedClips.size() - 1; i >= 0; i--) {
  1.2055 +    if (mPushedClips[i].mLayer) {
  1.2056 +      aRT->PopLayer();
  1.2057 +    } else {
  1.2058 +      aRT->PopAxisAlignedClip();
  1.2059 +    }
  1.2060 +  }
  1.2061 +}
  1.2062 +
  1.2063 +void
  1.2064 +DrawTargetD2D::EnsureClipMaskTexture(IntRect *aBounds)
  1.2065 +{
  1.2066 +  if (mCurrentClipMaskTexture || mPushedClips.empty()) {
  1.2067 +    *aBounds = mCurrentClipBounds;
  1.2068 +    return;
  1.2069 +  }
  1.2070 +  
  1.2071 +  RefPtr<ID2D1Geometry> geometry = GetClippedGeometry(aBounds);
  1.2072 +
  1.2073 +  CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_A8_UNORM,
  1.2074 +                             mSize.width,
  1.2075 +                             mSize.height,
  1.2076 +                             1, 1);
  1.2077 +  desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1.2078 +
  1.2079 +  HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mCurrentClipMaskTexture));
  1.2080 +
  1.2081 +  if (FAILED(hr)) {
  1.2082 +    gfxWarning() << "Failed to create texture for ClipMask!";
  1.2083 +    return;
  1.2084 +  }
  1.2085 +
  1.2086 +  RefPtr<ID2D1RenderTarget> rt = CreateRTForTexture(mCurrentClipMaskTexture, SurfaceFormat::A8);
  1.2087 +
  1.2088 +  if (!rt) {
  1.2089 +    gfxWarning() << "Failed to create RT for ClipMask!";
  1.2090 +    return;
  1.2091 +  }
  1.2092 +  
  1.2093 +  RefPtr<ID2D1SolidColorBrush> brush;
  1.2094 +  rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush));
  1.2095 +    
  1.2096 +  rt->BeginDraw();
  1.2097 +  rt->Clear(D2D1::ColorF(0, 0));
  1.2098 +  rt->FillGeometry(geometry, brush);
  1.2099 +  rt->EndDraw();
  1.2100 +}
  1.2101 +
  1.2102 +bool
  1.2103 +DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
  1.2104 +                                const GlyphBuffer &aBuffer,
  1.2105 +                                const Color &aColor,
  1.2106 +                                IDWriteRenderingParams *aParams,
  1.2107 +                                const DrawOptions &aOptions)
  1.2108 +{
  1.2109 +  HRESULT hr;
  1.2110 +
  1.2111 +  RefPtr<IDWriteRenderingParams> params;
  1.2112 +
  1.2113 +  if (aParams) {
  1.2114 +    params = aParams;
  1.2115 +  } else {
  1.2116 +    mRT->GetTextRenderingParams(byRef(params));
  1.2117 +  }
  1.2118 +
  1.2119 +  DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
  1.2120 +  if (params) {
  1.2121 +    hr = aFont->mFontFace->GetRecommendedRenderingMode(
  1.2122 +      (FLOAT)aFont->GetSize(),
  1.2123 +      1.0f,
  1.2124 +      DWRITE_MEASURING_MODE_NATURAL,
  1.2125 +      params,
  1.2126 +      &renderMode);
  1.2127 +    if (FAILED(hr)) {
  1.2128 +      // this probably never happens, but let's play it safe
  1.2129 +      renderMode = DWRITE_RENDERING_MODE_DEFAULT;
  1.2130 +    }
  1.2131 +  }
  1.2132 +
  1.2133 +  // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept.
  1.2134 +  switch (renderMode) {
  1.2135 +  case DWRITE_RENDERING_MODE_ALIASED:
  1.2136 +    // ClearType texture creation will fail in this mode, so bail out
  1.2137 +    return false;
  1.2138 +  case DWRITE_RENDERING_MODE_DEFAULT:
  1.2139 +    // As per DWRITE_RENDERING_MODE documentation, pick Natural for font
  1.2140 +    // sizes under 16 ppem
  1.2141 +    if (aFont->GetSize() < 16.0f) {
  1.2142 +      renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
  1.2143 +    } else {
  1.2144 +      renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
  1.2145 +    }
  1.2146 +    break;
  1.2147 +  case DWRITE_RENDERING_MODE_OUTLINE:
  1.2148 +    renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
  1.2149 +    break;
  1.2150 +  default:
  1.2151 +    break;
  1.2152 +  }
  1.2153 +
  1.2154 +  DWRITE_MEASURING_MODE measureMode =
  1.2155 +    renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
  1.2156 +    renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
  1.2157 +    DWRITE_MEASURING_MODE_NATURAL;
  1.2158 +
  1.2159 +  DWRITE_MATRIX mat = DWriteMatrixFromMatrix(mTransform);
  1.2160 +
  1.2161 +  AutoDWriteGlyphRun autoRun;
  1.2162 +  DWriteGlyphRunFromGlyphs(aBuffer, aFont, &autoRun);
  1.2163 +
  1.2164 +  RefPtr<IDWriteGlyphRunAnalysis> analysis;
  1.2165 +  hr = GetDWriteFactory()->CreateGlyphRunAnalysis(&autoRun, 1.0f, &mat,
  1.2166 +                                                  renderMode, measureMode, 0, 0, byRef(analysis));
  1.2167 +
  1.2168 +  if (FAILED(hr)) {
  1.2169 +    return false;
  1.2170 +  }
  1.2171 +
  1.2172 +  RECT bounds;
  1.2173 +  hr = analysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
  1.2174 +
  1.2175 +  if (bounds.bottom <= bounds.top || bounds.right <= bounds.left) {
  1.2176 +    // DWrite seems to do this sometimes. I'm not 100% sure why. See bug 758980.
  1.2177 +    gfxDebug() << "Empty alpha texture bounds! Falling back to regular drawing.";
  1.2178 +    return false;
  1.2179 +  }
  1.2180 +  IntRect rectBounds(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
  1.2181 +  IntRect surfBounds(IntPoint(0, 0), mSize);
  1.2182 +
  1.2183 +  rectBounds.IntersectRect(rectBounds, surfBounds);
  1.2184 +
  1.2185 +  if (rectBounds.IsEmpty()) {
  1.2186 +    // Nothing to do.
  1.2187 +    return true;
  1.2188 +  }
  1.2189 +
  1.2190 +  RefPtr<ID3D10Texture2D> tex = CreateTextureForAnalysis(analysis, rectBounds);
  1.2191 +
  1.2192 +  if (!tex) {
  1.2193 +    return false;
  1.2194 +  }
  1.2195 +
  1.2196 +  RefPtr<ID3D10ShaderResourceView> srView;
  1.2197 +  hr = mDevice->CreateShaderResourceView(tex, nullptr, byRef(srView));
  1.2198 +
  1.2199 +  if (FAILED(hr)) {
  1.2200 +    return false;
  1.2201 +  }
  1.2202 +
  1.2203 +  MarkChanged();
  1.2204 +
  1.2205 +  // Prepare our background texture for drawing.
  1.2206 +  PopAllClips();
  1.2207 +  mRT->Flush();
  1.2208 +
  1.2209 +  SetupStateForRendering();
  1.2210 +
  1.2211 +  ID3D10EffectTechnique *technique = mPrivateData->mEffect->GetTechniqueByName("SampleTextTexture");
  1.2212 +
  1.2213 +  mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
  1.2214 +    SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((Float(rectBounds.x) / mSize.width) * 2.0f),
  1.2215 +                                           1.0f - (Float(rectBounds.y) / mSize.height * 2.0f),
  1.2216 +                                           (Float(rectBounds.width) / mSize.width) * 2.0f,
  1.2217 +                                           (-Float(rectBounds.height) / mSize.height) * 2.0f));
  1.2218 +  mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
  1.2219 +    SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  1.2220 +  FLOAT color[4] = { aColor.r, aColor.g, aColor.b, aColor.a };
  1.2221 +  mPrivateData->mEffect->GetVariableByName("TextColor")->AsVector()->
  1.2222 +    SetFloatVector(color);
  1.2223 +  
  1.2224 +  mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
  1.2225 +
  1.2226 +  bool isMasking = false;
  1.2227 +
  1.2228 +  IntRect clipBoundsStorage;
  1.2229 +  IntRect *clipBounds = nullptr;
  1.2230 +
  1.2231 +  if (!mPushedClips.empty()) {
  1.2232 +    clipBounds = &clipBoundsStorage;
  1.2233 +    RefPtr<ID2D1Geometry> geom = GetClippedGeometry(clipBounds);
  1.2234 +
  1.2235 +    RefPtr<ID2D1RectangleGeometry> rectGeom;
  1.2236 +    factory()->CreateRectangleGeometry(D2D1::RectF(Float(rectBounds.x),
  1.2237 +                                                   Float(rectBounds.y),
  1.2238 +                                                   Float(rectBounds.width + rectBounds.x),
  1.2239 +                                                   Float(rectBounds.height + rectBounds.y)),
  1.2240 +                                       byRef(rectGeom));
  1.2241 +
  1.2242 +    D2D1_GEOMETRY_RELATION relation;
  1.2243 +    if (FAILED(geom->CompareWithGeometry(rectGeom, D2D1::IdentityMatrix(), &relation)) ||
  1.2244 +        relation != D2D1_GEOMETRY_RELATION_CONTAINS ) {
  1.2245 +      isMasking = true;
  1.2246 +    }        
  1.2247 +  }
  1.2248 +  
  1.2249 +  if (isMasking) {
  1.2250 +    clipBounds = &clipBoundsStorage;
  1.2251 +    EnsureClipMaskTexture(clipBounds);
  1.2252 +
  1.2253 +    RefPtr<ID3D10ShaderResourceView> srViewMask;
  1.2254 +    hr = mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(srViewMask));
  1.2255 +
  1.2256 +    if (FAILED(hr)) {
  1.2257 +      return false;
  1.2258 +    }
  1.2259 +
  1.2260 +    mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(srViewMask);
  1.2261 +
  1.2262 +    mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
  1.2263 +      SetFloatVector(ShaderConstantRectD3D10(Float(rectBounds.x) / mSize.width, Float(rectBounds.y) / mSize.height,
  1.2264 +                                             Float(rectBounds.width) / mSize.width, Float(rectBounds.height) / mSize.height));
  1.2265 +
  1.2266 +    technique->GetPassByIndex(1)->Apply(0);
  1.2267 +  } else {
  1.2268 +    technique->GetPassByIndex(0)->Apply(0);
  1.2269 +  }  
  1.2270 +
  1.2271 +  RefPtr<ID3D10RenderTargetView> rtView;
  1.2272 +  ID3D10RenderTargetView *rtViews;
  1.2273 +  mDevice->CreateRenderTargetView(mTexture, nullptr, byRef(rtView));
  1.2274 +
  1.2275 +  rtViews = rtView;
  1.2276 +  mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
  1.2277 +  SetScissorToRect(clipBounds);
  1.2278 +  mDevice->Draw(4, 0);
  1.2279 +  return true;
  1.2280 +}
  1.2281 +
  1.2282 +TemporaryRef<ID2D1Brush>
  1.2283 +DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
  1.2284 +{
  1.2285 +  if (!IsPatternSupportedByD2D(aPattern)) {
  1.2286 +    RefPtr<ID2D1SolidColorBrush> colBrush;
  1.2287 +    mRT->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
  1.2288 +    return colBrush;
  1.2289 +  }
  1.2290 +
  1.2291 +  if (aPattern.GetType() == PatternType::COLOR) {
  1.2292 +    RefPtr<ID2D1SolidColorBrush> colBrush;
  1.2293 +    Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
  1.2294 +    mRT->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g,
  1.2295 +                                            color.b, color.a),
  1.2296 +                               D2D1::BrushProperties(aAlpha),
  1.2297 +                               byRef(colBrush));
  1.2298 +    return colBrush;
  1.2299 +  } else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
  1.2300 +    RefPtr<ID2D1LinearGradientBrush> gradBrush;
  1.2301 +    const LinearGradientPattern *pat =
  1.2302 +      static_cast<const LinearGradientPattern*>(&aPattern);
  1.2303 +
  1.2304 +    GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
  1.2305 +
  1.2306 +    if (!stops) {
  1.2307 +      gfxDebug() << "No stops specified for gradient pattern.";
  1.2308 +      return nullptr;
  1.2309 +    }
  1.2310 +
  1.2311 +    if (pat->mBegin == pat->mEnd) {
  1.2312 +      RefPtr<ID2D1SolidColorBrush> colBrush;
  1.2313 +      uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
  1.2314 +      vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
  1.2315 +      stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
  1.2316 +      mRT->CreateSolidColorBrush(d2dStops.back().color,
  1.2317 +                                 D2D1::BrushProperties(aAlpha),
  1.2318 +                                 byRef(colBrush));
  1.2319 +      return colBrush;
  1.2320 +    }
  1.2321 +
  1.2322 +    mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
  1.2323 +                                                                       D2DPoint(pat->mEnd)),
  1.2324 +                                   D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
  1.2325 +                                   stops->mStopCollection,
  1.2326 +                                   byRef(gradBrush));
  1.2327 +    return gradBrush;
  1.2328 +  } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
  1.2329 +    RefPtr<ID2D1RadialGradientBrush> gradBrush;
  1.2330 +    const RadialGradientPattern *pat =
  1.2331 +      static_cast<const RadialGradientPattern*>(&aPattern);
  1.2332 +
  1.2333 +    GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
  1.2334 +
  1.2335 +    if (!stops) {
  1.2336 +      gfxDebug() << "No stops specified for gradient pattern.";
  1.2337 +      return nullptr;
  1.2338 +    }
  1.2339 +
  1.2340 +    // This will not be a complex radial gradient brush.
  1.2341 +    mRT->CreateRadialGradientBrush(
  1.2342 +      D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2),
  1.2343 +                                          D2DPoint(pat->mCenter1 - pat->mCenter2),
  1.2344 +                                          pat->mRadius2, pat->mRadius2),
  1.2345 +      D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
  1.2346 +      stops->mStopCollection,
  1.2347 +      byRef(gradBrush));
  1.2348 +
  1.2349 +    return gradBrush;
  1.2350 +  } else if (aPattern.GetType() == PatternType::SURFACE) {
  1.2351 +    RefPtr<ID2D1BitmapBrush> bmBrush;
  1.2352 +    const SurfacePattern *pat =
  1.2353 +      static_cast<const SurfacePattern*>(&aPattern);
  1.2354 +
  1.2355 +    if (!pat->mSurface) {
  1.2356 +      gfxDebug() << "No source surface specified for surface pattern";
  1.2357 +      return nullptr;
  1.2358 +    }
  1.2359 +
  1.2360 +    RefPtr<ID2D1Bitmap> bitmap;
  1.2361 +
  1.2362 +    Matrix mat = pat->mMatrix;
  1.2363 +    
  1.2364 +    switch (pat->mSurface->GetType()) {
  1.2365 +    case SurfaceType::D2D1_BITMAP:
  1.2366 +      {
  1.2367 +        SourceSurfaceD2D *surf = static_cast<SourceSurfaceD2D*>(pat->mSurface.get());
  1.2368 +
  1.2369 +        bitmap = surf->mBitmap;
  1.2370 +
  1.2371 +        if (!bitmap) {
  1.2372 +          return nullptr;
  1.2373 +        }
  1.2374 +      }
  1.2375 +      break;
  1.2376 +    case SurfaceType::D2D1_DRAWTARGET:
  1.2377 +      {
  1.2378 +        SourceSurfaceD2DTarget *surf =
  1.2379 +          static_cast<SourceSurfaceD2DTarget*>(pat->mSurface.get());
  1.2380 +        bitmap = surf->GetBitmap(mRT);
  1.2381 +        AddDependencyOnSource(surf);
  1.2382 +      }
  1.2383 +      break;
  1.2384 +    default:
  1.2385 +      {
  1.2386 +        RefPtr<DataSourceSurface> dataSurf = pat->mSurface->GetDataSurface();
  1.2387 +        if (!dataSurf) {
  1.2388 +          gfxWarning() << "Invalid surface type.";
  1.2389 +          return nullptr;
  1.2390 +        }
  1.2391 +
  1.2392 +        bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT); 
  1.2393 +        if (!bitmap) {
  1.2394 +          return nullptr;
  1.2395 +        }
  1.2396 +      }
  1.2397 +      break;
  1.2398 +    }
  1.2399 +    
  1.2400 +    mRT->CreateBitmapBrush(bitmap,
  1.2401 +                           D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
  1.2402 +                                                       D2DExtend(pat->mExtendMode),
  1.2403 +                                                       D2DFilter(pat->mFilter)),
  1.2404 +                           D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
  1.2405 +                           byRef(bmBrush));
  1.2406 +
  1.2407 +    return bmBrush;
  1.2408 +  }
  1.2409 +
  1.2410 +  gfxWarning() << "Invalid pattern type detected.";
  1.2411 +  return nullptr;
  1.2412 +}
  1.2413 +
  1.2414 +TemporaryRef<ID3D10Texture2D>
  1.2415 +DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops)
  1.2416 +{
  1.2417 +  CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 4096, 1, 1, 1);
  1.2418 +
  1.2419 +  std::vector<D2D1_GRADIENT_STOP> rawStops;
  1.2420 +  rawStops.resize(aStops->mStopCollection->GetGradientStopCount());
  1.2421 +  aStops->mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size());
  1.2422 +
  1.2423 +  std::vector<unsigned char> textureData;
  1.2424 +  textureData.resize(4096 * 4);
  1.2425 +  unsigned char *texData = &textureData.front();
  1.2426 +
  1.2427 +  float prevColorPos = 0;
  1.2428 +  float nextColorPos = 1.0f;
  1.2429 +  D2D1_COLOR_F prevColor = rawStops[0].color;
  1.2430 +  D2D1_COLOR_F nextColor = prevColor;
  1.2431 +
  1.2432 +  if (rawStops.size() >= 2) {
  1.2433 +    nextColor = rawStops[1].color;
  1.2434 +    nextColorPos = rawStops[1].position;
  1.2435 +  }
  1.2436 +
  1.2437 +  uint32_t stopPosition = 2;
  1.2438 +
  1.2439 +  // Not the most optimized way but this will do for now.
  1.2440 +  for (int i = 0; i < 4096; i++) {
  1.2441 +    // The 4095 seems a little counter intuitive, but we want the gradient
  1.2442 +    // color at offset 0 at the first pixel, and at offset 1.0f at the last
  1.2443 +    // pixel.
  1.2444 +    float pos = float(i) / 4095;
  1.2445 +
  1.2446 +    while (pos > nextColorPos) {
  1.2447 +      prevColor = nextColor;
  1.2448 +      prevColorPos = nextColorPos;
  1.2449 +      if (rawStops.size() > stopPosition) {
  1.2450 +        nextColor = rawStops[stopPosition].color;
  1.2451 +        nextColorPos = rawStops[stopPosition++].position;
  1.2452 +      } else {
  1.2453 +        nextColorPos = 1.0f;
  1.2454 +      }
  1.2455 +    }
  1.2456 +
  1.2457 +    float interp;
  1.2458 +    
  1.2459 +    if (nextColorPos != prevColorPos) {
  1.2460 +      interp = (pos - prevColorPos) / (nextColorPos - prevColorPos);
  1.2461 +    } else {
  1.2462 +      interp = 0;
  1.2463 +    }
  1.2464 +
  1.2465 +    Color newColor(prevColor.r + (nextColor.r - prevColor.r) * interp,
  1.2466 +                    prevColor.g + (nextColor.g - prevColor.g) * interp,
  1.2467 +                    prevColor.b + (nextColor.b - prevColor.b) * interp,
  1.2468 +                    prevColor.a + (nextColor.a - prevColor.a) * interp);
  1.2469 +
  1.2470 +    texData[i * 4] = (char)(255.0f * newColor.b);
  1.2471 +    texData[i * 4 + 1] = (char)(255.0f * newColor.g);
  1.2472 +    texData[i * 4 + 2] = (char)(255.0f * newColor.r);
  1.2473 +    texData[i * 4 + 3] = (char)(255.0f * newColor.a);
  1.2474 +  }
  1.2475 +
  1.2476 +  D3D10_SUBRESOURCE_DATA data;
  1.2477 +  data.pSysMem = &textureData.front();
  1.2478 +  data.SysMemPitch = 4096 * 4;
  1.2479 +
  1.2480 +  RefPtr<ID3D10Texture2D> tex;
  1.2481 +  mDevice->CreateTexture2D(&desc, &data, byRef(tex));
  1.2482 +
  1.2483 +  return tex;
  1.2484 +}
  1.2485 +
  1.2486 +TemporaryRef<ID3D10Texture2D>
  1.2487 +DrawTargetD2D::CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds)
  1.2488 +{
  1.2489 +  HRESULT hr;
  1.2490 +
  1.2491 +  uint32_t bufferSize = aBounds.width * aBounds.height * 3;
  1.2492 +
  1.2493 +  RECT bounds;
  1.2494 +  bounds.left = aBounds.x;
  1.2495 +  bounds.top = aBounds.y;
  1.2496 +  bounds.right = aBounds.x + aBounds.width;
  1.2497 +  bounds.bottom = aBounds.y + aBounds.height;
  1.2498 +
  1.2499 +  // Add one byte so we can safely read a 32-bit int when copying the last
  1.2500 +  // 3 bytes.
  1.2501 +  BYTE *texture = new BYTE[bufferSize + 1];
  1.2502 +  hr = aAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, texture, bufferSize);
  1.2503 +
  1.2504 +  if (FAILED(hr)) {
  1.2505 +    delete [] texture;
  1.2506 +    return nullptr;
  1.2507 +  }
  1.2508 +
  1.2509 +  int alignedBufferSize = aBounds.width * aBounds.height * 4;
  1.2510 +
  1.2511 +  // Create a one-off immutable texture from system memory.
  1.2512 +  BYTE *alignedTextureData = new BYTE[alignedBufferSize];
  1.2513 +  for (int y = 0; y < aBounds.height; y++) {
  1.2514 +    for (int x = 0; x < aBounds.width; x++) {
  1.2515 +      // Copy 3 Bpp source to 4 Bpp destination memory used for
  1.2516 +      // texture creation. D3D10 has no 3 Bpp texture format we can
  1.2517 +      // use.
  1.2518 +      //
  1.2519 +      // Since we don't care what ends up in the alpha pixel of the
  1.2520 +      // destination, therefor we can simply copy a normal 32 bit
  1.2521 +      // integer each time, filling the alpha pixel of the destination
  1.2522 +      // with the first subpixel of the next pixel from the source.
  1.2523 +      *((int*)(alignedTextureData + (y * aBounds.width + x) * 4)) =
  1.2524 +        *((int*)(texture + (y * aBounds.width + x) * 3));
  1.2525 +    }
  1.2526 +  }
  1.2527 +
  1.2528 +  D3D10_SUBRESOURCE_DATA data;
  1.2529 +  
  1.2530 +  CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
  1.2531 +                             aBounds.width, aBounds.height,
  1.2532 +                             1, 1);
  1.2533 +  desc.Usage = D3D10_USAGE_IMMUTABLE;
  1.2534 +
  1.2535 +  data.SysMemPitch = aBounds.width * 4;
  1.2536 +  data.pSysMem = alignedTextureData;
  1.2537 +
  1.2538 +  RefPtr<ID3D10Texture2D> tex;
  1.2539 +  hr = mDevice->CreateTexture2D(&desc, &data, byRef(tex));
  1.2540 +	
  1.2541 +  delete [] alignedTextureData;
  1.2542 +  delete [] texture;
  1.2543 +
  1.2544 +  if (FAILED(hr)) {
  1.2545 +    return nullptr;
  1.2546 +  }
  1.2547 +
  1.2548 +  return tex;
  1.2549 +}
  1.2550 +
  1.2551 +void
  1.2552 +DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPattern)
  1.2553 +{
  1.2554 +  mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->GetPassByIndex(0)->Apply(0);
  1.2555 +  mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
  1.2556 +    SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  1.2557 +
  1.2558 +  float dimensions[] = { float(mSize.width), float(mSize.height), 0, 0 };
  1.2559 +  mPrivateData->mEffect->GetVariableByName("dimensions")->AsVector()->
  1.2560 +    SetFloatVector(dimensions);
  1.2561 +
  1.2562 +  const GradientStopsD2D *stops =
  1.2563 +    static_cast<const GradientStopsD2D*>(aPattern->mStops.get());
  1.2564 +
  1.2565 +  RefPtr<ID3D10Texture2D> tex = CreateGradientTexture(stops);
  1.2566 +
  1.2567 +  RefPtr<ID3D10ShaderResourceView> srView;
  1.2568 +  mDevice->CreateShaderResourceView(tex, nullptr, byRef(srView));
  1.2569 +
  1.2570 +  mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
  1.2571 +
  1.2572 +  Point dc = aPattern->mCenter2 - aPattern->mCenter1;
  1.2573 +  float dr = aPattern->mRadius2 - aPattern->mRadius1;
  1.2574 +
  1.2575 +  float diffv[] = { dc.x, dc.y, dr, 0 };
  1.2576 +  mPrivateData->mEffect->GetVariableByName("diff")->AsVector()->
  1.2577 +    SetFloatVector(diffv);
  1.2578 +
  1.2579 +  float center1[] = { aPattern->mCenter1.x, aPattern->mCenter1.y, dr, 0 };
  1.2580 +  mPrivateData->mEffect->GetVariableByName("center1")->AsVector()->
  1.2581 +    SetFloatVector(center1);
  1.2582 +
  1.2583 +  mPrivateData->mEffect->GetVariableByName("radius1")->AsScalar()->
  1.2584 +    SetFloat(aPattern->mRadius1);
  1.2585 +  mPrivateData->mEffect->GetVariableByName("sq_radius1")->AsScalar()->
  1.2586 +    SetFloat(pow(aPattern->mRadius1, 2));
  1.2587 +
  1.2588 +  Matrix invTransform = mTransform;
  1.2589 +
  1.2590 +  if (!invTransform.Invert()) {
  1.2591 +    // Bail if the matrix is singular.
  1.2592 +    return;
  1.2593 +  }
  1.2594 +  float matrix[] = { invTransform._11, invTransform._12, 0, 0,
  1.2595 +                      invTransform._21, invTransform._22, 0, 0,
  1.2596 +                      invTransform._31, invTransform._32, 1.0f, 0,
  1.2597 +                      0, 0, 0, 1.0f };
  1.2598 +
  1.2599 +  mPrivateData->mEffect->GetVariableByName("DeviceSpaceToUserSpace")->
  1.2600 +    AsMatrix()->SetMatrix(matrix);
  1.2601 +
  1.2602 +  float A = dc.x * dc.x + dc.y * dc.y - dr * dr;
  1.2603 +
  1.2604 +  uint32_t offset = 0;
  1.2605 +  switch (stops->mStopCollection->GetExtendMode()) {
  1.2606 +  case D2D1_EXTEND_MODE_WRAP:
  1.2607 +    offset = 1;
  1.2608 +    break;
  1.2609 +  case D2D1_EXTEND_MODE_MIRROR:
  1.2610 +    offset = 2;
  1.2611 +    break;
  1.2612 +  default:
  1.2613 +    gfxWarning() << "This shouldn't happen! Invalid extend mode for gradient stops.";
  1.2614 +  }
  1.2615 +
  1.2616 +  if (A == 0) {
  1.2617 +    mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
  1.2618 +      GetPassByIndex(offset * 2 + 1)->Apply(0);
  1.2619 +  } else {
  1.2620 +    mPrivateData->mEffect->GetVariableByName("A")->AsScalar()->SetFloat(A);
  1.2621 +    mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
  1.2622 +      GetPassByIndex(offset * 2)->Apply(0);
  1.2623 +  }
  1.2624 +}
  1.2625 +
  1.2626 +void
  1.2627 +DrawTargetD2D::SetupStateForRendering()
  1.2628 +{
  1.2629 +  UINT stride = sizeof(Vertex);
  1.2630 +  UINT offset = 0;
  1.2631 +  ID3D10Buffer *buff = mPrivateData->mVB;
  1.2632 +
  1.2633 +  mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  1.2634 +  mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
  1.2635 +  mDevice->IASetInputLayout(mPrivateData->mInputLayout);
  1.2636 +
  1.2637 +  D3D10_VIEWPORT viewport;
  1.2638 +  viewport.MaxDepth = 1;
  1.2639 +  viewport.MinDepth = 0;
  1.2640 +  viewport.Height = mSize.height;
  1.2641 +  viewport.Width = mSize.width;
  1.2642 +  viewport.TopLeftX = 0;
  1.2643 +  viewport.TopLeftY = 0;
  1.2644 +
  1.2645 +  mDevice->RSSetViewports(1, &viewport);
  1.2646 +}
  1.2647 +
  1.2648 +ID2D1Factory*
  1.2649 +DrawTargetD2D::factory()
  1.2650 +{
  1.2651 +  if (mFactory) {
  1.2652 +    return mFactory;
  1.2653 +  }
  1.2654 +
  1.2655 +  D2D1CreateFactoryFunc createD2DFactory;
  1.2656 +  HMODULE d2dModule = LoadLibraryW(L"d2d1.dll");
  1.2657 +  createD2DFactory = (D2D1CreateFactoryFunc)
  1.2658 +      GetProcAddress(d2dModule, "D2D1CreateFactory");
  1.2659 +
  1.2660 +  if (!createD2DFactory) {
  1.2661 +    gfxWarning() << "Failed to locate D2D1CreateFactory function.";
  1.2662 +    return nullptr;
  1.2663 +  }
  1.2664 +
  1.2665 +  D2D1_FACTORY_OPTIONS options;
  1.2666 +#ifdef _DEBUG
  1.2667 +  options.debugLevel = D2D1_DEBUG_LEVEL_WARNING;
  1.2668 +#else
  1.2669 +  options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
  1.2670 +#endif
  1.2671 +
  1.2672 +  HRESULT hr = createD2DFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
  1.2673 +                                __uuidof(ID2D1Factory),
  1.2674 +                                &options,
  1.2675 +                                (void**)&mFactory);
  1.2676 +
  1.2677 +  if (FAILED(hr)) {
  1.2678 +    gfxWarning() << "Failed to create Direct2D factory.";
  1.2679 +  }
  1.2680 +
  1.2681 +  return mFactory;
  1.2682 +}
  1.2683 +
  1.2684 +void
  1.2685 +DrawTargetD2D::CleanupD2D()
  1.2686 +{
  1.2687 +  if (mFactory) {
  1.2688 +    mFactory->Release();
  1.2689 +    mFactory = nullptr;
  1.2690 +  }
  1.2691 +}
  1.2692 +
  1.2693 +IDWriteFactory*
  1.2694 +DrawTargetD2D::GetDWriteFactory()
  1.2695 +{
  1.2696 +  if (mDWriteFactory) {
  1.2697 +    return mDWriteFactory;
  1.2698 +  }
  1.2699 +
  1.2700 +  decltype(DWriteCreateFactory)* createDWriteFactory;
  1.2701 +  HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
  1.2702 +  createDWriteFactory = (decltype(DWriteCreateFactory)*)
  1.2703 +    GetProcAddress(dwriteModule, "DWriteCreateFactory");
  1.2704 +
  1.2705 +  if (!createDWriteFactory) {
  1.2706 +    gfxWarning() << "Failed to locate DWriteCreateFactory function.";
  1.2707 +    return nullptr;
  1.2708 +  }
  1.2709 +
  1.2710 +  HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
  1.2711 +                                   reinterpret_cast<IUnknown**>(&mDWriteFactory));
  1.2712 +
  1.2713 +  if (FAILED(hr)) {
  1.2714 +    gfxWarning() << "Failed to create DWrite Factory.";
  1.2715 +  }
  1.2716 +
  1.2717 +  return mDWriteFactory;
  1.2718 +}
  1.2719 +
  1.2720 +void
  1.2721 +DrawTargetD2D::SetScissorToRect(IntRect *aRect)
  1.2722 +{
  1.2723 +  D3D10_RECT rect;
  1.2724 +  if (aRect) {
  1.2725 +    rect.left = aRect->x;
  1.2726 +    rect.right = aRect->XMost();
  1.2727 +    rect.top = aRect->y;
  1.2728 +    rect.bottom = aRect->YMost();
  1.2729 +  } else {
  1.2730 +    rect.left = rect.top = INT32_MIN;
  1.2731 +    rect.right = rect.bottom = INT32_MAX;
  1.2732 +  }
  1.2733 +
  1.2734 +  mDevice->RSSetScissorRects(1, &rect);
  1.2735 +}
  1.2736 +
  1.2737 +void
  1.2738 +DrawTargetD2D::PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID2D1Layer *aLayer, const D2D1_MATRIX_3X2_F &aTransform)
  1.2739 +{
  1.2740 +  D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
  1.2741 +  D2D1_LAYER_OPTIONS1 options1 =  D2D1_LAYER_OPTIONS1_NONE;
  1.2742 +
  1.2743 +  if (aRT->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
  1.2744 +    options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
  1.2745 +    options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
  1.2746 +  }
  1.2747 +
  1.2748 +	RefPtr<ID2D1DeviceContext> dc;
  1.2749 +	HRESULT hr = aRT->QueryInterface(IID_ID2D1DeviceContext, (void**)((ID2D1DeviceContext**)byRef(dc)));
  1.2750 +
  1.2751 +	if (FAILED(hr)) {
  1.2752 +	    aRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), aGeometry,
  1.2753 +				                                   D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
  1.2754 +				                                   1.0, nullptr, options),
  1.2755 +				             aLayer);
  1.2756 +	} else {
  1.2757 +	    dc->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry,
  1.2758 +				                                   D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
  1.2759 +				                                   1.0, nullptr, options1),
  1.2760 +				            aLayer);
  1.2761 +	}
  1.2762 +}
  1.2763 +
  1.2764 +}
  1.2765 +}

mercurial