gfx/2d/DrawTargetD2D.cpp

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

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

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

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

mercurial