gfx/2d/DrawTargetD2D.cpp

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

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

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <initguid.h>
     7 #include "DrawTargetD2D.h"
     8 #include "SourceSurfaceD2D.h"
     9 #ifdef USE_D2D1_1
    10 #include "SourceSurfaceD2D1.h"
    11 #endif
    12 #include "SourceSurfaceD2DTarget.h"
    13 #include "ShadersD2D.h"
    14 #include "PathD2D.h"
    15 #include "GradientStopsD2D.h"
    16 #include "ScaledFontDWrite.h"
    17 #include "ImageScaling.h"
    18 #include "Logging.h"
    19 #include "Tools.h"
    20 #include <algorithm>
    21 #include "mozilla/Constants.h"
    22 #include "FilterNodeSoftware.h"
    24 #ifdef USE_D2D1_1
    25 #include "FilterNodeD2D1.h"
    26 #endif
    28 #include <dwrite.h>
    30 // decltype is not usable for overloaded functions.
    31 typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
    32     D2D1_FACTORY_TYPE factoryType,
    33     REFIID iid,
    34     CONST D2D1_FACTORY_OPTIONS *pFactoryOptions,
    35     void **factory
    36 );
    38 using namespace std;
    40 namespace mozilla {
    41 namespace gfx {
    43 struct Vertex {
    44   float x;
    45   float y;
    46 };
    48 ID2D1Factory *DrawTargetD2D::mFactory;
    49 IDWriteFactory *DrawTargetD2D::mDWriteFactory;
    50 uint64_t DrawTargetD2D::mVRAMUsageDT;
    51 uint64_t DrawTargetD2D::mVRAMUsageSS;
    53 // Helper class to restore surface contents that was clipped out but may have
    54 // been altered by a drawing call.
    55 class AutoSaveRestoreClippedOut
    56 {
    57 public:
    58   AutoSaveRestoreClippedOut(DrawTargetD2D *aDT)
    59     : mDT(aDT)
    60   {}
    62   void Save() {
    63     if (!mDT->mPushedClips.size()) {
    64       return;
    65     }
    67     mDT->Flush();
    69     RefPtr<ID3D10Texture2D> tmpTexture;
    70     IntSize size = mDT->mSize;
    71     SurfaceFormat format = mDT->mFormat;
    73     CD3D10_TEXTURE2D_DESC desc(DXGIFormat(format), size.width, size.height,
    74                                1, 1);
    75     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    77     HRESULT hr = mDT->mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpTexture));
    78     if (FAILED(hr)) {
    79       gfxWarning() << "Failed to create temporary texture to hold surface data.";
    80     }
    81     mDT->mDevice->CopyResource(tmpTexture, mDT->mTexture);
    83     D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(format));
    85     RefPtr<IDXGISurface> surf;
    87     tmpTexture->QueryInterface((IDXGISurface**)byRef(surf));
    89     hr = mDT->mRT->CreateSharedBitmap(IID_IDXGISurface, surf,
    90                                       &props, byRef(mOldSurfBitmap));
    92     if (FAILED(hr)) {
    93       gfxWarning() << "Failed to create shared bitmap for old surface.";
    94     }
    96     IntRect clipBounds;
    97     mClippedArea = mDT->GetClippedGeometry(&clipBounds);
    99     if (!clipBounds.IsEqualEdges(IntRect(IntPoint(0, 0), mDT->mSize))) {
   100       // We still need to take into account clipBounds if it contains additional
   101       // clipping information.
   102       RefPtr<ID2D1RectangleGeometry> rectGeom;
   103       factory()->CreateRectangleGeometry(D2D1::Rect(Float(clipBounds.x),
   104                                                     Float(clipBounds.y),
   105                                                     Float(clipBounds.XMost()),
   106                                                     Float(clipBounds.YMost())),
   107                                          byRef(rectGeom));
   109       mClippedArea = IntersectGeometry(mClippedArea, rectGeom);
   110     }
   111   }
   113   ID2D1Factory *factory() { return mDT->factory(); }
   115   ~AutoSaveRestoreClippedOut()
   116   {
   117     if (!mOldSurfBitmap) {
   118       return;
   119     }
   121     ID2D1RenderTarget *rt = mDT->mRT;
   123     // Write the area that was clipped out back to the surface. This all
   124     // happens in device space.
   125     rt->SetTransform(D2D1::IdentityMatrix());
   126     mDT->mTransformDirty = true;
   128     RefPtr<ID2D1RectangleGeometry> rectGeom;
   129     factory()->CreateRectangleGeometry(
   130       D2D1::RectF(0, 0, float(mDT->mSize.width), float(mDT->mSize.height)),
   131       byRef(rectGeom));
   133     RefPtr<ID2D1PathGeometry> invClippedArea;
   134     factory()->CreatePathGeometry(byRef(invClippedArea));
   135     RefPtr<ID2D1GeometrySink> sink;
   136     invClippedArea->Open(byRef(sink));
   138     rectGeom->CombineWithGeometry(mClippedArea, D2D1_COMBINE_MODE_EXCLUDE, nullptr, sink);
   139     sink->Close();
   141     RefPtr<ID2D1BitmapBrush> brush;
   142     rt->CreateBitmapBrush(mOldSurfBitmap, D2D1::BitmapBrushProperties(), D2D1::BrushProperties(), byRef(brush));                   
   144     rt->FillGeometry(invClippedArea, brush);
   145   }
   147 private:
   149   DrawTargetD2D *mDT;  
   151   // If we have an operator unbound by the source, this will contain a bitmap
   152   // with the old dest surface data.
   153   RefPtr<ID2D1Bitmap> mOldSurfBitmap;
   154   // This contains the area drawing is clipped to.
   155   RefPtr<ID2D1Geometry> mClippedArea;
   156 };
   158 ID2D1Factory *D2DFactory()
   159 {
   160   return DrawTargetD2D::factory();
   161 }
   163 DrawTargetD2D::DrawTargetD2D()
   164   : mCurrentCachedLayer(0)
   165   , mClipsArePushed(false)
   166   , mPrivateData(nullptr)
   167 {
   168 }
   170 DrawTargetD2D::~DrawTargetD2D()
   171 {
   172   if (mRT) {  
   173     PopAllClips();
   175     mRT->EndDraw();
   177     mVRAMUsageDT -= GetByteSize();
   178   }
   179   if (mTempRT) {
   180     mTempRT->EndDraw();
   182     mVRAMUsageDT -= GetByteSize();
   183   }
   185   if (mSnapshot) {
   186     // We may hold the only reference. MarkIndependent will clear mSnapshot;
   187     // keep the snapshot object alive so it doesn't get destroyed while
   188     // MarkIndependent is running.
   189     RefPtr<SourceSurfaceD2DTarget> deathGrip = mSnapshot;
   190     // mSnapshot can be treated as independent of this DrawTarget since we know
   191     // this DrawTarget won't change again.
   192     deathGrip->MarkIndependent();
   193     // mSnapshot will be cleared now.
   194   }
   196   for (int i = 0; i < kLayerCacheSize; i++) {
   197     if (mCachedLayers[i]) {
   198       mCachedLayers[i] = nullptr;
   199       mVRAMUsageDT -= GetByteSize();
   200     }
   201   }
   203   // Targets depending on us can break that dependency, since we're obviously not going to
   204   // be modified in the future.
   205   for (TargetSet::iterator iter = mDependentTargets.begin();
   206        iter != mDependentTargets.end(); iter++) {
   207     (*iter)->mDependingOnTargets.erase(this);
   208   }
   209   // Our dependencies on other targets no longer matter.
   210   for (TargetSet::iterator iter = mDependingOnTargets.begin();
   211        iter != mDependingOnTargets.end(); iter++) {
   212     (*iter)->mDependentTargets.erase(this);
   213   }
   214 }
   216 /*
   217  * DrawTarget Implementation
   218  */
   219 TemporaryRef<SourceSurface>
   220 DrawTargetD2D::Snapshot()
   221 {
   222   if (!mSnapshot) {
   223     mSnapshot = new SourceSurfaceD2DTarget(this, mTexture, mFormat);
   224     Flush();
   225   }
   227   return mSnapshot;
   228 }
   230 void
   231 DrawTargetD2D::Flush()
   232 {
   233   PopAllClips();
   235   HRESULT hr = mRT->Flush();
   237   if (FAILED(hr)) {
   238     gfxWarning() << "Error reported when trying to flush D2D rendertarget. Code: " << hr;
   239   }
   241   // We no longer depend on any target.
   242   for (TargetSet::iterator iter = mDependingOnTargets.begin();
   243        iter != mDependingOnTargets.end(); iter++) {
   244     (*iter)->mDependentTargets.erase(this);
   245   }
   246   mDependingOnTargets.clear();
   247 }
   249 void
   250 DrawTargetD2D::AddDependencyOnSource(SourceSurfaceD2DTarget* aSource)
   251 {
   252   if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
   253     aSource->mDrawTarget->mDependentTargets.insert(this);
   254     mDependingOnTargets.insert(aSource->mDrawTarget);
   255   }
   256 }
   258 TemporaryRef<ID2D1Bitmap>
   259 DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface,
   260                                    Rect &aSource)
   261 {
   262   RefPtr<ID2D1Bitmap> bitmap;
   264   switch (aSurface->GetType()) {
   266   case SurfaceType::D2D1_BITMAP:
   267     {
   268       SourceSurfaceD2D *srcSurf = static_cast<SourceSurfaceD2D*>(aSurface);
   269       bitmap = srcSurf->GetBitmap();
   270     }
   271     break;
   272   case SurfaceType::D2D1_DRAWTARGET:
   273     {
   274       SourceSurfaceD2DTarget *srcSurf = static_cast<SourceSurfaceD2DTarget*>(aSurface);
   275       bitmap = srcSurf->GetBitmap(mRT);
   276       AddDependencyOnSource(srcSurf);
   277     }
   278     break;
   279   default:
   280     {
   281       RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
   283       if (!srcSurf) {
   284         gfxDebug() << "Not able to deal with non-data source surface.";
   285         return nullptr;
   286       }
   288       // We need to include any pixels that are overlapped by aSource
   289       Rect sourceRect(aSource);
   290       sourceRect.RoundOut();
   292       if (sourceRect.IsEmpty()) {
   293         gfxDebug() << "Bitmap source is empty. DrawBitmap will silently fail.";
   294         return nullptr;
   295       }
   297       if (sourceRect.width > mRT->GetMaximumBitmapSize() ||
   298           sourceRect.height > mRT->GetMaximumBitmapSize()) {
   299         gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail.";
   300         // Don't know how to deal with this yet.
   301         return nullptr;
   302       }
   304       int stride = srcSurf->Stride();
   306       unsigned char *data = srcSurf->GetData() +
   307                             (uint32_t)sourceRect.y * stride +
   308                             (uint32_t)sourceRect.x * BytesPerPixel(srcSurf->GetFormat());
   310       D2D1_BITMAP_PROPERTIES props =
   311         D2D1::BitmapProperties(D2DPixelFormat(srcSurf->GetFormat()));
   312       mRT->CreateBitmap(D2D1::SizeU(UINT32(sourceRect.width), UINT32(sourceRect.height)), data, stride, props, byRef(bitmap));
   314       // subtract the integer part leaving the fractional part
   315       aSource.x -= (uint32_t)aSource.x;
   316       aSource.y -= (uint32_t)aSource.y;
   317     }
   318     break;
   319   }
   321   return bitmap;
   322 }
   324 #ifdef USE_D2D1_1
   325 TemporaryRef<ID2D1Image>
   326 DrawTargetD2D::GetImageForSurface(SourceSurface *aSurface)
   327 {
   328   RefPtr<ID2D1Image> image;
   330   if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
   331     image = static_cast<SourceSurfaceD2D1*>(aSurface)->GetImage();
   332     static_cast<SourceSurfaceD2D1*>(aSurface)->EnsureIndependent();
   333   } else {
   334     Rect r(Point(), Size(aSurface->GetSize()));
   335     image = GetBitmapForSurface(aSurface, r);
   336   }
   338   return image;
   339 }
   340 #endif
   342 void
   343 DrawTargetD2D::DrawSurface(SourceSurface *aSurface,
   344                            const Rect &aDest,
   345                            const Rect &aSource,
   346                            const DrawSurfaceOptions &aSurfOptions,
   347                            const DrawOptions &aOptions)
   348 {
   349   RefPtr<ID2D1Bitmap> bitmap;
   351   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   353   PrepareForDrawing(rt);
   355   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   357   Rect srcRect = aSource;
   359   bitmap = GetBitmapForSurface(aSurface, srcRect);
   360   if (!bitmap) {
   361       return;
   362   }
   364   rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect));
   366   FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), aDest);
   367 }
   369 void
   370 DrawTargetD2D::DrawFilter(FilterNode *aNode,
   371                           const Rect &aSourceRect,
   372                           const Point &aDestPoint,
   373                           const DrawOptions &aOptions)
   374 {
   375 #ifdef USE_D2D1_1
   376   RefPtr<ID2D1DeviceContext> dc;
   377   HRESULT hr;
   379   hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc));
   381   if (SUCCEEDED(hr) && aNode->GetBackendType() == FILTER_BACKEND_DIRECT2D1_1) {
   382     ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   384     PrepareForDrawing(rt);
   386     rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   387     hr = rt->QueryInterface((ID2D1DeviceContext**)byRef(dc));
   389     if (SUCCEEDED(hr)) {
   390       dc->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
   392       Rect destRect = aSourceRect;
   393       destRect.MoveBy(aDestPoint);
   394       FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), destRect);
   395       return;
   396     }
   397   }
   398 #endif
   400   if (aNode->GetBackendType() != FILTER_BACKEND_SOFTWARE) {
   401     gfxWarning() << "Invalid filter backend passed to DrawTargetD2D!";
   402     return;
   403   }
   405   FilterNodeSoftware* filter = static_cast<FilterNodeSoftware*>(aNode);
   406   filter->Draw(this, aSourceRect, aDestPoint, aOptions);
   407 }
   409 void
   410 DrawTargetD2D::MaskSurface(const Pattern &aSource,
   411                            SourceSurface *aMask,
   412                            Point aOffset,
   413                            const DrawOptions &aOptions)
   414 {
   415   RefPtr<ID2D1Bitmap> bitmap;
   417   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()));
   419   PrepareForDrawing(rt);
   421   // FillOpacityMask only works if the antialias mode is MODE_ALIASED
   422   rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   424   IntSize size = aMask->GetSize();
   425   Rect maskRect = Rect(0.f, 0.f, size.width, size.height);
   426   bitmap = GetBitmapForSurface(aMask, maskRect);
   427   if (!bitmap) {
   428        return;
   429   }
   431   Rect dest = Rect(aOffset.x, aOffset.y, size.width, size.height);
   432   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
   433   rt->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
   435   FinalizeRTForOperation(aOptions.mCompositionOp, ColorPattern(Color()), dest);
   436 }
   438 void
   439 DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface,
   440                                      const Point &aDest,
   441                                      const Color &aColor,
   442                                      const Point &aOffset,
   443                                      Float aSigma,
   444                                      CompositionOp aOperator)
   445 {
   446   RefPtr<ID3D10ShaderResourceView> srView = nullptr;
   447   if (aSurface->GetType() != SurfaceType::D2D1_DRAWTARGET) {
   448     return;
   449   }
   451   SetScissorToRect(nullptr);
   453   // XXX - This function is way too long, it should be split up soon to make
   454   // it more graspable!
   456   Flush();
   458   AutoSaveRestoreClippedOut restoreClippedOut(this);
   460   if (!IsOperatorBoundByMask(aOperator)) {
   461     restoreClippedOut.Save();
   462   }
   464   srView = static_cast<SourceSurfaceD2DTarget*>(aSurface)->GetSRView();
   466   EnsureViews();
   468   if (!mTempRTView) {
   469     // This view is only needed in this path.
   470     HRESULT hr = mDevice->CreateRenderTargetView(mTempTexture, nullptr, byRef(mTempRTView));
   472     if (FAILED(hr)) {
   473       gfxWarning() << "Failure to create RenderTargetView. Code: " << hr;
   474       return;
   475     }
   476   }
   479   RefPtr<ID3D10RenderTargetView> destRTView = mRTView;
   480   RefPtr<ID3D10Texture2D> destTexture;
   481   HRESULT hr;
   483   RefPtr<ID3D10Texture2D> maskTexture;
   484   RefPtr<ID3D10ShaderResourceView> maskSRView;
   485   IntRect clipBounds;
   486   if (mPushedClips.size()) {
   487     EnsureClipMaskTexture(&clipBounds);
   489     mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(maskSRView));
   490   }
   492   IntSize srcSurfSize;
   493   ID3D10RenderTargetView *rtViews;
   494   D3D10_VIEWPORT viewport;
   496   UINT stride = sizeof(Vertex);
   497   UINT offset = 0;
   498   ID3D10Buffer *buff = mPrivateData->mVB;
   500   mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   501   mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
   502   mDevice->IASetInputLayout(mPrivateData->mInputLayout);
   504   mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   505     SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f));
   506   mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   507     SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
   509   // If we create a downsampled source surface we need to correct aOffset for that.
   510   Point correctedOffset = aOffset + aDest;
   512   // The 'practical' scaling factors.
   513   Float dsFactorX = 1.0f;
   514   Float dsFactorY = 1.0f;
   516   if (aSigma > 1.7f) {
   517     // In this case 9 samples of our original will not cover it. Generate the
   518     // mip levels for the original and create a downsampled version from
   519     // them. We generate a version downsampled so that a kernel for a sigma
   520     // of 1.7 will produce the right results.
   521     float blurWeights[9] = { 0.234671f, 0.197389f, 0.197389f, 0.117465f, 0.117465f, 0.049456f, 0.049456f, 0.014732f, 0.014732f };
   522     mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights));
   524     CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
   525                                aSurface->GetSize().width,
   526                                aSurface->GetSize().height);
   527     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   528     desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS;
   530     RefPtr<ID3D10Texture2D> mipTexture;
   531     hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mipTexture));
   533     if (FAILED(hr)) {
   534       gfxWarning() << "Failure to create temporary texture. Size: " <<
   535         aSurface->GetSize() << " Code: " << hr;
   536       return;
   537     }
   539     IntSize dsSize = IntSize(int32_t(aSurface->GetSize().width * (1.7f / aSigma)),
   540                              int32_t(aSurface->GetSize().height * (1.7f / aSigma)));
   542     if (dsSize.width < 1) {
   543       dsSize.width = 1;
   544     }
   545     if (dsSize.height < 1) {
   546       dsSize.height = 1;
   547     }
   549     dsFactorX = dsSize.width / Float(aSurface->GetSize().width);
   550     dsFactorY = dsSize.height / Float(aSurface->GetSize().height);
   551     correctedOffset.x *= dsFactorX;
   552     correctedOffset.y *= dsFactorY;
   554     desc = CD3D10_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM,
   555                                  dsSize.width,
   556                                  dsSize.height, 1, 1);
   557     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   558     RefPtr<ID3D10Texture2D> tmpDSTexture;
   559     hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpDSTexture));
   561     if (FAILED(hr)) {
   562       gfxWarning() << "Failure to create temporary texture. Size: " << dsSize << " Code: " << hr;
   563       return;
   564     }
   566     D3D10_BOX box;
   567     box.left = box.top = box.front = 0;
   568     box.back = 1;
   569     box.right = aSurface->GetSize().width;
   570     box.bottom = aSurface->GetSize().height;
   571     mDevice->CopySubresourceRegion(mipTexture, 0, 0, 0, 0, static_cast<SourceSurfaceD2DTarget*>(aSurface)->mTexture, 0, &box);
   573     mDevice->CreateShaderResourceView(mipTexture, nullptr,  byRef(srView));
   574     mDevice->GenerateMips(srView);
   576     RefPtr<ID3D10RenderTargetView> dsRTView;
   577     RefPtr<ID3D10ShaderResourceView> dsSRView;
   578     mDevice->CreateRenderTargetView(tmpDSTexture, nullptr,  byRef(dsRTView));
   579     mDevice->CreateShaderResourceView(tmpDSTexture, nullptr,  byRef(dsSRView));
   581     // We're not guaranteed the texture we created will be empty, we've
   582     // seen old content at least on NVidia drivers.
   583     float color[4] = { 0, 0, 0, 0 };
   584     mDevice->ClearRenderTargetView(dsRTView, color);
   586     rtViews = dsRTView;
   587     mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   589     viewport.MaxDepth = 1;
   590     viewport.MinDepth = 0;
   591     viewport.Height = dsSize.height;
   592     viewport.Width = dsSize.width;
   593     viewport.TopLeftX = 0;
   594     viewport.TopLeftY = 0;
   596     mDevice->RSSetViewports(1, &viewport);
   597     mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
   598     mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
   599       GetPassByIndex(0)->Apply(0);
   601     mDevice->OMSetBlendState(GetBlendStateForOperator(CompositionOp::OP_OVER), nullptr, 0xffffffff);
   603     mDevice->Draw(4, 0);
   605     srcSurfSize = dsSize;
   607     srView = dsSRView;
   608   } else {
   609     // In this case generate a kernel to draw the blur directly to the temp
   610     // surf in one direction and to final in the other.
   611     float blurWeights[9];
   613     float normalizeFactor = 1.0f;
   614     if (aSigma != 0) {
   615       normalizeFactor = 1.0f / Float(sqrt(2 * M_PI * pow(aSigma, 2)));
   616     }
   618     blurWeights[0] = normalizeFactor;
   620     // XXX - We should actually optimize for Sigma = 0 here. We could use a
   621     // much simpler shader and save a lot of texture lookups.
   622     for (int i = 1; i < 9; i += 2) {
   623       if (aSigma != 0) {
   624         blurWeights[i] = blurWeights[i + 1] = normalizeFactor *
   625           exp(-pow(float((i + 1) / 2), 2) / (2 * pow(aSigma, 2)));
   626       } else {
   627         blurWeights[i] = blurWeights[i + 1] = 0;
   628       }
   629     }
   631     mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights));
   633     viewport.MaxDepth = 1;
   634     viewport.MinDepth = 0;
   635     viewport.Height = aSurface->GetSize().height;
   636     viewport.Width = aSurface->GetSize().width;
   637     viewport.TopLeftX = 0;
   638     viewport.TopLeftY = 0;
   640     mDevice->RSSetViewports(1, &viewport);
   642     srcSurfSize = aSurface->GetSize();
   643   }
   645   // We may need to draw to a different intermediate surface if our temp
   646   // texture isn't big enough.
   647   bool needBiggerTemp = srcSurfSize.width > mSize.width ||
   648                         srcSurfSize.height > mSize.height;
   650   RefPtr<ID3D10RenderTargetView> tmpRTView;
   651   RefPtr<ID3D10ShaderResourceView> tmpSRView;
   652   RefPtr<ID3D10Texture2D> tmpTexture;
   654   IntSize tmpSurfSize = mSize;
   656   if (!needBiggerTemp) {
   657     tmpRTView = mTempRTView;
   658     tmpSRView = mSRView;
   660     // There could still be content here!
   661     float color[4] = { 0, 0, 0, 0 };
   662     mDevice->ClearRenderTargetView(tmpRTView, color);
   663   } else {
   664     CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
   665                                srcSurfSize.width,
   666                                srcSurfSize.height,
   667                                1, 1);
   668     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
   670     mDevice->CreateTexture2D(&desc, nullptr,  byRef(tmpTexture));
   671     mDevice->CreateRenderTargetView(tmpTexture, nullptr,  byRef(tmpRTView));
   672     mDevice->CreateShaderResourceView(tmpTexture, nullptr,  byRef(tmpSRView));
   674     tmpSurfSize = srcSurfSize;
   675   }
   677   rtViews = tmpRTView;
   678   mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   680   mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
   682   // Premultiplied!
   683   float shadowColor[4] = { aColor.r * aColor.a, aColor.g * aColor.a,
   684                            aColor.b * aColor.a, aColor.a };
   685   mPrivateData->mEffect->GetVariableByName("ShadowColor")->AsVector()->
   686     SetFloatVector(shadowColor);
   688   float pixelOffset = 1.0f / float(srcSurfSize.width);
   689   float blurOffsetsH[9] = { 0, pixelOffset, -pixelOffset,
   690                             2.0f * pixelOffset, -2.0f * pixelOffset,
   691                             3.0f * pixelOffset, -3.0f * pixelOffset,
   692                             4.0f * pixelOffset, - 4.0f * pixelOffset };
   694   pixelOffset = 1.0f / float(tmpSurfSize.height);
   695   float blurOffsetsV[9] = { 0, pixelOffset, -pixelOffset,
   696                             2.0f * pixelOffset, -2.0f * pixelOffset,
   697                             3.0f * pixelOffset, -3.0f * pixelOffset,
   698                             4.0f * pixelOffset, - 4.0f * pixelOffset };
   700   mPrivateData->mEffect->GetVariableByName("BlurOffsetsH")->
   701     SetRawValue(blurOffsetsH, 0, sizeof(blurOffsetsH));
   702   mPrivateData->mEffect->GetVariableByName("BlurOffsetsV")->
   703     SetRawValue(blurOffsetsV, 0, sizeof(blurOffsetsV));
   705   mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   706     GetPassByIndex(0)->Apply(0);
   708   mDevice->Draw(4, 0);
   710   viewport.MaxDepth = 1;
   711   viewport.MinDepth = 0;
   712   viewport.Height = mSize.height;
   713   viewport.Width = mSize.width;
   714   viewport.TopLeftX = 0;
   715   viewport.TopLeftY = 0;
   717   mDevice->RSSetViewports(1, &viewport);
   719   mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(tmpSRView);
   721   rtViews = destRTView;
   722   mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
   724   Point shadowDest = aDest + aOffset;
   726   mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   727     SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((shadowDest.x / mSize.width) * 2.0f),
   728                                            1.0f - (shadowDest.y / mSize.height * 2.0f),
   729                                            (Float(aSurface->GetSize().width) / mSize.width) * 2.0f,
   730                                            (-Float(aSurface->GetSize().height) / mSize.height) * 2.0f));
   731   mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   732     SetFloatVector(ShaderConstantRectD3D10(0, 0, Float(srcSurfSize.width) / tmpSurfSize.width,
   733                                                  Float(srcSurfSize.height) / tmpSurfSize.height));
   735   if (mPushedClips.size()) {
   736     mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(maskSRView);
   737     mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
   738       SetFloatVector(ShaderConstantRectD3D10(shadowDest.x / mSize.width, shadowDest.y / mSize.height,
   739                                              Float(aSurface->GetSize().width) / mSize.width,
   740                                              Float(aSurface->GetSize().height) / mSize.height));
   741     mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   742       GetPassByIndex(2)->Apply(0);
   743     SetScissorToRect(&clipBounds);
   744   } else {
   745     mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")->
   746       GetPassByIndex(1)->Apply(0);
   747   }
   749   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
   751   mDevice->Draw(4, 0);
   753   mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
   754     SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((aDest.x / mSize.width) * 2.0f),
   755                                            1.0f - (aDest.y / mSize.height * 2.0f),
   756                                            (Float(aSurface->GetSize().width) / mSize.width) * 2.0f,
   757                                            (-Float(aSurface->GetSize().height) / mSize.height) * 2.0f));
   758   mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(static_cast<SourceSurfaceD2DTarget*>(aSurface)->GetSRView());
   759   mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
   760     SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
   762   if (mPushedClips.size()) {
   763     mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
   764       SetFloatVector(ShaderConstantRectD3D10(aDest.x / mSize.width, aDest.y / mSize.height,
   765                                              Float(aSurface->GetSize().width) / mSize.width,
   766                                              Float(aSurface->GetSize().height) / mSize.height));
   767     mPrivateData->mEffect->GetTechniqueByName("SampleMaskedTexture")->
   768       GetPassByIndex(0)->Apply(0);
   769     // We've set the scissor rect here for the previous draw call.
   770   } else {
   771     mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->
   772       GetPassByIndex(0)->Apply(0);
   773   }
   775   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
   777   mDevice->Draw(4, 0);
   778 }
   780 void
   781 DrawTargetD2D::ClearRect(const Rect &aRect)
   782 {
   783   MarkChanged();
   784   PushClipRect(aRect);
   786   PopAllClips();
   788   AutoSaveRestoreClippedOut restoreClippedOut(this);
   790   D2D1_RECT_F clipRect;
   791   bool isPixelAligned;
   792   bool pushedClip = false;
   793   if (mTransform.IsRectilinear() &&
   794       GetDeviceSpaceClipRect(clipRect, isPixelAligned)) {
   795     if (mTransformDirty ||
   796         !mTransform.IsIdentity()) {
   797       mRT->SetTransform(D2D1::IdentityMatrix());
   798       mTransformDirty = true;
   799     }
   801     mRT->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   802     pushedClip = true;
   803   } else {
   804     FlushTransformToRT();
   805     restoreClippedOut.Save();
   806   }
   808   mRT->Clear(D2D1::ColorF(0, 0.0f));
   810   if (pushedClip) {
   811     mRT->PopAxisAlignedClip();
   812   }
   814   PopClip();
   815   return;
   816 }
   818 void
   819 DrawTargetD2D::CopySurface(SourceSurface *aSurface,
   820                            const IntRect &aSourceRect,
   821                            const IntPoint &aDestination)
   822 {
   823   MarkChanged();
   825   Rect srcRect(Float(aSourceRect.x), Float(aSourceRect.y),
   826                Float(aSourceRect.width), Float(aSourceRect.height));
   827   Rect dstRect(Float(aDestination.x), Float(aDestination.y),
   828                Float(aSourceRect.width), Float(aSourceRect.height));
   830   mRT->SetTransform(D2D1::IdentityMatrix());
   831   mTransformDirty = true;
   832   mRT->PushAxisAlignedClip(D2DRect(dstRect), D2D1_ANTIALIAS_MODE_ALIASED);
   833   mRT->Clear(D2D1::ColorF(0, 0.0f));
   834   mRT->PopAxisAlignedClip();
   836   RefPtr<ID2D1Bitmap> bitmap = GetBitmapForSurface(aSurface, srcRect);
   837   if (!bitmap) {
   838     return;
   839   }
   841   if (aSurface->GetFormat() == SurfaceFormat::A8) {
   842     RefPtr<ID2D1SolidColorBrush> brush;
   843     mRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White),
   844                                D2D1::BrushProperties(), byRef(brush));
   845     mRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
   846     mRT->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
   847   } else {
   848     mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f,
   849             D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
   850             D2DRect(srcRect));
   851   }
   852 }
   854 void
   855 DrawTargetD2D::FillRect(const Rect &aRect,
   856                         const Pattern &aPattern,
   857                         const DrawOptions &aOptions)
   858 {
   859   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   861   PrepareForDrawing(rt);
   863   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   865   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   867   if (brush) {
   868     rt->FillRectangle(D2DRect(aRect), brush);
   869   }
   871   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, aRect);
   872 }
   874 void
   875 DrawTargetD2D::StrokeRect(const Rect &aRect,
   876                           const Pattern &aPattern,
   877                           const StrokeOptions &aStrokeOptions,
   878                           const DrawOptions &aOptions)
   879 {
   880   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   882   PrepareForDrawing(rt);
   884   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   886   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   888   RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   890   if (brush && strokeStyle) {
   891     rt->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle);
   892   }
   894   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, aRect);
   895 }
   897 void
   898 DrawTargetD2D::StrokeLine(const Point &aStart,
   899                           const Point &aEnd,
   900                           const Pattern &aPattern,
   901                           const StrokeOptions &aStrokeOptions,
   902                           const DrawOptions &aOptions)
   903 {
   904   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   906   PrepareForDrawing(rt);
   908   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   910   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   912   RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   914   if (brush && strokeStyle) {
   915     rt->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle);
   916   }
   918   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, Float(mSize.width), Float(mSize.height)));
   919 }
   921 void
   922 DrawTargetD2D::Stroke(const Path *aPath,
   923                       const Pattern &aPattern,
   924                       const StrokeOptions &aStrokeOptions,
   925                       const DrawOptions &aOptions)
   926 {
   927   if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   928     gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   929     return;
   930   }
   932   const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   934   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   936   PrepareForDrawing(rt);
   938   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   940   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   942   RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
   944   if (brush && strokeStyle) {
   945     rt->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle);
   946   }
   948   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, Float(mSize.width), Float(mSize.height)));
   949 }
   951 void
   952 DrawTargetD2D::Fill(const Path *aPath,
   953                     const Pattern &aPattern,
   954                     const DrawOptions &aOptions)
   955 {
   956   if (aPath->GetBackendType() != BackendType::DIRECT2D) {
   957     gfxDebug() << *this << ": Ignoring drawing call for incompatible path.";
   958     return;
   959   }
   961   const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath);
   963   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
   965   PrepareForDrawing(rt);
   967   rt->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
   969   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
   971   if (brush) {
   972     rt->FillGeometry(d2dPath->mGeometry, brush);
   973   }
   975   Rect bounds;
   976   if (aOptions.mCompositionOp != CompositionOp::OP_OVER) {
   977     D2D1_RECT_F d2dbounds;
   978     d2dPath->mGeometry->GetBounds(D2D1::IdentityMatrix(), &d2dbounds);
   979     bounds = ToRect(d2dbounds);
   980   }
   981   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, bounds);
   982 }
   984 void
   985 DrawTargetD2D::FillGlyphs(ScaledFont *aFont,
   986                           const GlyphBuffer &aBuffer,
   987                           const Pattern &aPattern,
   988                           const DrawOptions &aOptions,
   989                           const GlyphRenderingOptions* aRenderOptions)
   990 {
   991   if (aFont->GetType() != FontType::DWRITE) {
   992     gfxDebug() << *this << ": Ignoring drawing call for incompatible font.";
   993     return;
   994   }
   996   ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont);
   998   IDWriteRenderingParams *params = nullptr;
   999   if (aRenderOptions) {
  1000     if (aRenderOptions->GetType() != FontType::DWRITE) {
  1001       gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions.";
  1002       // This should never happen.
  1003       MOZ_ASSERT(false);
  1004     } else {
  1005       params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderOptions)->mParams;
  1009   AntialiasMode aaMode = font->GetDefaultAAMode();
  1011   if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) {
  1012     aaMode = aOptions.mAntialiasMode;
  1015   if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA &&
  1016       aOptions.mCompositionOp == CompositionOp::OP_OVER && aPattern.GetType() == PatternType::COLOR &&
  1017       aaMode == AntialiasMode::SUBPIXEL) {
  1018     if (FillGlyphsManual(font, aBuffer,
  1019                          static_cast<const ColorPattern*>(&aPattern)->mColor,
  1020                          params, aOptions)) {
  1021       return;
  1025   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aPattern);
  1027   PrepareForDrawing(rt);
  1029   D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
  1031   switch (aaMode) {
  1032   case AntialiasMode::NONE:
  1033     d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
  1034     break;
  1035   case AntialiasMode::GRAY:
  1036     d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
  1037     break;
  1038   case AntialiasMode::SUBPIXEL:
  1039     d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE;
  1040     break;
  1041   default:
  1042     d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
  1045   if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE &&
  1046       mFormat != SurfaceFormat::B8G8R8X8) {
  1047     d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
  1050   rt->SetTextAntialiasMode(d2dAAMode);
  1052   if (rt != mRT || params != mTextRenderingParams) {
  1053     rt->SetTextRenderingParams(params);
  1054     if (rt == mRT) {
  1055       mTextRenderingParams = params;
  1059   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha);
  1061   AutoDWriteGlyphRun autoRun;
  1062   DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun);
  1064   if (brush) {
  1065     rt->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush);
  1068   FinalizeRTForOperation(aOptions.mCompositionOp, aPattern, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
  1071 void
  1072 DrawTargetD2D::Mask(const Pattern &aSource,
  1073                     const Pattern &aMask,
  1074                     const DrawOptions &aOptions)
  1076   ID2D1RenderTarget *rt = GetRTForOperation(aOptions.mCompositionOp, aSource);
  1078   PrepareForDrawing(rt);
  1080   RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
  1081   RefPtr<ID2D1Brush> maskBrush = CreateBrushForPattern(aMask, 1.0f);
  1083   RefPtr<ID2D1Layer> layer;
  1085   layer = GetCachedLayer();
  1087   rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), nullptr,
  1088                                       D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
  1089                                       D2D1::IdentityMatrix(),
  1090                                       1.0f, maskBrush),
  1091                 layer);
  1093   Rect rect(0, 0, (Float)mSize.width, (Float)mSize.height);
  1094   Matrix mat = mTransform;
  1095   mat.Invert();
  1097   rt->FillRectangle(D2DRect(mat.TransformBounds(rect)), brush);
  1098   PopCachedLayer(rt);
  1100   FinalizeRTForOperation(aOptions.mCompositionOp, aSource, Rect(0, 0, (Float)mSize.width, (Float)mSize.height));
  1103 void
  1104 DrawTargetD2D::PushClip(const Path *aPath)
  1106   if (aPath->GetBackendType() != BackendType::DIRECT2D) {
  1107     gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
  1108     return;
  1111   mCurrentClipMaskTexture = nullptr;
  1112   mCurrentClippedGeometry = nullptr;
  1114   RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath));
  1116   PushedClip clip;
  1117   clip.mTransform = D2DMatrix(mTransform);
  1118   clip.mPath = pathD2D;
  1120   pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds);
  1122   clip.mLayer = GetCachedLayer();
  1124   mPushedClips.push_back(clip);
  1126   // The transform of clips is relative to the world matrix, since we use the total
  1127   // transform for the clips, make the world matrix identity.
  1128   mRT->SetTransform(D2D1::IdentityMatrix());
  1129   mTransformDirty = true;
  1131   if (mClipsArePushed) {
  1132     PushD2DLayer(mRT, pathD2D->mGeometry, clip.mLayer, clip.mTransform);
  1136 void
  1137 DrawTargetD2D::PushClipRect(const Rect &aRect)
  1139   mCurrentClipMaskTexture = nullptr;
  1140   mCurrentClippedGeometry = nullptr;
  1141   if (!mTransform.IsRectilinear()) {
  1142     // Whoops, this isn't a rectangle in device space, Direct2D will not deal
  1143     // with this transform the way we want it to.
  1144     // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
  1146     RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
  1147     pathBuilder->MoveTo(aRect.TopLeft());
  1148     pathBuilder->LineTo(aRect.TopRight());
  1149     pathBuilder->LineTo(aRect.BottomRight());
  1150     pathBuilder->LineTo(aRect.BottomLeft());
  1151     pathBuilder->Close();
  1152     RefPtr<Path> path = pathBuilder->Finish();
  1153     return PushClip(path);
  1156   PushedClip clip;
  1157   Rect rect = mTransform.TransformBounds(aRect);
  1158   IntRect intRect;
  1159   clip.mIsPixelAligned = rect.ToIntRect(&intRect);
  1161   // Do not store the transform, just store the device space rectangle directly.
  1162   clip.mBounds = D2DRect(rect);
  1164   mPushedClips.push_back(clip);
  1166   mRT->SetTransform(D2D1::IdentityMatrix());
  1167   mTransformDirty = true;
  1169   if (mClipsArePushed) {
  1170     mRT->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
  1174 void
  1175 DrawTargetD2D::PopClip()
  1177   mCurrentClipMaskTexture = nullptr;
  1178   mCurrentClippedGeometry = nullptr;
  1179   if (mClipsArePushed) {
  1180     if (mPushedClips.back().mLayer) {
  1181       PopCachedLayer(mRT);
  1182     } else {
  1183       mRT->PopAxisAlignedClip();
  1186   mPushedClips.pop_back();
  1189 TemporaryRef<SourceSurface> 
  1190 DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData,
  1191                                            const IntSize &aSize,
  1192                                            int32_t aStride,
  1193                                            SurfaceFormat aFormat) const
  1195   RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1197   if (!newSurf->InitFromData(aData, aSize, aStride, aFormat, mRT)) {
  1198     return nullptr;
  1201   return newSurf;
  1204 TemporaryRef<SourceSurface> 
  1205 DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const
  1207   if (aSurface->GetType() == SurfaceType::D2D1_BITMAP ||
  1208       aSurface->GetType() == SurfaceType::D2D1_DRAWTARGET) {
  1209     return aSurface;
  1212   RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
  1214   DataSourceSurface::MappedSurface map;
  1215   if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
  1216     return nullptr;
  1219   RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1220   bool success = newSurf->InitFromData(map.mData, data->GetSize(), map.mStride, data->GetFormat(), mRT);
  1222   data->Unmap();
  1224   if (!success) {
  1225     return data;
  1227   return newSurf;
  1230 TemporaryRef<SourceSurface>
  1231 DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
  1233   if (aSurface.mType != NativeSurfaceType::D3D10_TEXTURE) {
  1234     gfxDebug() << *this << ": Failure to create source surface from non-D3D10 texture native surface.";
  1235     return nullptr;
  1237   RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
  1239   if (!newSurf->InitFromTexture(static_cast<ID3D10Texture2D*>(aSurface.mSurface),
  1240                                 aSurface.mFormat,
  1241                                 mRT))
  1243     gfxWarning() << *this << ": Failed to create SourceSurface from texture.";
  1244     return nullptr;
  1247   return newSurf;
  1250 TemporaryRef<DrawTarget>
  1251 DrawTargetD2D::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
  1253   RefPtr<DrawTargetD2D> newTarget =
  1254     new DrawTargetD2D();
  1256   if (!newTarget->Init(aSize, aFormat)) {
  1257     gfxDebug() << *this << ": Failed to create optimal draw target. Size: " << aSize;
  1258     return nullptr;
  1261   return newTarget;
  1264 TemporaryRef<PathBuilder>
  1265 DrawTargetD2D::CreatePathBuilder(FillRule aFillRule) const
  1267   RefPtr<ID2D1PathGeometry> path;
  1268   HRESULT hr = factory()->CreatePathGeometry(byRef(path));
  1270   if (FAILED(hr)) {
  1271     gfxWarning() << "Failed to create Direct2D Path Geometry. Code: " << hr;
  1272     return nullptr;
  1275   RefPtr<ID2D1GeometrySink> sink;
  1276   hr = path->Open(byRef(sink));
  1277   if (FAILED(hr)) {
  1278     gfxWarning() << "Failed to access Direct2D Path Geometry. Code: " << hr;
  1279     return nullptr;
  1282   if (aFillRule == FillRule::FILL_WINDING) {
  1283     sink->SetFillMode(D2D1_FILL_MODE_WINDING);
  1286   return new PathBuilderD2D(sink, path, aFillRule);
  1289 TemporaryRef<GradientStops>
  1290 DrawTargetD2D::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops, ExtendMode aExtendMode) const
  1292   D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops];
  1294   for (uint32_t i = 0; i < aNumStops; i++) {
  1295     stops[i].position = rawStops[i].offset;
  1296     stops[i].color = D2DColor(rawStops[i].color);
  1299   RefPtr<ID2D1GradientStopCollection> stopCollection;
  1301   HRESULT hr =
  1302     mRT->CreateGradientStopCollection(stops, aNumStops,
  1303                                       D2D1_GAMMA_2_2, D2DExtend(aExtendMode),
  1304                                       byRef(stopCollection));
  1305   delete [] stops;
  1307   if (FAILED(hr)) {
  1308     gfxWarning() << "Failed to create GradientStopCollection. Code: " << hr;
  1309     return nullptr;
  1312   return new GradientStopsD2D(stopCollection);
  1315 TemporaryRef<FilterNode>
  1316 DrawTargetD2D::CreateFilter(FilterType aType)
  1318 #ifdef USE_D2D1_1
  1319   RefPtr<ID2D1DeviceContext> dc;
  1320   HRESULT hr = mRT->QueryInterface((ID2D1DeviceContext**)byRef(dc));
  1322   if (SUCCEEDED(hr)) {
  1323     return FilterNodeD2D1::Create(this, dc, aType);
  1325 #endif
  1326   return FilterNodeSoftware::Create(aType);
  1329 void*
  1330 DrawTargetD2D::GetNativeSurface(NativeSurfaceType aType)
  1332   if (aType != NativeSurfaceType::D3D10_TEXTURE) {
  1333     return nullptr;
  1336   return mTexture;
  1339 /*
  1340  * Public functions
  1341  */
  1342 bool
  1343 DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat)
  1345   HRESULT hr;
  1347   mSize = aSize;
  1348   mFormat = aFormat;
  1350   if (!Factory::GetDirect3D10Device()) {
  1351     gfxDebug() << "Failed to Init Direct2D DrawTarget (No D3D10 Device set.)";
  1352     return false;
  1354   mDevice = Factory::GetDirect3D10Device();
  1356   CD3D10_TEXTURE2D_DESC desc(DXGIFormat(aFormat),
  1357                              mSize.width,
  1358                              mSize.height,
  1359                              1, 1);
  1360   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1362   hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture));
  1364   if (FAILED(hr)) {
  1365     gfxDebug() << "Failed to init Direct2D DrawTarget. Size: " << mSize << " Code: " << hr;
  1366     return false;
  1369   if (!InitD2DRenderTarget()) {
  1370     return false;
  1373   mRT->Clear(D2D1::ColorF(0, 0));
  1374   return true;
  1377 bool
  1378 DrawTargetD2D::Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
  1380   HRESULT hr;
  1382   mTexture = aTexture;
  1383   mFormat = aFormat;
  1385   if (!mTexture) {
  1386     gfxDebug() << "No valid texture for Direct2D draw target initialization.";
  1387     return false;
  1390   RefPtr<ID3D10Device> device;
  1391   mTexture->GetDevice(byRef(device));
  1393   hr = device->QueryInterface((ID3D10Device1**)byRef(mDevice));
  1395   if (FAILED(hr)) {
  1396     gfxWarning() << "Failed to get D3D10 device from texture.";
  1397     return false;
  1400   D3D10_TEXTURE2D_DESC desc;
  1401   mTexture->GetDesc(&desc);
  1402   mSize.width = desc.Width;
  1403   mSize.height = desc.Height;
  1405   return InitD2DRenderTarget();
  1408 // {0D398B49-AE7B-416F-B26D-EA3C137D1CF7}
  1409 static const GUID sPrivateDataD2D = 
  1410 { 0xd398b49, 0xae7b, 0x416f, { 0xb2, 0x6d, 0xea, 0x3c, 0x13, 0x7d, 0x1c, 0xf7 } };
  1412 bool
  1413 DrawTargetD2D::InitD3D10Data()
  1415   HRESULT hr;
  1417   UINT privateDataSize;
  1418   privateDataSize = sizeof(mPrivateData);
  1419   hr = mDevice->GetPrivateData(sPrivateDataD2D, &privateDataSize, &mPrivateData);
  1421   if (SUCCEEDED(hr)) {
  1422       return true;
  1425   mPrivateData = new PrivateD3D10DataD2D;
  1427   decltype(D3D10CreateEffectFromMemory)* createD3DEffect;
  1428   HMODULE d3dModule = LoadLibraryW(L"d3d10_1.dll");
  1429   createD3DEffect = (decltype(D3D10CreateEffectFromMemory)*)
  1430       GetProcAddress(d3dModule, "D3D10CreateEffectFromMemory");
  1432   hr = createD3DEffect((void*)d2deffect, sizeof(d2deffect), 0, mDevice, nullptr, byRef(mPrivateData->mEffect));
  1434   if (FAILED(hr)) {
  1435     gfxWarning() << "Failed to initialize Direct2D required effects. Code: " << hr;
  1436     return false;
  1439   privateDataSize = sizeof(mPrivateData);
  1440   mDevice->SetPrivateData(sPrivateDataD2D, privateDataSize, &mPrivateData);
  1442   D3D10_INPUT_ELEMENT_DESC layout[] =
  1444     { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
  1445   };
  1446   D3D10_PASS_DESC passDesc;
  1448   mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->GetDesc(&passDesc);
  1450   hr = mDevice->CreateInputLayout(layout,
  1451                                   sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC),
  1452                                   passDesc.pIAInputSignature,
  1453                                   passDesc.IAInputSignatureSize,
  1454                                   byRef(mPrivateData->mInputLayout));
  1456   if (FAILED(hr)) {
  1457     gfxWarning() << "Failed to initialize Direct2D required InputLayout. Code: " << hr;
  1458     return false;
  1461   D3D10_SUBRESOURCE_DATA data;
  1462   Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} };
  1463   data.pSysMem = vertices;
  1464   CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
  1466   hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mPrivateData->mVB));
  1468   if (FAILED(hr)) {
  1469     gfxWarning() << "Failed to initialize Direct2D required VertexBuffer. Code: " << hr;
  1470     return false;
  1473   return true;
  1476 /*
  1477  * Private helpers
  1478  */
  1479 uint32_t
  1480 DrawTargetD2D::GetByteSize() const
  1482   return mSize.width * mSize.height * BytesPerPixel(mFormat);
  1485 TemporaryRef<ID2D1Layer>
  1486 DrawTargetD2D::GetCachedLayer()
  1488   RefPtr<ID2D1Layer> layer;
  1490   if (mCurrentCachedLayer < 5) {
  1491     if (!mCachedLayers[mCurrentCachedLayer]) {
  1492       mRT->CreateLayer(byRef(mCachedLayers[mCurrentCachedLayer]));
  1493       mVRAMUsageDT += GetByteSize();
  1495     layer = mCachedLayers[mCurrentCachedLayer];
  1496   } else {
  1497     mRT->CreateLayer(byRef(layer));
  1500   mCurrentCachedLayer++;
  1501   return layer;
  1504 void
  1505 DrawTargetD2D::PopCachedLayer(ID2D1RenderTarget *aRT)
  1507   aRT->PopLayer();
  1508   mCurrentCachedLayer--;
  1511 bool
  1512 DrawTargetD2D::InitD2DRenderTarget()
  1514   if (!factory()) {
  1515     return false;
  1518   mRT = CreateRTForTexture(mTexture, mFormat);
  1520   if (!mRT) {
  1521     return false;
  1524   mRT->BeginDraw();
  1526   if (mFormat == SurfaceFormat::B8G8R8X8) {
  1527     mRT->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
  1530   mVRAMUsageDT += GetByteSize();
  1532   return InitD3D10Data();
  1535 void
  1536 DrawTargetD2D::PrepareForDrawing(ID2D1RenderTarget *aRT)
  1538   if (!mClipsArePushed || aRT == mTempRT) {
  1539     if (mPushedClips.size()) {
  1540       // The transform of clips is relative to the world matrix, since we use the total
  1541       // transform for the clips, make the world matrix identity.
  1542       aRT->SetTransform(D2D1::IdentityMatrix());
  1543       if (aRT == mRT) {
  1544         mTransformDirty = true;
  1545         mClipsArePushed = true;
  1547       PushClipsToRT(aRT);
  1550   FlushTransformToRT();
  1551   MarkChanged();
  1553   if (aRT == mTempRT) {
  1554     mTempRT->SetTransform(D2DMatrix(mTransform));
  1558 void
  1559 DrawTargetD2D::MarkChanged()
  1561   if (mSnapshot) {
  1562     if (mSnapshot->hasOneRef()) {
  1563       // Just destroy it, since no-one else knows about it.
  1564       mSnapshot = nullptr;
  1565     } else {
  1566       mSnapshot->DrawTargetWillChange();
  1567       // The snapshot will no longer depend on this target.
  1568       MOZ_ASSERT(!mSnapshot);
  1571   if (mDependentTargets.size()) {
  1572     // Copy mDependentTargets since the Flush()es below will modify it.
  1573     TargetSet tmpTargets = mDependentTargets;
  1574     for (TargetSet::iterator iter = tmpTargets.begin();
  1575          iter != tmpTargets.end(); iter++) {
  1576       (*iter)->Flush();
  1578     // The Flush() should have broken all dependencies on this target.
  1579     MOZ_ASSERT(!mDependentTargets.size());
  1583 ID3D10BlendState*
  1584 DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator)
  1586   size_t operatorIndex = static_cast<size_t>(aOperator);
  1587   if (mPrivateData->mBlendStates[operatorIndex]) {
  1588     return mPrivateData->mBlendStates[operatorIndex];
  1591   D3D10_BLEND_DESC desc;
  1593   memset(&desc, 0, sizeof(D3D10_BLEND_DESC));
  1595   desc.AlphaToCoverageEnable = FALSE;
  1596   desc.BlendEnable[0] = TRUE;
  1597   desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
  1598   desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
  1600   switch (aOperator) {
  1601   case CompositionOp::OP_ADD:
  1602     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1603     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
  1604     break;
  1605   case CompositionOp::OP_IN:
  1606     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
  1607     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1608     break;
  1609   case CompositionOp::OP_OUT:
  1610     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1611     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1612     break;
  1613   case CompositionOp::OP_ATOP:
  1614     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA;
  1615     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1616     break;
  1617   case CompositionOp::OP_DEST_IN:
  1618     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
  1619     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
  1620     break;
  1621   case CompositionOp::OP_DEST_OUT:
  1622     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO;
  1623     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1624     break;
  1625   case CompositionOp::OP_DEST_ATOP:
  1626     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1627     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA;
  1628     break;
  1629   case CompositionOp::OP_DEST_OVER:
  1630     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1631     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE;
  1632     break;
  1633   case CompositionOp::OP_XOR:
  1634     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA;
  1635     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1636     break;
  1637   case CompositionOp::OP_SOURCE:
  1638     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1639     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO;
  1640     break;
  1641   default:
  1642     desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE;
  1643     desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
  1646   mDevice->CreateBlendState(&desc, byRef(mPrivateData->mBlendStates[operatorIndex]));
  1648   return mPrivateData->mBlendStates[operatorIndex];
  1651 /* This function prepares the temporary RT for drawing and returns it when a
  1652  * drawing operation other than OVER is required.
  1653  */
  1654 ID2D1RenderTarget*
  1655 DrawTargetD2D::GetRTForOperation(CompositionOp aOperator, const Pattern &aPattern)
  1657   if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
  1658     return mRT;
  1661   PopAllClips();
  1663   if (aOperator > CompositionOp::OP_XOR) {
  1664     mRT->Flush();
  1667   if (mTempRT) {
  1668     mTempRT->Clear(D2D1::ColorF(0, 0));
  1669     return mTempRT;
  1672   EnsureViews();
  1674   if (!mRTView || !mSRView) {
  1675     gfxDebug() << *this << ": Failed to get required views. Defaulting to CompositionOp::OP_OVER.";
  1676     return mRT;
  1679   mTempRT = CreateRTForTexture(mTempTexture, SurfaceFormat::B8G8R8A8);
  1681   if (!mTempRT) {
  1682     return mRT;
  1685   mVRAMUsageDT += GetByteSize();
  1687   mTempRT->BeginDraw();
  1689   mTempRT->Clear(D2D1::ColorF(0, 0));
  1691   return mTempRT;
  1694 /* This function blends back the content of a drawing operation (drawn to an
  1695  * empty surface with OVER, so the surface now contains the source operation
  1696  * contents) to the rendertarget using the requested composition operation.
  1697  * In order to respect clip for operations which are unbound by their mask,
  1698  * the old content of the surface outside the clipped area may be blended back
  1699  * to the surface.
  1700  */
  1701 void
  1702 DrawTargetD2D::FinalizeRTForOperation(CompositionOp aOperator, const Pattern &aPattern, const Rect &aBounds)
  1704   if (aOperator == CompositionOp::OP_OVER && IsPatternSupportedByD2D(aPattern)) {
  1705     return;
  1708   if (!mTempRT) {
  1709     return;
  1712   PopClipsFromRT(mTempRT);
  1714   mRT->Flush();
  1715   mTempRT->Flush();
  1717   AutoSaveRestoreClippedOut restoreClippedOut(this);
  1719   bool needsWriteBack =
  1720     !IsOperatorBoundByMask(aOperator) && mPushedClips.size();
  1722   if (needsWriteBack) {
  1723     restoreClippedOut.Save();
  1726   ID3D10RenderTargetView *rtViews = mRTView;
  1727   mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
  1729   UINT stride = sizeof(Vertex);
  1730   UINT offset = 0;
  1731   ID3D10Buffer *buff = mPrivateData->mVB;
  1733   mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  1734   mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
  1735   mDevice->IASetInputLayout(mPrivateData->mInputLayout);
  1737   D3D10_VIEWPORT viewport;
  1738   viewport.MaxDepth = 1;
  1739   viewport.MinDepth = 0;
  1740   viewport.Height = mSize.height;
  1741   viewport.Width = mSize.width;
  1742   viewport.TopLeftX = 0;
  1743   viewport.TopLeftY = 0;
  1745   RefPtr<ID3D10Texture2D> tmpTexture;
  1746   RefPtr<ID3D10ShaderResourceView> mBckSRView;
  1748   mDevice->RSSetViewports(1, &viewport);
  1749   mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
  1750     SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f));
  1752   if (IsPatternSupportedByD2D(aPattern)) {
  1753     mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
  1754       SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  1755     mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(mSRView);
  1757     // Handle the case where we blend with the backdrop
  1758     if (aOperator > CompositionOp::OP_XOR) {
  1759       IntSize size = mSize;
  1760       SurfaceFormat format = mFormat;
  1762       CD3D10_TEXTURE2D_DESC desc(DXGIFormat(format), size.width, size.height, 1, 1);
  1763       desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  1765       HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(tmpTexture));
  1766       if (FAILED(hr)) {
  1767         gfxWarning() << "Failed to create temporary texture to hold surface data.";
  1768         return;
  1771       mDevice->CopyResource(tmpTexture, mTexture);
  1772       if (FAILED(hr)) {
  1773         gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  1774         return;
  1777       DrawTargetD2D::Flush();
  1779       hr = mDevice->CreateShaderResourceView(tmpTexture, nullptr, byRef(mBckSRView));
  1781       if (FAILED(hr)) {
  1782         gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  1783         return;
  1786       unsigned int compop = (unsigned int)aOperator - (unsigned int)CompositionOp::OP_XOR;
  1787       mPrivateData->mEffect->GetVariableByName("bcktex")->AsShaderResource()->SetResource(mBckSRView);
  1788       mPrivateData->mEffect->GetVariableByName("blendop")->AsScalar()->SetInt(compop);
  1790       if (aOperator > CompositionOp::OP_EXCLUSION)
  1791         mPrivateData->mEffect->GetTechniqueByName("SampleTextureForNonSeparableBlending")->
  1792           GetPassByIndex(0)->Apply(0);
  1793       else if (aOperator > CompositionOp::OP_COLOR_DODGE)
  1794         mPrivateData->mEffect->GetTechniqueByName("SampleTextureForSeparableBlending_2")->
  1795           GetPassByIndex(0)->Apply(0);
  1796       else
  1797         mPrivateData->mEffect->GetTechniqueByName("SampleTextureForSeparableBlending_1")->
  1798           GetPassByIndex(0)->Apply(0);
  1800     else {
  1801       mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->Apply(0);
  1804   } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
  1805     const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
  1807     if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
  1808       // Draw nothing!
  1809       return;
  1812     mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(mSRView);
  1814     SetupEffectForRadialGradient(pat);
  1817   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
  1819   SetScissorToRect(nullptr);
  1820   mDevice->Draw(4, 0);
  1823 static D2D1_RECT_F
  1824 IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
  1826   D2D1_RECT_F result;
  1827   result.left = max(aRect1.left, aRect2.left);
  1828   result.top = max(aRect1.top, aRect2.top);
  1829   result.right = min(aRect1.right, aRect2.right);
  1830   result.bottom = min(aRect1.bottom, aRect2.bottom);
  1832   result.right = max(result.right, result.left);
  1833   result.bottom = max(result.bottom, result.top);
  1835   return result;
  1838 bool
  1839 DrawTargetD2D::GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned)
  1841   if (!mPushedClips.size()) {
  1842     return false;
  1845   std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
  1846   if (iter->mPath) {
  1847     return false;
  1849   aClipRect = iter->mBounds;
  1850   aIsPixelAligned = iter->mIsPixelAligned;
  1852   iter++;
  1853   for (;iter != mPushedClips.end(); iter++) {
  1854     if (iter->mPath) {
  1855       return false;
  1857     aClipRect = IntersectRect(aClipRect, iter->mBounds);
  1858     if (!iter->mIsPixelAligned) {
  1859       aIsPixelAligned = false;
  1862   return true;
  1865 TemporaryRef<ID2D1Geometry>
  1866 DrawTargetD2D::GetClippedGeometry(IntRect *aClipBounds)
  1868   if (mCurrentClippedGeometry) {
  1869     *aClipBounds = mCurrentClipBounds;
  1870     return mCurrentClippedGeometry;
  1873   mCurrentClipBounds = IntRect(IntPoint(0, 0), mSize);
  1875   // if pathGeom is null then pathRect represents the path.
  1876   RefPtr<ID2D1Geometry> pathGeom;
  1877   D2D1_RECT_F pathRect;
  1878   bool pathRectIsAxisAligned = false;
  1879   std::vector<DrawTargetD2D::PushedClip>::iterator iter = mPushedClips.begin();
  1881   if (iter->mPath) {
  1882     pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
  1883   } else {
  1884     pathRect = iter->mBounds;
  1885     pathRectIsAxisAligned = iter->mIsPixelAligned;
  1888   iter++;
  1889   for (;iter != mPushedClips.end(); iter++) {
  1890     // Do nothing but add it to the current clip bounds.
  1891     if (!iter->mPath && iter->mIsPixelAligned) {
  1892       mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
  1893         IntRect(int32_t(iter->mBounds.left), int32_t(iter->mBounds.top),
  1894                 int32_t(iter->mBounds.right - iter->mBounds.left),
  1895                 int32_t(iter->mBounds.bottom - iter->mBounds.top)));
  1896       continue;
  1899     if (!pathGeom) {
  1900       if (pathRectIsAxisAligned) {
  1901         mCurrentClipBounds.IntersectRect(mCurrentClipBounds,
  1902           IntRect(int32_t(pathRect.left), int32_t(pathRect.top),
  1903                   int32_t(pathRect.right - pathRect.left),
  1904                   int32_t(pathRect.bottom - pathRect.top)));
  1906       if (iter->mPath) {
  1907         // See if pathRect needs to go into the path geometry.
  1908         if (!pathRectIsAxisAligned) {
  1909           pathGeom = ConvertRectToGeometry(pathRect);
  1910         } else {
  1911           pathGeom = GetTransformedGeometry(iter->mPath->GetGeometry(), iter->mTransform);
  1913       } else {
  1914         pathRect = IntersectRect(pathRect, iter->mBounds);
  1915         pathRectIsAxisAligned = false;
  1916         continue;
  1920     RefPtr<ID2D1PathGeometry> newGeom;
  1921     factory()->CreatePathGeometry(byRef(newGeom));
  1923     RefPtr<ID2D1GeometrySink> currentSink;
  1924     newGeom->Open(byRef(currentSink));
  1926     if (iter->mPath) {
  1927       pathGeom->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT,
  1928                                     iter->mTransform, currentSink);
  1929     } else {
  1930       RefPtr<ID2D1Geometry> rectGeom = ConvertRectToGeometry(iter->mBounds);
  1931       pathGeom->CombineWithGeometry(rectGeom, D2D1_COMBINE_MODE_INTERSECT,
  1932                                     D2D1::IdentityMatrix(), currentSink);
  1935     currentSink->Close();
  1937     pathGeom = newGeom.forget();
  1940   // For now we need mCurrentClippedGeometry to always be non-nullptr. This
  1941   // method might seem a little strange but it is just fine, if pathGeom is
  1942   // nullptr pathRect will always still contain 1 clip unaccounted for
  1943   // regardless of mCurrentClipBounds.
  1944   if (!pathGeom) {
  1945     pathGeom = ConvertRectToGeometry(pathRect);
  1947   mCurrentClippedGeometry = pathGeom.forget();
  1948   *aClipBounds = mCurrentClipBounds;
  1949   return mCurrentClippedGeometry;
  1952 TemporaryRef<ID2D1RenderTarget>
  1953 DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat)
  1955   HRESULT hr;
  1957   RefPtr<IDXGISurface> surface;
  1958   RefPtr<ID2D1RenderTarget> rt;
  1960   hr = aTexture->QueryInterface((IDXGISurface**)byRef(surface));
  1962   if (FAILED(hr)) {
  1963     gfxWarning() << "Failed to QI texture to surface.";
  1964     return nullptr;
  1967   D3D10_TEXTURE2D_DESC desc;
  1968   aTexture->GetDesc(&desc);
  1970   D2D1_ALPHA_MODE alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
  1972   if (aFormat == SurfaceFormat::B8G8R8X8 && aTexture == mTexture) {
  1973     alphaMode = D2D1_ALPHA_MODE_IGNORE;
  1976   D2D1_RENDER_TARGET_PROPERTIES props =
  1977     D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(desc.Format, alphaMode));
  1978   hr = factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt));
  1980   if (FAILED(hr)) {
  1981     gfxWarning() << "Failed to create D2D render target for texture.";
  1982     return nullptr;
  1985   return rt;
  1988 void
  1989 DrawTargetD2D::EnsureViews()
  1991   if (mTempTexture && mSRView && mRTView) {
  1992     return;
  1995   HRESULT hr;
  1997   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
  1998                              mSize.width,
  1999                              mSize.height,
  2000                              1, 1);
  2001   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  2003   hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mTempTexture));
  2005   if (FAILED(hr)) {
  2006     gfxWarning() << *this << "Failed to create temporary texture for rendertarget. Size: "
  2007       << mSize << " Code: " << hr;
  2008     return;
  2011   hr = mDevice->CreateShaderResourceView(mTempTexture, nullptr, byRef(mSRView));
  2013   if (FAILED(hr)) {
  2014     gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr;
  2015     return;
  2018   hr = mDevice->CreateRenderTargetView(mTexture, nullptr, byRef(mRTView));
  2020   if (FAILED(hr)) {
  2021     gfxWarning() << *this << "Failed to create rendertarget view for temp texture. Code: " << hr;
  2025 void
  2026 DrawTargetD2D::PopAllClips()
  2028   if (mClipsArePushed) {
  2029     PopClipsFromRT(mRT);
  2031     mClipsArePushed = false;
  2035 void
  2036 DrawTargetD2D::PushClipsToRT(ID2D1RenderTarget *aRT)
  2038   for (std::vector<PushedClip>::iterator iter = mPushedClips.begin();
  2039         iter != mPushedClips.end(); iter++) {
  2040     if (iter->mLayer) {
  2041       PushD2DLayer(aRT, iter->mPath->mGeometry, iter->mLayer, iter->mTransform);
  2042     } else {
  2043       aRT->PushAxisAlignedClip(iter->mBounds, iter->mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
  2048 void
  2049 DrawTargetD2D::PopClipsFromRT(ID2D1RenderTarget *aRT)
  2051   for (int i = mPushedClips.size() - 1; i >= 0; i--) {
  2052     if (mPushedClips[i].mLayer) {
  2053       aRT->PopLayer();
  2054     } else {
  2055       aRT->PopAxisAlignedClip();
  2060 void
  2061 DrawTargetD2D::EnsureClipMaskTexture(IntRect *aBounds)
  2063   if (mCurrentClipMaskTexture || mPushedClips.empty()) {
  2064     *aBounds = mCurrentClipBounds;
  2065     return;
  2068   RefPtr<ID2D1Geometry> geometry = GetClippedGeometry(aBounds);
  2070   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_A8_UNORM,
  2071                              mSize.width,
  2072                              mSize.height,
  2073                              1, 1);
  2074   desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
  2076   HRESULT hr = mDevice->CreateTexture2D(&desc, nullptr, byRef(mCurrentClipMaskTexture));
  2078   if (FAILED(hr)) {
  2079     gfxWarning() << "Failed to create texture for ClipMask!";
  2080     return;
  2083   RefPtr<ID2D1RenderTarget> rt = CreateRTForTexture(mCurrentClipMaskTexture, SurfaceFormat::A8);
  2085   if (!rt) {
  2086     gfxWarning() << "Failed to create RT for ClipMask!";
  2087     return;
  2090   RefPtr<ID2D1SolidColorBrush> brush;
  2091   rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), byRef(brush));
  2093   rt->BeginDraw();
  2094   rt->Clear(D2D1::ColorF(0, 0));
  2095   rt->FillGeometry(geometry, brush);
  2096   rt->EndDraw();
  2099 bool
  2100 DrawTargetD2D::FillGlyphsManual(ScaledFontDWrite *aFont,
  2101                                 const GlyphBuffer &aBuffer,
  2102                                 const Color &aColor,
  2103                                 IDWriteRenderingParams *aParams,
  2104                                 const DrawOptions &aOptions)
  2106   HRESULT hr;
  2108   RefPtr<IDWriteRenderingParams> params;
  2110   if (aParams) {
  2111     params = aParams;
  2112   } else {
  2113     mRT->GetTextRenderingParams(byRef(params));
  2116   DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
  2117   if (params) {
  2118     hr = aFont->mFontFace->GetRecommendedRenderingMode(
  2119       (FLOAT)aFont->GetSize(),
  2120       1.0f,
  2121       DWRITE_MEASURING_MODE_NATURAL,
  2122       params,
  2123       &renderMode);
  2124     if (FAILED(hr)) {
  2125       // this probably never happens, but let's play it safe
  2126       renderMode = DWRITE_RENDERING_MODE_DEFAULT;
  2130   // Deal with rendering modes CreateGlyphRunAnalysis doesn't accept.
  2131   switch (renderMode) {
  2132   case DWRITE_RENDERING_MODE_ALIASED:
  2133     // ClearType texture creation will fail in this mode, so bail out
  2134     return false;
  2135   case DWRITE_RENDERING_MODE_DEFAULT:
  2136     // As per DWRITE_RENDERING_MODE documentation, pick Natural for font
  2137     // sizes under 16 ppem
  2138     if (aFont->GetSize() < 16.0f) {
  2139       renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
  2140     } else {
  2141       renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
  2143     break;
  2144   case DWRITE_RENDERING_MODE_OUTLINE:
  2145     renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
  2146     break;
  2147   default:
  2148     break;
  2151   DWRITE_MEASURING_MODE measureMode =
  2152     renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
  2153     renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
  2154     DWRITE_MEASURING_MODE_NATURAL;
  2156   DWRITE_MATRIX mat = DWriteMatrixFromMatrix(mTransform);
  2158   AutoDWriteGlyphRun autoRun;
  2159   DWriteGlyphRunFromGlyphs(aBuffer, aFont, &autoRun);
  2161   RefPtr<IDWriteGlyphRunAnalysis> analysis;
  2162   hr = GetDWriteFactory()->CreateGlyphRunAnalysis(&autoRun, 1.0f, &mat,
  2163                                                   renderMode, measureMode, 0, 0, byRef(analysis));
  2165   if (FAILED(hr)) {
  2166     return false;
  2169   RECT bounds;
  2170   hr = analysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds);
  2172   if (bounds.bottom <= bounds.top || bounds.right <= bounds.left) {
  2173     // DWrite seems to do this sometimes. I'm not 100% sure why. See bug 758980.
  2174     gfxDebug() << "Empty alpha texture bounds! Falling back to regular drawing.";
  2175     return false;
  2177   IntRect rectBounds(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
  2178   IntRect surfBounds(IntPoint(0, 0), mSize);
  2180   rectBounds.IntersectRect(rectBounds, surfBounds);
  2182   if (rectBounds.IsEmpty()) {
  2183     // Nothing to do.
  2184     return true;
  2187   RefPtr<ID3D10Texture2D> tex = CreateTextureForAnalysis(analysis, rectBounds);
  2189   if (!tex) {
  2190     return false;
  2193   RefPtr<ID3D10ShaderResourceView> srView;
  2194   hr = mDevice->CreateShaderResourceView(tex, nullptr, byRef(srView));
  2196   if (FAILED(hr)) {
  2197     return false;
  2200   MarkChanged();
  2202   // Prepare our background texture for drawing.
  2203   PopAllClips();
  2204   mRT->Flush();
  2206   SetupStateForRendering();
  2208   ID3D10EffectTechnique *technique = mPrivateData->mEffect->GetTechniqueByName("SampleTextTexture");
  2210   mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()->
  2211     SetFloatVector(ShaderConstantRectD3D10(-1.0f + ((Float(rectBounds.x) / mSize.width) * 2.0f),
  2212                                            1.0f - (Float(rectBounds.y) / mSize.height * 2.0f),
  2213                                            (Float(rectBounds.width) / mSize.width) * 2.0f,
  2214                                            (-Float(rectBounds.height) / mSize.height) * 2.0f));
  2215   mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()->
  2216     SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  2217   FLOAT color[4] = { aColor.r, aColor.g, aColor.b, aColor.a };
  2218   mPrivateData->mEffect->GetVariableByName("TextColor")->AsVector()->
  2219     SetFloatVector(color);
  2221   mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
  2223   bool isMasking = false;
  2225   IntRect clipBoundsStorage;
  2226   IntRect *clipBounds = nullptr;
  2228   if (!mPushedClips.empty()) {
  2229     clipBounds = &clipBoundsStorage;
  2230     RefPtr<ID2D1Geometry> geom = GetClippedGeometry(clipBounds);
  2232     RefPtr<ID2D1RectangleGeometry> rectGeom;
  2233     factory()->CreateRectangleGeometry(D2D1::RectF(Float(rectBounds.x),
  2234                                                    Float(rectBounds.y),
  2235                                                    Float(rectBounds.width + rectBounds.x),
  2236                                                    Float(rectBounds.height + rectBounds.y)),
  2237                                        byRef(rectGeom));
  2239     D2D1_GEOMETRY_RELATION relation;
  2240     if (FAILED(geom->CompareWithGeometry(rectGeom, D2D1::IdentityMatrix(), &relation)) ||
  2241         relation != D2D1_GEOMETRY_RELATION_CONTAINS ) {
  2242       isMasking = true;
  2246   if (isMasking) {
  2247     clipBounds = &clipBoundsStorage;
  2248     EnsureClipMaskTexture(clipBounds);
  2250     RefPtr<ID3D10ShaderResourceView> srViewMask;
  2251     hr = mDevice->CreateShaderResourceView(mCurrentClipMaskTexture, nullptr, byRef(srViewMask));
  2253     if (FAILED(hr)) {
  2254       return false;
  2257     mPrivateData->mEffect->GetVariableByName("mask")->AsShaderResource()->SetResource(srViewMask);
  2259     mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
  2260       SetFloatVector(ShaderConstantRectD3D10(Float(rectBounds.x) / mSize.width, Float(rectBounds.y) / mSize.height,
  2261                                              Float(rectBounds.width) / mSize.width, Float(rectBounds.height) / mSize.height));
  2263     technique->GetPassByIndex(1)->Apply(0);
  2264   } else {
  2265     technique->GetPassByIndex(0)->Apply(0);
  2268   RefPtr<ID3D10RenderTargetView> rtView;
  2269   ID3D10RenderTargetView *rtViews;
  2270   mDevice->CreateRenderTargetView(mTexture, nullptr, byRef(rtView));
  2272   rtViews = rtView;
  2273   mDevice->OMSetRenderTargets(1, &rtViews, nullptr);
  2274   SetScissorToRect(clipBounds);
  2275   mDevice->Draw(4, 0);
  2276   return true;
  2279 TemporaryRef<ID2D1Brush>
  2280 DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
  2282   if (!IsPatternSupportedByD2D(aPattern)) {
  2283     RefPtr<ID2D1SolidColorBrush> colBrush;
  2284     mRT->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
  2285     return colBrush;
  2288   if (aPattern.GetType() == PatternType::COLOR) {
  2289     RefPtr<ID2D1SolidColorBrush> colBrush;
  2290     Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
  2291     mRT->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g,
  2292                                             color.b, color.a),
  2293                                D2D1::BrushProperties(aAlpha),
  2294                                byRef(colBrush));
  2295     return colBrush;
  2296   } else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
  2297     RefPtr<ID2D1LinearGradientBrush> gradBrush;
  2298     const LinearGradientPattern *pat =
  2299       static_cast<const LinearGradientPattern*>(&aPattern);
  2301     GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
  2303     if (!stops) {
  2304       gfxDebug() << "No stops specified for gradient pattern.";
  2305       return nullptr;
  2308     if (pat->mBegin == pat->mEnd) {
  2309       RefPtr<ID2D1SolidColorBrush> colBrush;
  2310       uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
  2311       vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
  2312       stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
  2313       mRT->CreateSolidColorBrush(d2dStops.back().color,
  2314                                  D2D1::BrushProperties(aAlpha),
  2315                                  byRef(colBrush));
  2316       return colBrush;
  2319     mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
  2320                                                                        D2DPoint(pat->mEnd)),
  2321                                    D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
  2322                                    stops->mStopCollection,
  2323                                    byRef(gradBrush));
  2324     return gradBrush;
  2325   } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
  2326     RefPtr<ID2D1RadialGradientBrush> gradBrush;
  2327     const RadialGradientPattern *pat =
  2328       static_cast<const RadialGradientPattern*>(&aPattern);
  2330     GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
  2332     if (!stops) {
  2333       gfxDebug() << "No stops specified for gradient pattern.";
  2334       return nullptr;
  2337     // This will not be a complex radial gradient brush.
  2338     mRT->CreateRadialGradientBrush(
  2339       D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2),
  2340                                           D2DPoint(pat->mCenter1 - pat->mCenter2),
  2341                                           pat->mRadius2, pat->mRadius2),
  2342       D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
  2343       stops->mStopCollection,
  2344       byRef(gradBrush));
  2346     return gradBrush;
  2347   } else if (aPattern.GetType() == PatternType::SURFACE) {
  2348     RefPtr<ID2D1BitmapBrush> bmBrush;
  2349     const SurfacePattern *pat =
  2350       static_cast<const SurfacePattern*>(&aPattern);
  2352     if (!pat->mSurface) {
  2353       gfxDebug() << "No source surface specified for surface pattern";
  2354       return nullptr;
  2357     RefPtr<ID2D1Bitmap> bitmap;
  2359     Matrix mat = pat->mMatrix;
  2361     switch (pat->mSurface->GetType()) {
  2362     case SurfaceType::D2D1_BITMAP:
  2364         SourceSurfaceD2D *surf = static_cast<SourceSurfaceD2D*>(pat->mSurface.get());
  2366         bitmap = surf->mBitmap;
  2368         if (!bitmap) {
  2369           return nullptr;
  2372       break;
  2373     case SurfaceType::D2D1_DRAWTARGET:
  2375         SourceSurfaceD2DTarget *surf =
  2376           static_cast<SourceSurfaceD2DTarget*>(pat->mSurface.get());
  2377         bitmap = surf->GetBitmap(mRT);
  2378         AddDependencyOnSource(surf);
  2380       break;
  2381     default:
  2383         RefPtr<DataSourceSurface> dataSurf = pat->mSurface->GetDataSurface();
  2384         if (!dataSurf) {
  2385           gfxWarning() << "Invalid surface type.";
  2386           return nullptr;
  2389         bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT); 
  2390         if (!bitmap) {
  2391           return nullptr;
  2394       break;
  2397     mRT->CreateBitmapBrush(bitmap,
  2398                            D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode),
  2399                                                        D2DExtend(pat->mExtendMode),
  2400                                                        D2DFilter(pat->mFilter)),
  2401                            D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
  2402                            byRef(bmBrush));
  2404     return bmBrush;
  2407   gfxWarning() << "Invalid pattern type detected.";
  2408   return nullptr;
  2411 TemporaryRef<ID3D10Texture2D>
  2412 DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops)
  2414   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 4096, 1, 1, 1);
  2416   std::vector<D2D1_GRADIENT_STOP> rawStops;
  2417   rawStops.resize(aStops->mStopCollection->GetGradientStopCount());
  2418   aStops->mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size());
  2420   std::vector<unsigned char> textureData;
  2421   textureData.resize(4096 * 4);
  2422   unsigned char *texData = &textureData.front();
  2424   float prevColorPos = 0;
  2425   float nextColorPos = 1.0f;
  2426   D2D1_COLOR_F prevColor = rawStops[0].color;
  2427   D2D1_COLOR_F nextColor = prevColor;
  2429   if (rawStops.size() >= 2) {
  2430     nextColor = rawStops[1].color;
  2431     nextColorPos = rawStops[1].position;
  2434   uint32_t stopPosition = 2;
  2436   // Not the most optimized way but this will do for now.
  2437   for (int i = 0; i < 4096; i++) {
  2438     // The 4095 seems a little counter intuitive, but we want the gradient
  2439     // color at offset 0 at the first pixel, and at offset 1.0f at the last
  2440     // pixel.
  2441     float pos = float(i) / 4095;
  2443     while (pos > nextColorPos) {
  2444       prevColor = nextColor;
  2445       prevColorPos = nextColorPos;
  2446       if (rawStops.size() > stopPosition) {
  2447         nextColor = rawStops[stopPosition].color;
  2448         nextColorPos = rawStops[stopPosition++].position;
  2449       } else {
  2450         nextColorPos = 1.0f;
  2454     float interp;
  2456     if (nextColorPos != prevColorPos) {
  2457       interp = (pos - prevColorPos) / (nextColorPos - prevColorPos);
  2458     } else {
  2459       interp = 0;
  2462     Color newColor(prevColor.r + (nextColor.r - prevColor.r) * interp,
  2463                     prevColor.g + (nextColor.g - prevColor.g) * interp,
  2464                     prevColor.b + (nextColor.b - prevColor.b) * interp,
  2465                     prevColor.a + (nextColor.a - prevColor.a) * interp);
  2467     texData[i * 4] = (char)(255.0f * newColor.b);
  2468     texData[i * 4 + 1] = (char)(255.0f * newColor.g);
  2469     texData[i * 4 + 2] = (char)(255.0f * newColor.r);
  2470     texData[i * 4 + 3] = (char)(255.0f * newColor.a);
  2473   D3D10_SUBRESOURCE_DATA data;
  2474   data.pSysMem = &textureData.front();
  2475   data.SysMemPitch = 4096 * 4;
  2477   RefPtr<ID3D10Texture2D> tex;
  2478   mDevice->CreateTexture2D(&desc, &data, byRef(tex));
  2480   return tex;
  2483 TemporaryRef<ID3D10Texture2D>
  2484 DrawTargetD2D::CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds)
  2486   HRESULT hr;
  2488   uint32_t bufferSize = aBounds.width * aBounds.height * 3;
  2490   RECT bounds;
  2491   bounds.left = aBounds.x;
  2492   bounds.top = aBounds.y;
  2493   bounds.right = aBounds.x + aBounds.width;
  2494   bounds.bottom = aBounds.y + aBounds.height;
  2496   // Add one byte so we can safely read a 32-bit int when copying the last
  2497   // 3 bytes.
  2498   BYTE *texture = new BYTE[bufferSize + 1];
  2499   hr = aAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &bounds, texture, bufferSize);
  2501   if (FAILED(hr)) {
  2502     delete [] texture;
  2503     return nullptr;
  2506   int alignedBufferSize = aBounds.width * aBounds.height * 4;
  2508   // Create a one-off immutable texture from system memory.
  2509   BYTE *alignedTextureData = new BYTE[alignedBufferSize];
  2510   for (int y = 0; y < aBounds.height; y++) {
  2511     for (int x = 0; x < aBounds.width; x++) {
  2512       // Copy 3 Bpp source to 4 Bpp destination memory used for
  2513       // texture creation. D3D10 has no 3 Bpp texture format we can
  2514       // use.
  2515       //
  2516       // Since we don't care what ends up in the alpha pixel of the
  2517       // destination, therefor we can simply copy a normal 32 bit
  2518       // integer each time, filling the alpha pixel of the destination
  2519       // with the first subpixel of the next pixel from the source.
  2520       *((int*)(alignedTextureData + (y * aBounds.width + x) * 4)) =
  2521         *((int*)(texture + (y * aBounds.width + x) * 3));
  2525   D3D10_SUBRESOURCE_DATA data;
  2527   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
  2528                              aBounds.width, aBounds.height,
  2529                              1, 1);
  2530   desc.Usage = D3D10_USAGE_IMMUTABLE;
  2532   data.SysMemPitch = aBounds.width * 4;
  2533   data.pSysMem = alignedTextureData;
  2535   RefPtr<ID3D10Texture2D> tex;
  2536   hr = mDevice->CreateTexture2D(&desc, &data, byRef(tex));
  2538   delete [] alignedTextureData;
  2539   delete [] texture;
  2541   if (FAILED(hr)) {
  2542     return nullptr;
  2545   return tex;
  2548 void
  2549 DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPattern)
  2551   mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->GetPassByIndex(0)->Apply(0);
  2552   mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
  2553     SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
  2555   float dimensions[] = { float(mSize.width), float(mSize.height), 0, 0 };
  2556   mPrivateData->mEffect->GetVariableByName("dimensions")->AsVector()->
  2557     SetFloatVector(dimensions);
  2559   const GradientStopsD2D *stops =
  2560     static_cast<const GradientStopsD2D*>(aPattern->mStops.get());
  2562   RefPtr<ID3D10Texture2D> tex = CreateGradientTexture(stops);
  2564   RefPtr<ID3D10ShaderResourceView> srView;
  2565   mDevice->CreateShaderResourceView(tex, nullptr, byRef(srView));
  2567   mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView);
  2569   Point dc = aPattern->mCenter2 - aPattern->mCenter1;
  2570   float dr = aPattern->mRadius2 - aPattern->mRadius1;
  2572   float diffv[] = { dc.x, dc.y, dr, 0 };
  2573   mPrivateData->mEffect->GetVariableByName("diff")->AsVector()->
  2574     SetFloatVector(diffv);
  2576   float center1[] = { aPattern->mCenter1.x, aPattern->mCenter1.y, dr, 0 };
  2577   mPrivateData->mEffect->GetVariableByName("center1")->AsVector()->
  2578     SetFloatVector(center1);
  2580   mPrivateData->mEffect->GetVariableByName("radius1")->AsScalar()->
  2581     SetFloat(aPattern->mRadius1);
  2582   mPrivateData->mEffect->GetVariableByName("sq_radius1")->AsScalar()->
  2583     SetFloat(pow(aPattern->mRadius1, 2));
  2585   Matrix invTransform = mTransform;
  2587   if (!invTransform.Invert()) {
  2588     // Bail if the matrix is singular.
  2589     return;
  2591   float matrix[] = { invTransform._11, invTransform._12, 0, 0,
  2592                       invTransform._21, invTransform._22, 0, 0,
  2593                       invTransform._31, invTransform._32, 1.0f, 0,
  2594                       0, 0, 0, 1.0f };
  2596   mPrivateData->mEffect->GetVariableByName("DeviceSpaceToUserSpace")->
  2597     AsMatrix()->SetMatrix(matrix);
  2599   float A = dc.x * dc.x + dc.y * dc.y - dr * dr;
  2601   uint32_t offset = 0;
  2602   switch (stops->mStopCollection->GetExtendMode()) {
  2603   case D2D1_EXTEND_MODE_WRAP:
  2604     offset = 1;
  2605     break;
  2606   case D2D1_EXTEND_MODE_MIRROR:
  2607     offset = 2;
  2608     break;
  2609   default:
  2610     gfxWarning() << "This shouldn't happen! Invalid extend mode for gradient stops.";
  2613   if (A == 0) {
  2614     mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
  2615       GetPassByIndex(offset * 2 + 1)->Apply(0);
  2616   } else {
  2617     mPrivateData->mEffect->GetVariableByName("A")->AsScalar()->SetFloat(A);
  2618     mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->
  2619       GetPassByIndex(offset * 2)->Apply(0);
  2623 void
  2624 DrawTargetD2D::SetupStateForRendering()
  2626   UINT stride = sizeof(Vertex);
  2627   UINT offset = 0;
  2628   ID3D10Buffer *buff = mPrivateData->mVB;
  2630   mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
  2631   mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset);
  2632   mDevice->IASetInputLayout(mPrivateData->mInputLayout);
  2634   D3D10_VIEWPORT viewport;
  2635   viewport.MaxDepth = 1;
  2636   viewport.MinDepth = 0;
  2637   viewport.Height = mSize.height;
  2638   viewport.Width = mSize.width;
  2639   viewport.TopLeftX = 0;
  2640   viewport.TopLeftY = 0;
  2642   mDevice->RSSetViewports(1, &viewport);
  2645 ID2D1Factory*
  2646 DrawTargetD2D::factory()
  2648   if (mFactory) {
  2649     return mFactory;
  2652   D2D1CreateFactoryFunc createD2DFactory;
  2653   HMODULE d2dModule = LoadLibraryW(L"d2d1.dll");
  2654   createD2DFactory = (D2D1CreateFactoryFunc)
  2655       GetProcAddress(d2dModule, "D2D1CreateFactory");
  2657   if (!createD2DFactory) {
  2658     gfxWarning() << "Failed to locate D2D1CreateFactory function.";
  2659     return nullptr;
  2662   D2D1_FACTORY_OPTIONS options;
  2663 #ifdef _DEBUG
  2664   options.debugLevel = D2D1_DEBUG_LEVEL_WARNING;
  2665 #else
  2666   options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
  2667 #endif
  2669   HRESULT hr = createD2DFactory(D2D1_FACTORY_TYPE_MULTI_THREADED,
  2670                                 __uuidof(ID2D1Factory),
  2671                                 &options,
  2672                                 (void**)&mFactory);
  2674   if (FAILED(hr)) {
  2675     gfxWarning() << "Failed to create Direct2D factory.";
  2678   return mFactory;
  2681 void
  2682 DrawTargetD2D::CleanupD2D()
  2684   if (mFactory) {
  2685     mFactory->Release();
  2686     mFactory = nullptr;
  2690 IDWriteFactory*
  2691 DrawTargetD2D::GetDWriteFactory()
  2693   if (mDWriteFactory) {
  2694     return mDWriteFactory;
  2697   decltype(DWriteCreateFactory)* createDWriteFactory;
  2698   HMODULE dwriteModule = LoadLibraryW(L"dwrite.dll");
  2699   createDWriteFactory = (decltype(DWriteCreateFactory)*)
  2700     GetProcAddress(dwriteModule, "DWriteCreateFactory");
  2702   if (!createDWriteFactory) {
  2703     gfxWarning() << "Failed to locate DWriteCreateFactory function.";
  2704     return nullptr;
  2707   HRESULT hr = createDWriteFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
  2708                                    reinterpret_cast<IUnknown**>(&mDWriteFactory));
  2710   if (FAILED(hr)) {
  2711     gfxWarning() << "Failed to create DWrite Factory.";
  2714   return mDWriteFactory;
  2717 void
  2718 DrawTargetD2D::SetScissorToRect(IntRect *aRect)
  2720   D3D10_RECT rect;
  2721   if (aRect) {
  2722     rect.left = aRect->x;
  2723     rect.right = aRect->XMost();
  2724     rect.top = aRect->y;
  2725     rect.bottom = aRect->YMost();
  2726   } else {
  2727     rect.left = rect.top = INT32_MIN;
  2728     rect.right = rect.bottom = INT32_MAX;
  2731   mDevice->RSSetScissorRects(1, &rect);
  2734 void
  2735 DrawTargetD2D::PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID2D1Layer *aLayer, const D2D1_MATRIX_3X2_F &aTransform)
  2737   D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
  2738   D2D1_LAYER_OPTIONS1 options1 =  D2D1_LAYER_OPTIONS1_NONE;
  2740   if (aRT->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
  2741     options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
  2742     options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
  2745 	RefPtr<ID2D1DeviceContext> dc;
  2746 	HRESULT hr = aRT->QueryInterface(IID_ID2D1DeviceContext, (void**)((ID2D1DeviceContext**)byRef(dc)));
  2748 	if (FAILED(hr)) {
  2749 	    aRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), aGeometry,
  2750 				                                   D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
  2751 				                                   1.0, nullptr, options),
  2752 				             aLayer);
  2753 	} else {
  2754 	    dc->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), aGeometry,
  2755 				                                   D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
  2756 				                                   1.0, nullptr, options1),
  2757 				            aLayer);

mercurial