Skip to content

Commit

Permalink
Implement the Picture and Recorder classes. (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
domchen authored May 9, 2024
1 parent 72edd24 commit be43219
Show file tree
Hide file tree
Showing 27 changed files with 1,613 additions and 401 deletions.
2 changes: 1 addition & 1 deletion DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
{
"url": "${PAG_GROUP}/pathkit.git",
"commit": "6d1e43220f40cfd7a032ecf45005e8846ba8a351",
"commit": "a03c6d8bc779bca102587d912b72d8d972af8324",
"dir": "third_party/pathkit"
},
{
Expand Down
29 changes: 26 additions & 3 deletions include/tgfx/core/Canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
#include "tgfx/core/Image.h"
#include "tgfx/core/Paint.h"
#include "tgfx/core/Path.h"
#include "tgfx/core/Picture.h"
#include "tgfx/core/SamplingOptions.h"
#include "tgfx/core/TextBlob.h"

namespace tgfx {
class Surface;
class FillStyle;
class DrawContext;
class MCState;

/**
* Canvas provides an interface for drawing, and how the drawing is clipped and transformed. Canvas
Expand Down Expand Up @@ -272,6 +274,23 @@ class Canvas {
void drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount,
const Font& font, const Paint& paint);

/**
* Draws a Picture using the current clip and matrix. Clip and matrix are unchanged by picture
* contents, as if save() was called before and restore() was called after drawPicture().
*/
void drawPicture(std::shared_ptr<Picture> picture);

/**
* Draws a Picture using the current clip, and matrix premultiplied with existing Matrix. If paint
* is non-null, then the picture is always drawn into a temporary layer before actually landing on
* the canvas. Note that drawing into a layer can also change its appearance if there are any
* non-associative blendModes inside any of the picture elements.
* @param picture recorded drawing commands to play back.
* @param matrix Matrix to rotate, scale, translate, and so on; may be nullptr.
* @param paint Paint to apply transparency, filtering, and so on; may be nullptr.
*/
void drawPicture(std::shared_ptr<Picture> picture, const Matrix* matrix, const Paint* paint);

/**
* Draws a set of sprites from the atlas using the current clip, matrix, and specified paint.
* @param atlas Image containing the sprites.
Expand All @@ -288,16 +307,20 @@ class Canvas {

private:
DrawContext* drawContext = nullptr;
std::unique_ptr<MCState> mcState;
std::stack<std::unique_ptr<MCState>> mcStack;

explicit Canvas(DrawContext* drawContext);
Canvas(DrawContext* drawContext, const Path& initClip);
bool drawSimplePath(const Path& path, const FillStyle& style);
void drawImage(std::shared_ptr<Image> image, const SamplingOptions& sampling, const Paint* paint,
const Matrix* extraMatrix);
void drawImageRect(const Rect& rect, std::shared_ptr<Image> image,
const SamplingOptions& sampling, const FillStyle& style,
const Matrix& extraMatrix);
void drawLayer(std::shared_ptr<Picture> picture, const MCState& state, const FillStyle& style,
std::shared_ptr<ImageFilter> filter = nullptr);
void resetMCState();

friend class Surface;
friend class Picture;
friend class Recorder;
};
} // namespace tgfx
63 changes: 63 additions & 0 deletions include/tgfx/core/Picture.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2023 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/Matrix.h"
#include "tgfx/core/Path.h"

namespace tgfx {
class Record;
class Canvas;
class DrawContext;
class MCState;

/**
* The Picture class captures the drawing commands made on a Canvas, which can be replayed later.
* The Picture object is thread-safe and immutable once created. Pictures can be created by a
* Recorder or loaded from serialized data.
*/
class Picture {
public:
~Picture();

/**
* Returns the bounding box of the Picture when drawn with the given Matrix.
*/
Rect getBounds(const Matrix& matrix = Matrix::I()) const;

/**
* Replays the drawing commands on the specified canvas. In the case that the commands are
* recorded, each command in the Picture is sent separately to canvas. To add a single command to
* draw Picture to recording canvas, call Canvas::drawPicture() instead.
*/
void playback(Canvas* canvas) const;

private:
std::vector<Record*> records = {};

explicit Picture(std::vector<Record*> records);

void playback(DrawContext* drawContext, const MCState& state) const;

friend class DrawContext;
friend class RenderContext;
friend class RecordingContext;
friend class Canvas;
};
} // namespace tgfx
59 changes: 59 additions & 0 deletions include/tgfx/core/Recorder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making tgfx available.
//
// Copyright (C) 2023 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/Canvas.h"
#include "tgfx/core/Picture.h"

namespace tgfx {
class RecordingContext;

/**
* The Recorder class records drawing commands made to a Canvas and generates a Picture object that
* captures all these commands, allowing them to be replayed at a later time.
*/
class Recorder {
public:
~Recorder();

/**
* Begins recording drawing commands. If recording is already active, it clears the existing
* commands and starts afresh. Returns the canvas that captures the drawing commands. The returned
* Canvas is managed by the Recorder and is deleted when the Recorder is deleted.
*/
Canvas* beginRecording();

/**
* Returns the recording canvas if one is active, or NULL if recording is not active.
*/
Canvas* getRecordingCanvas() const;

/**
* Signals that the caller is done recording and returns a Picture object that captures all the
* drawing commands made to the canvas. Returns nullptr if no recording is active or no commands
* were recorded.
*/
std::shared_ptr<Picture> finishRecordingAsPicture();

private:
bool activelyRecording = false;
RecordingContext* recordingContext = nullptr;
Canvas* canvas = nullptr;
};
} // namespace tgfx
Loading

0 comments on commit be43219

Please sign in to comment.