diff options
-rw-r--r-- | include/cru/osx/graphics/quartz/Painter.hpp | 8 | ||||
-rw-r--r-- | include/cru/platform/Matrix.hpp | 13 | ||||
-rw-r--r-- | include/cru/platform/graphics/Painter.hpp | 6 | ||||
-rw-r--r-- | include/cru/platform/graphics/util/Painter.hpp | 5 | ||||
-rw-r--r-- | src/osx/Convert.cpp | 3 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Painter.cpp | 60 |
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() { |