void PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, Float aEndAngle, bool aAntiClockwise) { if (aAntiClockwise && aStartAngle < aEndAngle) { // D2D does things a little differently, and draws the arc by specifying an // beginning and an end point. This means the circle will be the wrong way // around if the start angle is smaller than the end angle. It might seem // tempting to invert aAntiClockwise but that would change the sweeping // direction of the arc to instead we exchange start/begin. Float oldStart = aStartAngle; aStartAngle = aEndAngle; aEndAngle = oldStart; } // XXX - Workaround for now, D2D does not appear to do the desired thing when // the angle sweeps a complete circle. if (aEndAngle - aStartAngle >= 2 * M_PI) { aEndAngle = Float(aStartAngle + M_PI * 1.9999); } else if (aStartAngle - aEndAngle >= 2 * M_PI) { aStartAngle = Float(aEndAngle + M_PI * 1.9999); } Point startPoint; startPoint.x = aOrigin.x + aRadius * cos(aStartAngle); startPoint.y = aOrigin.y + aRadius * sin(aStartAngle); if (!mFigureActive) { EnsureActive(startPoint); } else { mSink->AddLine(D2DPoint(startPoint)); } Point endPoint; endPoint.x = aOrigin.x + aRadius * cos(aEndAngle); endPoint.y = aOrigin.y + aRadius * sin(aEndAngle); D2D1_ARC_SIZE arcSize = D2D1_ARC_SIZE_SMALL; if (aAntiClockwise) { if (aStartAngle - aEndAngle > M_PI) { arcSize = D2D1_ARC_SIZE_LARGE; } } else { if (aEndAngle - aStartAngle > M_PI) { arcSize = D2D1_ARC_SIZE_LARGE; } } mSink->AddArc(D2D1::ArcSegment(D2DPoint(endPoint), D2D1::SizeF(aRadius, aRadius), 0.0f, aAntiClockwise ? D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE : D2D1_SWEEP_DIRECTION_CLOCKWISE, arcSize)); mCurrentPoint = endPoint; }
void PathBuilderD2D::QuadraticBezierTo(const Point &aCP1, const Point &aCP2) { EnsureActive(aCP1); mSink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(D2DPoint(aCP1), D2DPoint(aCP2))); mCurrentPoint = aCP2; }
void PathBuilderD2D::BezierTo(const Point &aCP1, const Point &aCP2, const Point &aCP3) { EnsureActive(aCP1); mSink->AddBezier(D2D1::BezierSegment(D2DPoint(aCP1), D2DPoint(aCP2), D2DPoint(aCP3))); mCurrentPoint = aCP3; }
void DrawTargetD2D1::StrokeLine(const Point &aStart, const Point &aEnd, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { PrepareForDrawing(aOptions.mCompositionOp, aPattern); RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); mDC->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle); FinalizeDrawing(aOptions.mCompositionOp, aPattern); }
void PathBuilderD2D::LineTo(const Point &aPoint) { EnsureActive(aPoint); mSink->AddLine(D2DPoint(aPoint)); mCurrentPoint = aPoint; }
void FilterNodeD2D1::SetAttribute(uint32_t aIndex, const IntPoint &aValue) { UINT32 input = GetD2D1PropForAttribute(mType, aIndex); MOZ_ASSERT(input < mEffect->GetPropertyCount()); mEffect->SetValue(input, D2DPoint(aValue)); }
void PathBuilderD2D::EnsureActive(const Point &aPoint) { if (!mFigureActive) { mSink->BeginFigure(D2DPoint(aPoint), D2D1_FIGURE_BEGIN_FILLED); mBeginPoint = aPoint; mFigureActive = true; } }
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; }
void DrawTargetD2D1::DrawFilter(FilterNode *aNode, const Rect &aSourceRect, const Point &aDestPoint, const DrawOptions &aOptions) { if (aNode->GetBackendType() != FILTER_BACKEND_DIRECT2D1_1) { gfxWarning() << *this << ": Incompatible filter passed to DrawFilter."; return; } PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color())); mDC->DrawImage(static_cast<FilterNodeD2D1*>(aNode)->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect)); }
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)); }
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 PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, Float aEndAngle, bool aAntiClockwise) { if (aAntiClockwise && aStartAngle < aEndAngle) { // D2D does things a little differently, and draws the arc by specifying an // beginning and an end point. This means the circle will be the wrong way // around if the start angle is smaller than the end angle. It might seem // tempting to invert aAntiClockwise but that would change the sweeping // direction of the arc so instead we exchange start/begin. Float oldStart = aStartAngle; aStartAngle = aEndAngle; aEndAngle = oldStart; } // XXX - Workaround for now, D2D does not appear to do the desired thing when // the angle sweeps a complete circle. bool fullCircle = false; if (aEndAngle - aStartAngle >= 2 * M_PI) { fullCircle = true; aEndAngle = Float(aStartAngle + M_PI * 1.9999); } else if (aStartAngle - aEndAngle >= 2 * M_PI) { fullCircle = true; aStartAngle = Float(aEndAngle + M_PI * 1.9999); } Point startPoint; startPoint.x = aOrigin.x + aRadius * cos(aStartAngle); startPoint.y = aOrigin.y + aRadius * sin(aStartAngle); if (!mFigureActive) { EnsureActive(startPoint); } else { mSink->AddLine(D2DPoint(startPoint)); } Point endPoint; endPoint.x = aOrigin.x + aRadius * cosf(aEndAngle); endPoint.y = aOrigin.y + aRadius * sinf(aEndAngle); D2D1_ARC_SIZE arcSize = D2D1_ARC_SIZE_SMALL; D2D1_SWEEP_DIRECTION direction = aAntiClockwise ? D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE : D2D1_SWEEP_DIRECTION_CLOCKWISE; // if startPoint and endPoint of our circle are too close there are D2D issues // with drawing the circle as a single arc const Float kEpsilon = 1e-5f; if (!fullCircle || (std::abs(startPoint.x - endPoint.x) + std::abs(startPoint.y - endPoint.y) > kEpsilon)) { if (aAntiClockwise) { if (aStartAngle - aEndAngle > M_PI) { arcSize = D2D1_ARC_SIZE_LARGE; } } else { if (aEndAngle - aStartAngle > M_PI) { arcSize = D2D1_ARC_SIZE_LARGE; } } mSink->AddArc(D2D1::ArcSegment(D2DPoint(endPoint), D2D1::SizeF(aRadius, aRadius), 0.0f, direction, arcSize)); } else { // our first workaround attempt didn't work, so instead draw the circle as // two half-circles Float midAngle = aEndAngle > aStartAngle ? Float(aStartAngle + M_PI) : Float(aEndAngle + M_PI); Point midPoint; midPoint.x = aOrigin.x + aRadius * cosf(midAngle); midPoint.y = aOrigin.y + aRadius * sinf(midAngle); mSink->AddArc(D2D1::ArcSegment(D2DPoint(midPoint), D2D1::SizeF(aRadius, aRadius), 0.0f, direction, arcSize)); // if the adjusted endPoint computed above is used here and endPoint != // startPoint then this half of the circle won't render... mSink->AddArc(D2D1::ArcSegment(D2DPoint(startPoint), D2D1::SizeF(aRadius, aRadius), 0.0f, direction, arcSize)); } mCurrentPoint = endPoint; }
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; }