Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the PathEffect::MakeStroke() method and add a applyToPath() method to Stroke. #299

Merged
merged 3 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions include/tgfx/core/PathEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ namespace tgfx {
*/
class PathEffect {
public:
/**
* Creates a stroke path effect with the specified stroke options.
*/
static std::unique_ptr<PathEffect> MakeStroke(const Stroke* stroke);

/**
* Creates a dash path effect.
* @param intervals array containing an even number of entries (>=2), with the even indices
Expand Down
8 changes: 8 additions & 0 deletions include/tgfx/core/Stroke.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#pragma once

#include "tgfx/core/Path.h"

namespace tgfx {
/**
* LineCap draws at the beginning and end of an open path contour.
Expand Down Expand Up @@ -73,6 +75,12 @@ class Stroke {
: width(width), cap(cap), join(join), miterLimit(miterLimit) {
}

/**
* Applies this stroke to the given path. Returns false if this stroke cannot be applied, and
* leaves the path unchanged.
*/
bool applyToPath(Path* path) const;

/**
* The thickness of the pen used to outline the paths or glyphs.
*/
Expand Down
11 changes: 4 additions & 7 deletions src/core/Canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,10 @@ void Canvas::drawPath(const Path& path, const Paint& paint) {
auto stroke = paint.getStroke();
auto style = CreateFillStyle(paint);
if (stroke && path.isLine()) {
auto effect = PathEffect::MakeStroke(stroke);
if (effect != nullptr) {
auto fillPath = path;
effect->filterPath(&fillPath);
if (drawSimplePath(fillPath, style)) {
return;
}
auto fillPath = path;
stroke->applyToPath(&fillPath);
if (drawSimplePath(fillPath, style)) {
return;
}
}
if (!stroke && drawSimplePath(path, style)) {
Expand Down
5 changes: 1 addition & 4 deletions src/core/GlyphRunList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,7 @@ bool GlyphRunList::getPath(Path* path, const Matrix& matrix, const Stroke* strok
if (stroke) {
auto scaledStroke = *stroke;
scaledStroke.width *= maxScale;
auto pathEffect = PathEffect::MakeStroke(&scaledStroke);
if (pathEffect) {
pathEffect->filterPath(&totalPath);
}
scaledStroke.applyToPath(&totalPath);
}
auto totalMatrix = matrix;
totalMatrix.preScale(1.0f / maxScale, 1.0f / maxScale);
Expand Down
5 changes: 2 additions & 3 deletions src/core/Mask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ void Mask::fillPath(const Path& path, const Stroke* stroke) {
if (path.isEmpty()) {
return;
}
auto effect = PathEffect::MakeStroke(stroke);
if (effect != nullptr) {
if (stroke != nullptr) {
auto newPath = path;
effect->filterPath(&newPath);
stroke->applyToPath(&newPath);
onFillPath(newPath, matrix);
} else {
onFillPath(path, matrix);
Expand Down
113 changes: 4 additions & 109 deletions src/core/PathEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/core/PathEffect.h"
#include <cmath>
#include "core/PathRef.h"
#include "tgfx/core/PathMeasure.h"
#include "tgfx/core/Stroke.h"

namespace tgfx {
using namespace pk;

class PkPathEffect : public PathEffect {
class SkPathEffectWrapper : public PathEffect {
public:
explicit PkPathEffect(sk_sp<SkPathEffect> effect) : pathEffect(std::move(effect)) {
explicit SkPathEffectWrapper(sk_sp<SkPathEffect> effect) : pathEffect(std::move(effect)) {
}

bool filterPath(Path* path) const override {
Expand All @@ -43,121 +40,19 @@ class PkPathEffect : public PathEffect {
sk_sp<SkPathEffect> pathEffect = nullptr;
};

class StrokePathEffect : public PathEffect {
public:
explicit StrokePathEffect(SkPaint paint) : paint(std::move(paint)) {
}

bool filterPath(Path* path) const override {
if (path == nullptr) {
return false;
}
auto& skPath = PathRef::WriteAccess(*path);
return paint.getFillPath(skPath, &skPath);
}

Rect filterBounds(const Rect& rect) const override {
auto bounds = rect;
auto strokeWidth = paint.getStrokeWidth();
bounds.outset(strokeWidth, strokeWidth);
return bounds;
}

private:
SkPaint paint = {};
};

class TrimPathEffect : public PathEffect {
public:
TrimPathEffect(float startT, float stopT) : startT(startT), stopT(stopT) {
}

bool filterPath(Path* path) const override {
if (path == nullptr) {
return false;
}
if (startT >= stopT) {
path->reset();
return true;
}
auto pathMeasure = PathMeasure::MakeFrom(*path);
auto length = pathMeasure->getLength();
auto start = startT * length;
auto end = stopT * length;
Path tempPath = {};
if (!pathMeasure->getSegment(start, end, &tempPath)) {
return false;
}
*path = std::move(tempPath);
return true;
}

private:
float startT = 0.0f;
float stopT = 1.0f;
};

static SkPaint::Cap ToSkLineCap(LineCap cap) {
switch (cap) {
case LineCap::Round:
return SkPaint::kRound_Cap;
case LineCap::Square:
return SkPaint::kSquare_Cap;
default:
return SkPaint::kButt_Cap;
}
}

static SkPaint::Join ToSkLineJoin(LineJoin join) {
switch (join) {
case LineJoin::Round:
return SkPaint::kRound_Join;
case LineJoin::Bevel:
return SkPaint::kBevel_Join;
default:
return SkPaint::kMiter_Join;
}
}

std::unique_ptr<PathEffect> PathEffect::MakeStroke(const Stroke* stroke) {
if (stroke == nullptr || stroke->width <= 0) {
return nullptr;
}
SkPaint paint = {};
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(stroke->width);
paint.setStrokeCap(ToSkLineCap(stroke->cap));
paint.setStrokeJoin(ToSkLineJoin(stroke->join));
paint.setStrokeMiter(stroke->miterLimit);
return std::unique_ptr<PathEffect>(new StrokePathEffect(std::move(paint)));
}

std::unique_ptr<PathEffect> PathEffect::MakeDash(const float* intervals, int count, float phase) {
auto effect = SkDashPathEffect::Make(intervals, count, phase);
if (effect == nullptr) {
return nullptr;
}
return std::unique_ptr<PathEffect>(new PkPathEffect(std::move(effect)));
return std::unique_ptr<PathEffect>(new SkPathEffectWrapper(std::move(effect)));
}

std::unique_ptr<PathEffect> PathEffect::MakeCorner(float radius) {
auto effect = SkCornerPathEffect::Make(radius);
if (effect == nullptr) {
return nullptr;
}
return std::unique_ptr<PathEffect>(new PkPathEffect(std::move(effect)));
return std::unique_ptr<PathEffect>(new SkPathEffectWrapper(std::move(effect)));
}

std::unique_ptr<PathEffect> PathEffect::MakeTrim(float startT, float stopT) {
if (isnan(startT) || isnan(stopT)) {
return nullptr;
}
if (startT <= 0 && stopT >= 1) {
return nullptr;
}
startT = std::max(0.f, std::min(startT, 1.f));
stopT = std::max(0.f, std::min(stopT, 1.f));
return std::unique_ptr<PathEffect>(new TrimPathEffect(startT, stopT));
}

} // namespace tgfx
65 changes: 65 additions & 0 deletions src/core/Stroke.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "tgfx/core/Stroke.h"
#include "core/PathRef.h"

namespace tgfx {
using namespace pk;

static SkPaint::Cap ToSkLineCap(LineCap cap) {
switch (cap) {
case LineCap::Round:
return SkPaint::kRound_Cap;
case LineCap::Square:
return SkPaint::kSquare_Cap;
default:
return SkPaint::kButt_Cap;
}
}

static SkPaint::Join ToSkLineJoin(LineJoin join) {
switch (join) {
case LineJoin::Round:
return SkPaint::kRound_Join;
case LineJoin::Bevel:
return SkPaint::kBevel_Join;
default:
return SkPaint::kMiter_Join;
}
}

bool Stroke::applyToPath(Path* path) const {
if (path == nullptr) {
return false;
}
if (width <= 0) {
path->reset();
return true;
}
SkPaint paint = {};
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(width);
paint.setStrokeCap(ToSkLineCap(cap));
paint.setStrokeJoin(ToSkLineJoin(join));
paint.setStrokeMiter(miterLimit);
auto& skPath = PathRef::WriteAccess(*path);
return paint.getFillPath(skPath, &skPath);
}

} // namespace tgfx
58 changes: 58 additions & 0 deletions src/core/TrimPathEffect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "TrimPathEffect.h"
#include "core/PathRef.h"
#include "tgfx/core/PathMeasure.h"

namespace tgfx {
using namespace pk;

std::unique_ptr<PathEffect> PathEffect::MakeTrim(float startT, float stopT) {
if (isnan(startT) || isnan(stopT)) {
return nullptr;
}
if (startT <= 0 && stopT >= 1) {
return nullptr;
}
startT = std::max(0.f, std::min(startT, 1.f));
stopT = std::max(0.f, std::min(stopT, 1.f));
return std::unique_ptr<PathEffect>(new TrimPathEffect(startT, stopT));
}

bool TrimPathEffect::filterPath(Path* path) const {
if (path == nullptr) {
return false;
}
if (startT >= stopT) {
path->reset();
return true;
}
auto pathMeasure = PathMeasure::MakeFrom(*path);
auto length = pathMeasure->getLength();
auto start = startT * length;
auto end = stopT * length;
Path tempPath = {};
if (!pathMeasure->getSegment(start, end, &tempPath)) {
return false;
}
*path = std::move(tempPath);
return true;
}

} // namespace tgfx
35 changes: 35 additions & 0 deletions src/core/TrimPathEffect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "tgfx/core/PathEffect.h"

namespace tgfx {
class TrimPathEffect : public PathEffect {
public:
TrimPathEffect(float startT, float stopT) : startT(startT), stopT(stopT) {
}

bool filterPath(Path* path) const override;

private:
float startT = 0.0f;
float stopT = 1.0f;
};
} // namespace tgfx
3 changes: 1 addition & 2 deletions src/core/vectors/coregraphics/CGScalerContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,7 @@ bool CGScalerContext::generatePath(GlyphID glyphID, bool fauxBold, bool fauxItal
if (fauxBold) {
auto strokePath = *path;
Stroke stroke(textSize * fauxBoldScale);
auto pathEffect = PathEffect::MakeStroke(&stroke);
pathEffect->filterPath(&strokePath);
stroke.applyToPath(&strokePath);
path->addPath(strokePath, PathOp::Union);
}
} else {
Expand Down
Loading