TemporaryRef<DrawTarget> Factory::CreateDrawTargetForData(BackendType aBackend, unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) { switch (aBackend) { #ifdef USE_SKIA case BACKEND_SKIA: { RefPtr<DrawTargetSkia> newTarget; newTarget = new DrawTargetSkia(); newTarget->Init(aData, aSize, aStride, aFormat); return newTarget; } #endif default: gfxDebug() << "Invalid draw target type specified."; return NULL; } gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize; // Failed return NULL; }
MemoryTextureData* MemoryTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags, ClientIPCAllocator* aAllocator) { // Should have used CreateForYCbCr. MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV); if (aSize.width <= 0 || aSize.height <= 0) { gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height; return nullptr; } uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat); if (!bufSize) { return nullptr; } uint8_t* buf = new (fallible) uint8_t[bufSize]; if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags)) { return nullptr; } auto fwd = aAllocator ? aAllocator->AsCompositableForwarder() : nullptr; bool hasIntermediateBuffer = fwd ? ComputeHasIntermediateBuffer(aFormat, fwd->GetCompositorBackendType()) : true; GfxMemoryImageReporter::DidAlloc(buf); BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat, hasIntermediateBuffer); return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize); }
already_AddRefed<DataSourceSurface> SourceSurfaceD2DTarget::GetDataSurface() { RefPtr<DataSourceSurfaceD2DTarget> dataSurf = new DataSourceSurfaceD2DTarget(mFormat); D3D10_TEXTURE2D_DESC desc; mTexture->GetDesc(&desc); desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; desc.Usage = D3D10_USAGE_STAGING; desc.BindFlags = 0; desc.MiscFlags = 0; if (!Factory::GetDirect3D10Device()) { gfxCriticalError() << "Invalid D3D10 device in D2D target surface"; return nullptr; } HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture)); if (FAILED(hr)) { gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hexa(hr); return nullptr; } Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); return dataSurf.forget(); }
void DrawTargetD2D1::PushClip(const Path *aPath) { if (aPath->GetBackendType() != BackendType::DIRECT2D) { gfxDebug() << *this << ": Ignoring clipping call for incompatible path."; return; } RefPtr<PathD2D> pathD2D = static_cast<PathD2D*>(const_cast<Path*>(aPath)); PushedClip clip; clip.mTransform = D2DMatrix(mTransform); clip.mPath = pathD2D; pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds); mPushedClips.push_back(clip); // The transform of clips is relative to the world matrix, since we use the total // transform for the clips, make the world matrix identity. mDC->SetTransform(D2D1::IdentityMatrix()); mTransformDirty = true; if (mClipsArePushed) { PushD2DLayer(mDC, pathD2D->mGeometry, clip.mTransform); } }
MemoryTextureData* MemoryTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend, LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags, LayersIPCChannel* aAllocator) { // Should have used CreateForYCbCr. MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV); if (aSize.width <= 0 || aSize.height <= 0) { gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height; return nullptr; } uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat); if (!bufSize) { return nullptr; } uint8_t* buf = new (fallible) uint8_t[bufSize]; if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, false)) { return nullptr; } bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat, aLayersBackend); GfxMemoryImageReporter::DidAlloc(buf); BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat, hasIntermediateBuffer); return new MemoryTextureData(descriptor, aMoz2DBackend, buf, bufSize); }
static bool InitBuffer(uint8_t* buf, size_t bufSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aAllocFlags, bool aAlreadyZero) { if (!buf) { gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes"; return false; } if ((aAllocFlags & ALLOC_CLEAR_BUFFER) || (aAllocFlags & ALLOC_CLEAR_BUFFER_BLACK)) { if (aFormat == gfx::SurfaceFormat::B8G8R8X8) { // Even though BGRX was requested, XRGB_UINT32 is what is meant, // so use 0xFF000000 to put alpha in the right place. libyuv::ARGBRect(buf, bufSize, 0, 0, bufSize / sizeof(uint32_t), 1, 0xFF000000); } else if (!aAlreadyZero) { memset(buf, 0, bufSize); } } if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) { memset(buf, 0xFF, bufSize); } return true; }
bool SourceSurfaceD2D::InitFromData(unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, ID2D1RenderTarget *aRT) { HRESULT hr; mFormat = aFormat; mSize = aSize; if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() || (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) { gfxDebug() << "Bitmap does not fit in texture."; return false; } D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap)); if (FAILED(hr)) { gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hr; return false; } DrawTargetD2D::mVRAMUsageSS += GetByteSize(); mDevice = Factory::GetDirect3D10Device(); return true; }
X11TextureData* X11TextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, TextureFlags aFlags, LayersIPCChannel* aAllocator) { MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0); if (aSize.width <= 0 || aSize.height <= 0 || aSize.width > XLIB_IMAGE_SIDE_SIZE_LIMIT || aSize.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) { gfxDebug() << "Asking for X11 surface of invalid size " << aSize.width << "x" << aSize.height; return nullptr; } gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aFormat); RefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, imageFormat); if (!surface || surface->GetType() != gfxSurfaceType::Xlib) { NS_ERROR("creating Xlib surface failed!"); return nullptr; } gfxXlibSurface* xlibSurface = static_cast<gfxXlibSurface*>(surface.get()); bool crossProcess = !aAllocator->IsSameProcess(); X11TextureData* texture = new X11TextureData( aSize, aFormat, !!(aFlags & TextureFlags::DEALLOCATE_CLIENT), crossProcess, xlibSurface); if (crossProcess) { FinishX(DefaultXDisplay()); } return texture; }
TemporaryRef<DrawTarget> Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat) { switch (aBackend) { #ifdef WIN32 case BACKEND_DIRECT2D: { RefPtr<DrawTargetD2D> newTarget; newTarget = new DrawTargetD2D(); if (newTarget->Init(aSize, aFormat)) { return newTarget; } break; } #elif defined XP_MACOSX || defined ANDROID || defined LINUX #ifdef USE_SKIA case BACKEND_SKIA: { RefPtr<DrawTargetSkia> newTarget; newTarget = new DrawTargetSkia(); if (newTarget->Init(aSize, aFormat)) { return newTarget; } break; } #endif #ifdef XP_MACOSX case BACKEND_COREGRAPHICS: { RefPtr<DrawTargetCG> newTarget; newTarget = new DrawTargetCG(); if (newTarget->Init(aSize, aFormat)) { return newTarget; } break; } #endif #endif default: gfxDebug() << "Invalid draw target type specified."; return NULL; } gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize; // Failed return NULL; }
TemporaryRef<SourceSurface> DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) const { RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia(); if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize; return nullptr; } return newSurf; }
// Minimum required shmem size in bytes size_t YCbCrImageDataDeserializerBase::ComputeMinBufferSize(const gfx::IntSize& aYSize, uint32_t aYStride, const gfx::IntSize& aCbCrSize, uint32_t aCbCrStride) { MOZ_ASSERT(aYSize.height >= 0 && aYSize.width >= 0); if (aYSize.height <= 0 || aYSize.width <= 0 || aCbCrSize.height <= 0 || aCbCrSize.width <= 0) { gfxDebug() << "Non-positive YCbCr buffer size request " << aYSize.height << "x" << aYSize.width << ", " << aCbCrSize.height << "x" << aCbCrSize.width; return 0; } return ComputeOffset(aYSize.height, aYStride) + 2 * ComputeOffset(aCbCrSize.height, aCbCrStride) + MOZ_ALIGN_WORD(sizeof(YCbCrBufferInfo)); }
TemporaryRef<Path> PathBuilderD2D::Finish() { if (mFigureActive) { mSink->EndFigure(D2D1_FIGURE_END_OPEN); } HRESULT hr = mSink->Close(); if (FAILED(hr)) { gfxDebug() << "Failed to close PathSink. Code: " << hr; return nullptr; } return new PathD2D(mGeometry, mFigureActive, mCurrentPoint, mFillRule); }
ShmemTextureData* ShmemTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat, gfx::BackendType aMoz2DBackend, LayersBackend aLayersBackend, TextureFlags aFlags, TextureAllocationFlags aAllocFlags, ClientIPCAllocator* aAllocator) { MOZ_ASSERT(aAllocator); // Should have used CreateForYCbCr. MOZ_ASSERT(aFormat != gfx::SurfaceFormat::YUV); if (!aAllocator || !aAllocator->AsShmemAllocator()) { return nullptr; } if (aSize.width <= 0 || aSize.height <= 0) { gfxDebug() << "Asking for buffer of invalid size " << aSize.width << "x" << aSize.height; return nullptr; } uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat); if (!bufSize) { return nullptr; } mozilla::ipc::Shmem shm; if (!aAllocator->AsShmemAllocator()->AllocUnsafeShmem(bufSize, OptimalShmemType(), &shm)) { return nullptr; } uint8_t* buf = shm.get<uint8_t>(); if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags, true)) { return nullptr; } // LAYERS_NONE must imply that we have no compositable forwarder MOZ_ASSERT_IF(aLayersBackend == LayersBackend::LAYERS_NONE, !aAllocator || !aAllocator->AsCompositableForwarder()); bool hasIntermediateBuffer = ComputeHasIntermediateBuffer(aFormat, aLayersBackend); BufferDescriptor descriptor = RGBDescriptor(aSize, aFormat, hasIntermediateBuffer); return new ShmemTextureData(descriptor, aMoz2DBackend, shm); return nullptr; }
void DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface, const Point &aDest, const Color &aColor, const Point &aOffset, Float aSigma, CompositionOp aOperator) { MarkChanged(); mDC->SetTransform(D2D1::IdentityMatrix()); mTransformDirty = true; Matrix mat; RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP); if (!mat.IsIdentity()) { gfxDebug() << *this << ": At this point complex partial uploads are not supported for Shadow surfaces."; return; } // Step 1, create the shadow effect. RefPtr<ID2D1Effect> shadowEffect; mDC->CreateEffect(CLSID_D2D1Shadow, byRef(shadowEffect)); shadowEffect->SetInput(0, image); shadowEffect->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, aSigma); D2D1_VECTOR_4F color = { aColor.r, aColor.g, aColor.b, aColor.a }; shadowEffect->SetValue(D2D1_SHADOW_PROP_COLOR, color); // Step 2, move the shadow effect into place. RefPtr<ID2D1Effect> affineTransformEffect; mDC->CreateEffect(CLSID_D2D12DAffineTransform, byRef(affineTransformEffect)); affineTransformEffect->SetInputEffect(0, shadowEffect); D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation(aOffset.x, aOffset.y); affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix); // Step 3, create an effect that combines shadow and bitmap in one image. RefPtr<ID2D1Effect> compositeEffect; mDC->CreateEffect(CLSID_D2D1Composite, byRef(compositeEffect)); compositeEffect->SetInputEffect(0, affineTransformEffect); compositeEffect->SetInput(1, image); compositeEffect->SetValue(D2D1_COMPOSITE_PROP_MODE, D2DCompositionMode(aOperator)); D2D1_POINT_2F surfPoint = D2DPoint(aDest); mDC->DrawImage(compositeEffect, &surfPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR, D2DCompositionMode(aOperator)); }
void DrawTargetD2D1::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aOptions) { if (aPath->GetBackendType() != BackendType::DIRECT2D) { gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; return; } const PathD2D *d2dPath = static_cast<const PathD2D*>(aPath); PrepareForDrawing(aOptions.mCompositionOp, aPattern); RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); mDC->FillGeometry(d2dPath->mGeometry, brush); FinalizeDrawing(aOptions.mCompositionOp, aPattern); }
void DrawTargetD2D1::CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect, const IntPoint &aDestination) { MarkChanged(); mDC->SetTransform(D2D1::IdentityMatrix()); mTransformDirty = true; Matrix mat; RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, mat, ExtendMode::CLAMP); if (!mat.IsIdentity()) { gfxDebug() << *this << ": At this point complex partial uploads are not supported for CopySurface."; return; } mDC->DrawImage(image, D2D1::Point2F(Float(aDestination.x), Float(aDestination.y)), D2D1::RectF(Float(aSourceRect.x), Float(aSourceRect.y), Float(aSourceRect.XMost()), Float(aSourceRect.YMost())), D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY); }
void DrawTargetSkia::DrawSurface(SourceSurface *aSurface, const Rect &aDest, const Rect &aSource, const DrawSurfaceOptions &aSurfOptions, const DrawOptions &aOptions) { RefPtr<SourceSurface> dataSurface; if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) { dataSurface = aSurface->GetDataSurface(); if (!dataSurface) { gfxDebug() << *this << ": DrawSurface() can't draw surface"; return; } aSurface = dataSurface.get(); } if (aSource.IsEmpty()) { return; } MarkChanged(); SkRect destRect = RectToSkRect(aDest); SkRect sourceRect = RectToSkRect(aSource); TempBitmap bitmap = GetBitmapForSurface(aSurface); AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest); if (aSurfOptions.mFilter == Filter::POINT) { paint.mPaint.setFilterLevel(SkPaint::kNone_FilterLevel); } mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint); }
TemporaryRef<DataSourceSurface> SourceSurfaceD2DTarget::GetDataSurface() { RefPtr<DataSourceSurfaceD2DTarget> dataSurf = new DataSourceSurfaceD2DTarget(); D3D10_TEXTURE2D_DESC desc; mTexture->GetDesc(&desc); desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; desc.Usage = D3D10_USAGE_STAGING; desc.BindFlags = 0; desc.MiscFlags = 0; HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture)); if (FAILED(hr)) { gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hr; return nullptr; } Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); return dataSurf; }
TemporaryRef<ID2D1Brush> DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) { if (!IsPatternSupportedByD2D(aPattern)) { RefPtr<ID2D1SolidColorBrush> colBrush; mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush)); return colBrush; } if (aPattern.GetType() == PatternType::COLOR) { RefPtr<ID2D1SolidColorBrush> colBrush; Color color = static_cast<const ColorPattern*>(&aPattern)->mColor; mDC->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g, color.b, color.a), D2D1::BrushProperties(aAlpha), byRef(colBrush)); return colBrush; } else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) { RefPtr<ID2D1LinearGradientBrush> gradBrush; const LinearGradientPattern *pat = static_cast<const LinearGradientPattern*>(&aPattern); GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get()); if (!stops) { gfxDebug() << "No stops specified for gradient pattern."; return nullptr; } if (pat->mBegin == pat->mEnd) { RefPtr<ID2D1SolidColorBrush> colBrush; uint32_t stopCount = stops->mStopCollection->GetGradientStopCount(); vector<D2D1_GRADIENT_STOP> d2dStops(stopCount); stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount); mDC->CreateSolidColorBrush(d2dStops.back().color, D2D1::BrushProperties(aAlpha), byRef(colBrush)); return colBrush; } mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin), D2DPoint(pat->mEnd)), D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), stops->mStopCollection, byRef(gradBrush)); return gradBrush; } else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) { RefPtr<ID2D1RadialGradientBrush> gradBrush; const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern); GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get()); if (!stops) { gfxDebug() << "No stops specified for gradient pattern."; return nullptr; } // This will not be a complex radial gradient brush. mDC->CreateRadialGradientBrush( D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter2), D2DPoint(pat->mCenter1 - pat->mCenter2), pat->mRadius2, pat->mRadius2), D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)), stops->mStopCollection, byRef(gradBrush)); return gradBrush; } else if (aPattern.GetType() == PatternType::SURFACE) { const SurfacePattern *pat = static_cast<const SurfacePattern*>(&aPattern); if (!pat->mSurface) { gfxDebug() << "No source surface specified for surface pattern"; return nullptr; } Matrix mat = pat->mMatrix; RefPtr<ID2D1ImageBrush> imageBrush; RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode); mDC->CreateImageBrush(image, D2D1::ImageBrushProperties(D2D1::RectF(0, 0, Float(pat->mSurface->GetSize().width), Float(pat->mSurface->GetSize().height)), D2DExtend(pat->mExtendMode), D2DExtend(pat->mExtendMode), D2DInterpolationMode(pat->mFilter)), D2D1::BrushProperties(aAlpha, D2DMatrix(mat)), byRef(imageBrush)); return imageBrush; } gfxWarning() << "Invalid pattern type detected."; return nullptr; }
void DrawTargetD2D1::FillGlyphs(ScaledFont *aFont, const GlyphBuffer &aBuffer, const Pattern &aPattern, const DrawOptions &aOptions, const GlyphRenderingOptions *aRenderingOptions) { if (aFont->GetType() != FontType::DWRITE) { gfxDebug() << *this << ": Ignoring drawing call for incompatible font."; return; } ScaledFontDWrite *font = static_cast<ScaledFontDWrite*>(aFont); IDWriteRenderingParams *params = nullptr; if (aRenderingOptions) { if (aRenderingOptions->GetType() != FontType::DWRITE) { gfxDebug() << *this << ": Ignoring incompatible GlyphRenderingOptions."; // This should never happen. MOZ_ASSERT(false); } else { params = static_cast<const GlyphRenderingOptionsDWrite*>(aRenderingOptions)->mParams; } } AntialiasMode aaMode = font->GetDefaultAAMode(); if (aOptions.mAntialiasMode != AntialiasMode::DEFAULT) { aaMode = aOptions.mAntialiasMode; } PrepareForDrawing(aOptions.mCompositionOp, aPattern); bool forceClearType = false; if (mFormat == SurfaceFormat::B8G8R8A8 && mPermitSubpixelAA && aOptions.mCompositionOp == CompositionOp::OP_OVER && aaMode == AntialiasMode::SUBPIXEL) { forceClearType = true; } D2D1_TEXT_ANTIALIAS_MODE d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; switch (aaMode) { case AntialiasMode::NONE: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; break; case AntialiasMode::GRAY: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; break; case AntialiasMode::SUBPIXEL: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; break; default: d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; } if (d2dAAMode == D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE && mFormat != SurfaceFormat::B8G8R8X8 && !forceClearType) { d2dAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; } mDC->SetTextAntialiasMode(d2dAAMode); if (params != mTextRenderingParams) { mDC->SetTextRenderingParams(params); mTextRenderingParams = params; } RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); AutoDWriteGlyphRun autoRun; DWriteGlyphRunFromGlyphs(aBuffer, font, &autoRun); if (brush) { mDC->DrawGlyphRun(D2D1::Point2F(), &autoRun, brush); } FinalizeDrawing(aOptions.mCompositionOp, aPattern); }