Skip to content

Commit

Permalink
Refactor the ShapeContent class to allow it to draw contours as well. (
Browse files Browse the repository at this point in the history
  • Loading branch information
domchen authored Jan 8, 2025
1 parent c08f94a commit 7a9c80a
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 222 deletions.
3 changes: 1 addition & 2 deletions drawers/src/base/Drawer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ void Drawer::draw(tgfx::Canvas* canvas, const AppHost* host) {
tgfx::PrintError("Drawer::draw() appHost is nullptr!");
return;
}
canvas->save();
tgfx::AutoCanvasRestore autoRestore(canvas);
onDraw(canvas, host);
canvas->restore();
}
} // namespace drawers
2 changes: 1 addition & 1 deletion drawers/src/layertree/SimpleLayerTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
#include "SimpleLayerTree.h"
#include "tgfx/layers/Gradient.h"
#include "tgfx/layers/ImageLayer.h"
#include "tgfx/layers/ImagePattern.h"
#include "tgfx/layers/ShapeLayer.h"
#include "tgfx/layers/SolidColor.h"
#include "tgfx/layers/TextLayer.h"
#include "tgfx/layers/filters/DropShadowFilter.h"

Expand Down
32 changes: 32 additions & 0 deletions include/tgfx/core/Canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,36 @@ class Canvas {
friend class Recorder;
friend class SVGExporter;
};

/**
* AutoCanvasRestore is a helper class that automatically saves the current state of a Canvas when
* created and restores it when destroyed. This is useful for ensuring that the Canvas state is
* restored to its previous state when exiting a scope.
*/
class AutoCanvasRestore {
public:
/**
* Creates an AutoSaveRestore object for the specified Canvas. The current state of the Canvas is
* saved when created and restored when destroyed.
* @param canvas the Canvas to save and restore.
*/
explicit AutoCanvasRestore(Canvas* canvas) : canvas(canvas) {
if (canvas) {
saveCount = canvas->save();
}
}

/**
* Restores the Canvas state to the saved state.
*/
~AutoCanvasRestore() {
if (canvas) {
canvas->restoreToCount(saveCount);
}
}

private:
Canvas* canvas = nullptr;
int saveCount = 0;
};
} // namespace tgfx
7 changes: 7 additions & 0 deletions include/tgfx/core/Shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ class Shader {
return false;
}

/**
* Returns true if the shader is backed by a single image.
*/
virtual bool isAImage() const {
return false;
}

/**
* If the shader has a constant color, this method returns true and updates the color parameter.
* Otherwise, it returns false and leaves the color parameter unchanged.
Expand Down
4 changes: 0 additions & 4 deletions include/tgfx/layers/ImagePattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ class ImagePattern : public ShapeStyle {
*/
void setMatrix(const Matrix& value);

bool isImage() const override {
return true;
}

protected:
std::shared_ptr<Shader> getShader() const override;

