Bug 1839490 - Add FillCircle to DrawTarget. r=lsalzman

This detects and forwards circles in DrawTargetRecording and also implements
StrokeCircle and FillCircle in D2D.

Differential Revision: https://phabricator.services.mozilla.com/D181559
This commit is contained in:
Jeff Muizelaar 2023-06-22 00:11:10 +00:00
parent e86f1fa0e9
commit 60eb91527f
7 changed files with 137 additions and 0 deletions

View File

@ -1578,6 +1578,17 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
virtual void Fill(const Path* aPath, const Pattern& aPattern,
const DrawOptions& aOptions = DrawOptions()) = 0;
/**
* Fill a circle on the DrawTarget with a certain source pattern.
*
* @param aCircle the parameters of the circle
* @param aPattern Pattern that forms the source of this stroking operation
* @param aOptions Options that are applied to this operation
*/
virtual void FillCircle(const Point& aOrigin, float radius,
const Pattern& aPattern,
const DrawOptions& aOptions = DrawOptions());
/**
* Fill a series of glyphs on the draw target with a certain source pattern.
*/

View File

@ -187,6 +187,13 @@ void DrawTarget::StrokeCircle(const Point& aOrigin, float radius,
Stroke(path, aPattern, aStrokeOptions, aOptions);
}
void DrawTarget::FillCircle(const Point& aOrigin, float radius,
const Pattern& aPattern,
const DrawOptions& aOptions) {
RefPtr<Path> path = MakePathForCircle(*this, aOrigin, radius);
Fill(path, aPattern, aOptions);
}
void DrawTarget::StrokeGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,

View File

