gecko-dev/gfx/2d/PathCapture.cpp

219 строки
6.7 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PathCapture.h"
namespace mozilla {
namespace gfx {
void PathBuilderCapture::MoveTo(const Point& aPoint) {
PathOp op;
op.mType = PathOp::OP_MOVETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mCurrentPoint = aPoint;
mBeginPoint = aPoint;
}
void PathBuilderCapture::LineTo(const Point& aPoint) {
PathOp op;
op.mType = PathOp::OP_LINETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mCurrentPoint = aPoint;
}
void PathBuilderCapture::BezierTo(const Point& aCP1, const Point& aCP2,
const Point& aCP3) {
PathOp op;
op.mType = PathOp::OP_BEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
op.mP3 = aCP3;
mPathOps.push_back(op);
mCurrentPoint = aCP3;
}
void PathBuilderCapture::QuadraticBezierTo(const Point& aCP1,
const Point& aCP2) {
PathOp op;
op.mType = PathOp::OP_QUADRATICBEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
mPathOps.push_back(op);
mCurrentPoint = aCP2;
}
void PathBuilderCapture::Arc(const Point& aCenter, float aRadius,
float aStartAngle, float aEndAngle,
bool aAntiClockwise) {
PathOp op;
op.mType = PathOp::OP_ARC;
op.mP1 = aCenter;
op.mRadius = aRadius;
op.mStartAngle = aStartAngle;
op.mEndAngle = aEndAngle;
op.mAntiClockwise = aAntiClockwise;
mPathOps.push_back(op);
mCurrentPoint = Point(aCenter.x + aRadius * cosf(aEndAngle),
aCenter.y + aRadius * sinf(aEndAngle));
}
void PathBuilderCapture::Close() {
PathOp op;
op.mType = PathOp::OP_CLOSE;
mPathOps.push_back(op);
mCurrentPoint = mBeginPoint;
}
already_AddRefed<Path> PathBuilderCapture::Finish() {
Point currentPoint = mCurrentPoint;
Point beginPoint = mBeginPoint;
mCurrentPoint = Point(0.0, 0.0);
mBeginPoint = Point(0.0, 0.0);
return MakeAndAddRef<PathCapture>(std::move(mPathOps), mFillRule, mDT,
currentPoint, beginPoint);
}
already_AddRefed<PathBuilder> PathCapture::CopyToBuilder(
FillRule aFillRule) const {
RefPtr<PathBuilderCapture> capture = new PathBuilderCapture(aFillRule, mDT);
capture->mPathOps = mPathOps;
capture->mCurrentPoint = mCurrentPoint;
capture->mBeginPoint = mBeginPoint;
return capture.forget();
}
already_AddRefed<PathBuilder> PathCapture::TransformedCopyToBuilder(
const Matrix& aTransform, FillRule aFillRule) const {
RefPtr<PathBuilderCapture> capture = new PathBuilderCapture(aFillRule, mDT);
typedef std::vector<PathOp> pathOpVec;
for (pathOpVec::const_iterator iter = mPathOps.begin();
iter != mPathOps.end(); iter++) {
PathOp newPathOp;
newPathOp.mType = iter->mType;
if (newPathOp.mType == PathOp::OpType::OP_ARC) {
struct ArcTransformer {
ArcTransformer(pathOpVec& aVector, const Matrix& aTransform)
: mVector(&aVector), mTransform(&aTransform) {}
void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) {
PathOp newPathOp;
newPathOp.mType = PathOp::OP_BEZIERTO;
newPathOp.mP1 = mTransform->TransformPoint(aCP1);
newPathOp.mP2 = mTransform->TransformPoint(aCP2);
newPathOp.mP3 = mTransform->TransformPoint(aCP3);
mVector->push_back(newPathOp);
}
void LineTo(const Point& aPoint) {
PathOp newPathOp;
newPathOp.mType = PathOp::OP_LINETO;
newPathOp.mP1 = mTransform->TransformPoint(aPoint);
mVector->push_back(newPathOp);
}
pathOpVec* mVector;
const Matrix* mTransform;
};
ArcTransformer arcTransformer(capture->mPathOps, aTransform);
ArcToBezier(&arcTransformer, iter->mP1,
Size(iter->mRadius, iter->mRadius), iter->mStartAngle,
iter->mEndAngle, iter->mAntiClockwise);
} else {
if (sPointCount[newPathOp.mType] >= 1) {
newPathOp.mP1 = aTransform.TransformPoint(iter->mP1);
}
if (sPointCount[newPathOp.mType] >= 2) {
newPathOp.mP2 = aTransform.TransformPoint(iter->mP2);
}
if (sPointCount[newPathOp.mType] >= 3) {
newPathOp.mP3 = aTransform.TransformPoint(iter->mP3);
}
capture->mPathOps.push_back(newPathOp);
}
}
capture->mCurrentPoint = aTransform.TransformPoint(mCurrentPoint);
capture->mBeginPoint = aTransform.TransformPoint(mBeginPoint);
return capture.forget();
}
bool PathCapture::ContainsPoint(const Point& aPoint,
const Matrix& aTransform) const {
if (!EnsureRealizedPath()) {
return false;
}
return mRealizedPath->ContainsPoint(aPoint, aTransform);
}
bool PathCapture::StrokeContainsPoint(const StrokeOptions& aStrokeOptions,
const Point& aPoint,
const Matrix& aTransform) const {
if (!EnsureRealizedPath()) {
return false;
}
return mRealizedPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform);
}
Rect PathCapture::GetBounds(const Matrix& aTransform) const {
if (!EnsureRealizedPath()) {
return Rect();
}
return mRealizedPath->GetBounds(aTransform);
}
Rect PathCapture::GetStrokedBounds(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform) const {
if (!EnsureRealizedPath()) {
return Rect();
}
return mRealizedPath->GetStrokedBounds(aStrokeOptions, aTransform);
}
void PathCapture::StreamToSink(PathSink* aSink) const {
for (const PathOp& op : mPathOps) {
switch (op.mType) {
case PathOp::OP_MOVETO:
aSink->MoveTo(op.mP1);
break;
case PathOp::OP_LINETO:
aSink->LineTo(op.mP1);
break;
case PathOp::OP_BEZIERTO:
aSink->BezierTo(op.mP1, op.mP2, op.mP3);
break;
case PathOp::OP_QUADRATICBEZIERTO:
aSink->QuadraticBezierTo(op.mP1, op.mP2);
break;
case PathOp::OP_ARC:
aSink->Arc(op.mP1, op.mRadius, op.mStartAngle, op.mEndAngle,
op.mAntiClockwise);
break;
case PathOp::OP_CLOSE:
aSink->Close();
break;
}
}
}
bool PathCapture::EnsureRealizedPath() const {
RefPtr<PathBuilder> builder = mDT->CreatePathBuilder(mFillRule);
if (!builder) {
return false;
}
StreamToSink(builder);
mRealizedPath = builder->Finish();
return true;
}
Path* PathCapture::GetRealizedPath() const {
if (!EnsureRealizedPath()) {
return nullptr;
}
return mRealizedPath.get();
}
} // namespace gfx
} // namespace mozilla