Expand Down
30 changes: 14 additions & 16 deletions include/tgfx/layers/Layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,10 +505,14 @@ class Layer {
virtual std::unique_ptr<LayerContent> onUpdateContent();

/**
* Returns the layer contour used for layer styles that require it.
* The default implementation returns the layer content.
* Draws the layer contour on the given canvas. The layer contour is the outline of the layer
* content, used for applying layer styles that need the contour. By default, this calls the
* draw() method with the layer content and the given paint object.
* @param content The layer content to draw. This can be nullptr.
* @param canvas The canvas to draw the layer contour on.
* @param paint The paint object used to draw the layer contour.
*/
virtual LayerContent* getContour();
virtual void drawContour(LayerContent* content, Canvas* canvas, const Paint& paint) const;

/**
* Attachs a property to this layer.
Expand All @@ -520,18 +524,6 @@ class Layer {
*/
void detachProperty(LayerProperty* property) const;

/**
* Draws the layer style onto the given canvas.
*/
void drawLayerStyles(Canvas* canvas, std::shared_ptr<Image> content, float contentScale,
std::shared_ptr<Image> contour, const Point& contourOffset, float alpha,
LayerStylePosition position);

/**
* Draws the layer children onto the given canvas.
*/
void drawChildren(const DrawArgs& args, Canvas* canvas, float alpha);

private:
/**
* Marks the layer's children as changed and needing to be redrawn.
Expand All @@ -554,7 +546,7 @@ class Layer {

Paint getLayerPaint(float alpha, BlendMode blendMode);

std::shared_ptr<ImageFilter> getCurrentFilter(float contentScale);
std::shared_ptr<ImageFilter> getImageFilter(float contentScale);

LayerContent* getRasterizedCache(const DrawArgs& args);

Expand All @@ -567,6 +559,12 @@ class Layer {

void drawContents(const DrawArgs& args, Canvas* canvas, float alpha);

void drawChildren(const DrawArgs& args, Canvas* canvas, float alpha);

void drawLayerStyles(Canvas* canvas, std::shared_ptr<Image> content, float contentScale,
std::shared_ptr<Image> contour, const Point& contourOffset, float alpha,
LayerStylePosition position);

bool getLayersUnderPointInternal(float x, float y, std::vector<std::shared_ptr<Layer>>* results);

std::shared_ptr<MaskFilter> getMaskFilter(const DrawArgs& args, float scale);
Expand Down
24 changes: 8 additions & 16 deletions include/tgfx/layers/ShapeLayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#pragma once

#include "SolidColor.h"
#include "tgfx/core/Shape.h"
#include "tgfx/layers/Layer.h"
#include "tgfx/layers/ShapeStyle.h"
Expand Down Expand Up @@ -55,6 +54,8 @@ class ShapeLayer : public Layer {
*/
static std::shared_ptr<ShapeLayer> Make();

~ShapeLayer() override;

LayerType type() const override {
return LayerType::Shape;
}
Expand Down Expand Up @@ -261,34 +262,25 @@ class ShapeLayer : public Layer {
void setStrokeEnd(float end);

/**
* Returns the stroke alignment applied to the shape’s path when stroked. The default stroke alignment is Center.
*/
* Returns the stroke alignment applied to the shape’s path when stroked. The default stroke alignment is Center.
*/
StrokeAlign strokeAlign() const {
return _strokeAlign;
}

/**
* Sets the stroke alignment applied to the shape’s path when stroked.
*/
* Sets the stroke alignment applied to the shape’s path when stroked.
*/
void setStrokeAlign(StrokeAlign align);

~ShapeLayer() override;

protected:
ShapeLayer() = default;

std::shared_ptr<Shape> createStrokeShape() const;

std::unique_ptr<LayerContent> onUpdateContent() override;

LayerContent* getContour() override;
void drawContour(LayerContent* content, Canvas* canvas, const Paint& paint) const override;

private:
static std::unique_ptr<LayerContent> CreateContourWithStyles(
std::shared_ptr<Shape> shape, const std::vector<std::shared_ptr<ShapeStyle>>& styles);

void invalidateContentAndContour();

std::shared_ptr<Shape> _shape = nullptr;
std::vector<std::shared_ptr<ShapeStyle>> _fillStyles = {};
std::vector<std::shared_ptr<ShapeStyle>> _strokeStyles = {};
Expand All @@ -299,6 +291,6 @@ class ShapeLayer : public Layer {
float _strokeEnd = 1.0f;
StrokeAlign _strokeAlign = StrokeAlign::Center;

std::unique_ptr<LayerContent> contourContent = nullptr;
std::shared_ptr<Shape> createStrokeShape() const;
};
} // namespace tgfx
7 changes: 0 additions & 7 deletions include/tgfx/layers/ShapeStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,6 @@ class ShapeStyle : public LayerProperty {
*/
virtual std::shared_ptr<Shader> getShader() const = 0;

/**
* Returns whether the shape style is an image pattern.
*/
virtual bool isImage() const {
return false;
}

private:
float _alpha = 1.0f;
BlendMode _blendMode = BlendMode::SrcOver;
Expand Down
8 changes: 8 additions & 0 deletions src/core/shaders/ColorFilterShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ class ColorFilterShader : public Shader {
: shader(std::move(shader)), colorFilter(std::move(colorFilter)) {
}

bool isOpaque() const override {
return shader->isOpaque() && colorFilter->isAlphaUnchanged();
}

bool isAImage() const override {
return shader->isAImage();
}

protected:
Type type() const override {
return Type::ColorFilter;
Expand Down
4 changes: 4 additions & 0 deletions src/core/shaders/ImageShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class ImageShader : public Shader {
TileMode tileModeY = TileMode::Clamp;
SamplingOptions sampling = {};

bool isAImage() const override {
return true;
}

protected:
Type type() const override {
return Type::Image;
Expand Down
4 changes: 4 additions & 0 deletions src/core/shaders/MatrixShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class MatrixShader final : public Shader {
return source->isOpaque();
}

bool isAImage() const override {
return source->isAImage();
}

bool asColor(Color* color) const override {
return source->asColor(color);
}
Expand Down
Loading

0 comments on commit 7a9c80a

Please sign in to comment.