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