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); } }
already_AddRefed<PathBuilder> PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const { RefPtr<ID2D1PathGeometry> path; HRESULT hr = DrawTargetD2D1::factory()->CreatePathGeometry(getter_AddRefs(path)); if (FAILED(hr)) { gfxWarning() << "Failed to create PathGeometry. Code: " << hexa(hr); return nullptr; } RefPtr<ID2D1GeometrySink> sink; hr = path->Open(getter_AddRefs(sink)); if (FAILED(hr)) { gfxWarning() << "Failed to open Geometry for writing. Code: " << hexa(hr); return nullptr; } if (aFillRule == FillRule::FILL_WINDING) { sink->SetFillMode(D2D1_FILL_MODE_WINDING); } if (mEndedActive) { OpeningGeometrySink wrapSink(sink); hr = mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, D2DMatrix(aTransform), &wrapSink); } else { hr = mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, D2DMatrix(aTransform), sink); } if (FAILED(hr)) { gfxWarning() << "Failed to simplify PathGeometry to tranformed copy. Code: " << hexa(hr) << " Active: " << mEndedActive; return nullptr; } RefPtr<PathBuilderD2D> pathBuilder = new PathBuilderD2D(sink, path, aFillRule, mBackendType); pathBuilder->mCurrentPoint = aTransform.TransformPoint(mEndPoint); if (mEndedActive) { pathBuilder->mFigureActive = true; } return pathBuilder.forget(); }
void FilterNodeD2D1::SetAttribute(uint32_t aIndex, const Matrix &aMatrix) { UINT32 input = GetD2D1PropForAttribute(mType, aIndex); MOZ_ASSERT(input < mEffect->GetPropertyCount()); mEffect->SetValue(input, D2DMatrix(aMatrix)); }
bool PathD2D::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const { BOOL result; HRESULT hr = mGeometry->FillContainsPoint(D2DPoint(aPoint), D2DMatrix(aTransform), 0.001f, &result); if (FAILED(hr)) { // Log return false; } return !!result; }
Rect PathD2D::GetBounds(const Matrix &aTransform) const { D2D1_RECT_F d2dBounds; HRESULT hr = mGeometry->GetBounds(D2DMatrix(aTransform), &d2dBounds); Rect bounds = ToRect(d2dBounds); if (FAILED(hr) || !bounds.IsFinite()) { gfxWarning() << "Failed to get stroked bounds for path. Code: " << hexa(hr); return Rect(); } return bounds; }
Rect PathD2D::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { D2D1_RECT_F d2dBounds; RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); HRESULT hr = mGeometry->GetWidenedBounds(aStrokeOptions.mLineWidth, strokeStyle, D2DMatrix(aTransform), &d2dBounds); Rect bounds = ToRect(d2dBounds); if (FAILED(hr) || !bounds.IsFinite()) { gfxWarning() << "Failed to get stroked bounds for path. Code: " << hexa(hr); return Rect(); } return bounds; }
void DrawTargetD2D1::DrawSurface(SourceSurface *aSurface, const Rect &aDest, const Rect &aSource, const DrawSurfaceOptions &aSurfOptions, const DrawOptions &aOptions) { RefPtr<ID2D1Image> image = GetImageForSurface(aSurface, ExtendMode::CLAMP); if (!image) { gfxWarning() << *this << ": Unable to get D2D image for surface."; return; } PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color())); D2D1_RECT_F samplingBounds; if (aSurfOptions.mSamplingBounds == SamplingBounds::BOUNDED) { samplingBounds = D2DRect(aSource); } else { samplingBounds = D2D1::RectF(0, 0, Float(aSurface->GetSize().width), Float(aSurface->GetSize().height)); } Float xScale = aDest.width / aSource.width; Float yScale = aDest.height / aSource.height; RefPtr<ID2D1ImageBrush> brush; // Here we scale the source pattern up to the size and position where we want // it to be. Matrix transform; transform.Translate(aDest.x, aDest.y); transform.Scale(xScale, yScale); mDC->CreateImageBrush(image, D2D1::ImageBrushProperties(samplingBounds), D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(transform)), byRef(brush)); mDC->FillRectangle(D2DRect(aDest), brush); FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color())); }
bool PathD2D::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, const Point &aPoint, const Matrix &aTransform) const { BOOL result; RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); HRESULT hr = mGeometry->StrokeContainsPoint(D2DPoint(aPoint), aStrokeOptions.mLineWidth, strokeStyle, D2DMatrix(aTransform), &result); if (FAILED(hr)) { // Log return false; } return !!result; }
void DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern) { bool patternSupported = IsPatternSupportedByD2D(aPattern); if (aOp == CompositionOp::OP_OVER && patternSupported) { return; } RefPtr<ID2D1Image> image; mDC->GetTarget(byRef(image)); mDC->SetTarget(mBitmap); if (patternSupported) { mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp)); return; } mDC->SetTransform(D2D1::IdentityMatrix()); mTransformDirty = true; RefPtr<ID2D1Effect> radialGradientEffect; mDC->CreateEffect(CLSID_RadialGradientEffect, byRef(radialGradientEffect)); const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern); radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION, static_cast<const GradientStopsD2D*>(pat->mStops.get())->mStopCollection); radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y)); radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y)); radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1); radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2); radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2); radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform)); radialGradientEffect->SetInput(0, image); mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp)); }
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; }