@ -688,6 +688,41 @@ void DrawTargetD2D1::StrokeLine(const Point& aStart, const Point& aEnd,
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
}
void DrawTargetD2D1::StrokeCircle(const Point& aOrigin, float radius,
const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,
const DrawOptions& aOptions) {
if (!PrepareForDrawing(aOptions.mCompositionOp, aPattern)) {
return;
}
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions);
RefPtr<ID2D1StrokeStyle> strokeStyle =
CreateStrokeStyleForOptions(aStrokeOptions);
mDC->DrawEllipse(D2D1::Ellipse(D2DPoint(aOrigin), radius, radius), brush,
aStrokeOptions.mLineWidth, strokeStyle);
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
}
void DrawTargetD2D1::FillCircle(const Point& aOrigin, float radius,
const Pattern& aPattern,
const DrawOptions& aOptions) {
if (!PrepareForDrawing(aOptions.mCompositionOp, aPattern)) {
return;
}
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aPattern, aOptions);
mDC->FillEllipse(D2D1::Ellipse(D2DPoint(aOrigin), radius, radius), brush);
FinalizeDrawing(aOptions.mCompositionOp, aPattern);
}
void DrawTargetD2D1::Stroke(const Path* aPath, const Pattern& aPattern,
const StrokeOptions& aStrokeOptions,

View File

@ -79,11 +79,18 @@ class DrawTargetD2D1 : public DrawTarget {
const Pattern& aPattern,
const StrokeOptions& aStrokeOptions = StrokeOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void StrokeCircle(
const Point& aOrigin, float radius, const Pattern& aPattern,
const StrokeOptions& aStrokeOptions = StrokeOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void Stroke(const Path* aPath, const Pattern& aPattern,
const StrokeOptions& aStrokeOptions = StrokeOptions(),
const DrawOptions& aOptions = DrawOptions()) override;
virtual void Fill(const Path* aPath, const Pattern& aPattern,
const DrawOptions& aOptions = DrawOptions()) override;
virtual void FillCircle(const Point& aOrigin, float radius,
const Pattern& aPattern,
const DrawOptions& aOptions = DrawOptions()) override;
virtual void FillGlyphs(ScaledFont* aFont, const GlyphBuffer& aBuffer,
const Pattern& aPattern,
const DrawOptions& aOptions = DrawOptions()) override;

View File

@ -252,6 +252,17 @@ void DrawTargetRecording::Fill(const Path* aPath, const Pattern& aPattern,
return;
}
if (aPath->GetBackendType() == BackendType::RECORDING) {
const PathRecording* path = static_cast<const PathRecording*>(aPath);
auto circle = path->AsCircle();
if (circle && true) {
EnsurePatternDependenciesStored(aPattern);
mRecorder->RecordEvent(
RecordedFillCircle(this, circle.value(), aPattern, aOptions));
return;
}
}
RefPtr<PathRecording> pathRecording = EnsurePathStored(aPath);
EnsurePatternDependenciesStored(aPattern);

View File

@ -369,6 +369,7 @@ class RecordedEvent {
PUSHCLIPRECT,
POPCLIP,
FILL,
FILLCIRCLE,
FILLGLYPHS,
MASK,
STROKE,

View File

@ -369,6 +369,36 @@ class RecordedFill : public RecordedDrawingEvent<RecordedFill> {
DrawOptions mOptions;
};
class RecordedFillCircle : public RecordedDrawingEvent<RecordedFillCircle> {
public:
RecordedFillCircle(DrawTarget* aDT, Circle aCircle, const Pattern& aPattern,
const DrawOptions& aOptions)
: RecordedDrawingEvent(FILLCIRCLE, aDT),
mCircle(aCircle),
mPattern(),
mOptions(aOptions) {
StorePattern(mPattern, aPattern);
}
bool PlayEvent(Translator* aTranslator) const override;
template <class S>
void Record(S& aStream) const;
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "FillCircle"; }
private:
friend class RecordedEvent;
template <class S>
MOZ_IMPLICIT RecordedFillCircle(S& aStream);
Circle mCircle;
PatternStorage mPattern;
DrawOptions mOptions;
};
class RecordedFillGlyphs : public RecordedDrawingEvent<RecordedFillGlyphs> {
public:
RecordedFillGlyphs(DrawTarget* aDT, ReferencePtr aScaledFont,
@ -2447,6 +2477,40 @@ inline void RecordedFill::OutputSimpleEventInfo(
OutputSimplePatternInfo(mPattern, aStringStream);
}
inline bool RecordedFillCircle::PlayEvent(Translator* aTranslator) const {
DrawTarget* dt = aTranslator->LookupDrawTarget(mDT);
if (!dt) {
return false;
}
dt->FillCircle(mCircle.origin, mCircle.radius,
*GenericPattern(mPattern, aTranslator), mOptions);
return true;
}
template <class S>
void RecordedFillCircle::Record(S& aStream) const {
RecordedDrawingEvent::Record(aStream);
WriteElement(aStream, mCircle);
WriteElement(aStream, mOptions);
RecordPatternData(aStream, mPattern);
}
template <class S>
RecordedFillCircle::RecordedFillCircle(S& aStream)
: RecordedDrawingEvent(FILLCIRCLE, aStream) {
ReadElement(aStream, mCircle);
ReadDrawOptions(aStream, mOptions);
ReadPatternData(aStream, mPattern);
}
inline void RecordedFillCircle::OutputSimpleEventInfo(
std::stringstream& aStringStream) const {
aStringStream << "[" << mDT << "] StrokeCircle (" << mCircle.origin.x << ", "
<< mCircle.origin.y << " - " << mCircle.radius << ")";
OutputSimplePatternInfo(mPattern, aStringStream);
}
inline RecordedFillGlyphs::~RecordedFillGlyphs() { delete[] mGlyphs; }
inline bool RecordedFillGlyphs::PlayEvent(Translator* aTranslator) const {
@ -4072,6 +4136,7 @@ inline void RecordedDestination::OutputSimpleEventInfo(
f(PUSHCLIP, RecordedPushClip); \
f(POPCLIP, RecordedPopClip); \
f(FILL, RecordedFill); \
f(FILLCIRCLE, RecordedFillCircle); \
f(FILLGLYPHS, RecordedFillGlyphs); \
f(MASK, RecordedMask); \
f(STROKE, RecordedStroke); \