aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/osx/graphics/quartz/Painter.hpp8
-rw-r--r--include/cru/platform/Matrix.hpp13
-rw-r--r--include/cru/platform/graphics/Painter.hpp6
-rw-r--r--include/cru/platform/graphics/util/Painter.hpp5
-rw-r--r--src/osx/Convert.cpp3
-rw-r--r--src/osx/graphics/quartz/Painter.cpp60
6 files changed, 79 insertions, 16 deletions
diff --git a/include/cru/osx/graphics/quartz/Painter.hpp b/include/cru/osx/graphics/quartz/Painter.hpp
index 60a660a0..e9b3365d 100644
--- a/include/cru/osx/graphics/quartz/Painter.hpp
+++ b/include/cru/osx/graphics/quartz/Painter.hpp
@@ -29,6 +29,8 @@ class QuartzCGContextPainter : public OsxQuartzResource,
Matrix GetTransform() override;
void SetTransform(const Matrix& matrix) override;
+ void ConcatTransform(const Matrix& matrix) override;
+
void Clear(const Color& color) override;
void DrawLine(const Point& start, const Point& end, IBrush* brush,
@@ -49,6 +51,10 @@ class QuartzCGContextPainter : public OsxQuartzResource,
void EndDraw() override;
+ void PushState() override;
+
+ void PopState() override;
+
private:
void DoEndDraw();
@@ -61,6 +67,8 @@ class QuartzCGContextPainter : public OsxQuartzResource,
Size size_;
+ Matrix transform_;
+
std::function<void(QuartzCGContextPainter*)> on_end_draw_;
std::vector<Rect> clip_stack_;
diff --git a/include/cru/platform/Matrix.hpp b/include/cru/platform/Matrix.hpp
index 7985af0e..72459b79 100644
--- a/include/cru/platform/Matrix.hpp
+++ b/include/cru/platform/Matrix.hpp
@@ -2,6 +2,7 @@
#include "GraphicsBase.hpp"
#include <cmath>
+#include <optional>
namespace cru::platform {
struct Matrix {
@@ -80,6 +81,18 @@ struct Matrix {
a.m31 * b.m12 + a.m32 * b.m22 + b.m32};
}
+ std::optional<Matrix> Inverted() const {
+ if (m11 * m22 == m12 * m21) return std::nullopt;
+ Matrix result;
+ result.m11 = m22 / (m11 * m22 - m12 * m21);
+ result.m12 = m12 / (m12 * m21 - m11 * m22);
+ result.m21 = m21 / (m12 * m21 - m11 * m22);
+ result.m22 = m11 / (m11 * m22 - m12 * m21);
+ result.m31 = (m21 * m32 - m22 * m31) / (m11 * m22 - m12 * m21);
+ result.m32 = (m31 * m12 - m11 * m32) / (m11 * m22 - m12 * m21);
+ return result;
+ }
+
private:
static constexpr float PI = 3.1415926535f;
diff --git a/include/cru/platform/graphics/Painter.hpp b/include/cru/platform/graphics/Painter.hpp
index 24592f95..9bde0640 100644
--- a/include/cru/platform/graphics/Painter.hpp
+++ b/include/cru/platform/graphics/Painter.hpp
@@ -7,6 +7,8 @@ struct IPainter : virtual IPlatformResource {
virtual Matrix GetTransform() = 0;
virtual void SetTransform(const Matrix& matrix) = 0;
+ virtual void ConcatTransform(const Matrix& matrix) = 0;
+
virtual void Clear(const Color& color) = 0;
virtual void DrawLine(const Point& start, const Point& end, IBrush* brush,
@@ -26,6 +28,10 @@ struct IPainter : virtual IPlatformResource {
virtual void PopLayer() = 0;
+ virtual void PushState() = 0;
+
+ virtual void PopState() = 0;
+
virtual void EndDraw() = 0;
};
} // namespace cru::platform::graphics
diff --git a/include/cru/platform/graphics/util/Painter.hpp b/include/cru/platform/graphics/util/Painter.hpp
index 90457cf4..2e0fbb51 100644
--- a/include/cru/platform/graphics/util/Painter.hpp
+++ b/include/cru/platform/graphics/util/Painter.hpp
@@ -10,8 +10,9 @@ void WithTransform(IPainter* painter, const Matrix& matrix, const Fn& action) {
static_assert(std::is_invocable_v<decltype(action), IPainter*>,
"Action must can be be invoked with painter.");
const auto old = painter->GetTransform();
- painter->SetTransform(matrix * old);
+ painter->PushState();
+ painter->ConcatTransform(matrix);
action(painter);
- painter->SetTransform(old);
+ painter->PopState();
}
} // namespace cru::platform::graphics::util
diff --git a/src/osx/Convert.cpp b/src/osx/Convert.cpp
index e8c023e9..6bec5adc 100644
--- a/src/osx/Convert.cpp
+++ b/src/osx/Convert.cpp
@@ -1,8 +1,9 @@
#include "cru/osx/Convert.hpp"
-#include <string>
#include "cru/common/StringUtil.hpp"
+#include <string>
+
namespace cru::platform::osx {
CFStringRef Convert(const String& string) {
return CFStringCreateWithBytes(
diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp
index 406e3273..eee175ac 100644
--- a/src/osx/graphics/quartz/Painter.cpp
+++ b/src/osx/graphics/quartz/Painter.cpp
@@ -21,6 +21,13 @@ QuartzCGContextPainter::QuartzCGContextPainter(
size_(size),
on_end_draw_(std::move(on_end_draw)) {
Expects(cg_context);
+
+ CGContextConcatCTM(cg_context_,
+ CGAffineTransformInvert(CGContextGetCTM(cg_context_)));
+
+ transform_ = Matrix::Scale(1, -1) * Matrix::Translation(0, size.height);
+ CGContextConcatCTM(cg_context_, Convert(transform_));
+
// log::TagDebug(log_tag,
// u"Created with CGContext: {}, Auto Release: {}, Size: {}.",
// cg_context, auto_release, size_);
@@ -34,15 +41,17 @@ QuartzCGContextPainter::~QuartzCGContextPainter() {
}
}
-Matrix QuartzCGContextPainter::GetTransform() {
- return Convert(CGContextGetCTM(cg_context_));
-}
+Matrix QuartzCGContextPainter::GetTransform() { return transform_; }
void QuartzCGContextPainter::SetTransform(const Matrix& matrix) {
- auto old = CGContextGetCTM(cg_context_);
- old = CGAffineTransformInvert(old);
- CGContextConcatCTM(cg_context_, old);
+ CGContextConcatCTM(cg_context_, Convert(*transform_.Inverted()));
+ CGContextConcatCTM(cg_context_, Convert(matrix));
+ transform_ = matrix;
+}
+
+void QuartzCGContextPainter::ConcatTransform(const Matrix& matrix) {
CGContextConcatCTM(cg_context_, Convert(matrix));
+ transform_ = matrix * transform_;
}
void QuartzCGContextPainter::Clear(const Color& color) {
@@ -128,13 +137,28 @@ void QuartzCGContextPainter::DrawText(const Point& offset,
color = colors::black;
}
- util::WithTransform(this, Matrix::Translation(offset),
- [this, tl, color](IPainter*) {
- auto frame = tl->CreateFrameWithColor(color);
- Ensures(frame);
- CTFrameDraw(frame, cg_context_);
- CFRelease(frame);
- });
+ auto bounds = tl->GetTextBounds();
+
+ bounds.width += bounds.left;
+ bounds.height += bounds.top;
+ bounds.left = bounds.top = 0;
+
+ Matrix transform =
+ Matrix::Translation(-bounds.width / 2, -bounds.height / 2) *
+ Matrix::Scale(1, -1) *
+ Matrix::Translation(bounds.width / 2, bounds.height / 2);
+
+ CGContextSaveGState(cg_context_);
+
+ CGContextConcatCTM(cg_context_, Convert(transform * Matrix::Translation(
+ offset.x, offset.y)));
+
+ auto frame = tl->CreateFrameWithColor(color);
+ Ensures(frame);
+ CTFrameDraw(frame, cg_context_);
+ CFRelease(frame);
+
+ CGContextRestoreGState(cg_context_);
}
void QuartzCGContextPainter::PushLayer(const Rect& bounds) {
@@ -153,6 +177,16 @@ void QuartzCGContextPainter::PopLayer() {
}
}
+void QuartzCGContextPainter::PushState() {
+ Validate();
+ CGContextSaveGState(cg_context_);
+}
+
+void QuartzCGContextPainter::PopState() {
+ Validate();
+ CGContextRestoreGState(cg_context_);
+}
+
void QuartzCGContextPainter::EndDraw() { DoEndDraw(); }
void QuartzCGContextPainter::DoEndDraw() {