aboutsummaryrefslogtreecommitdiff
path: root/src/osx/graphics/quartz
diff options
context:
space:
mode:
Diffstat (limited to 'src/osx/graphics/quartz')
-rw-r--r--src/osx/graphics/quartz/Brush.cpp36
-rw-r--r--src/osx/graphics/quartz/CMakeLists.txt19
-rw-r--r--src/osx/graphics/quartz/Convert.cpp63
-rw-r--r--src/osx/graphics/quartz/Factory.cpp43
-rw-r--r--src/osx/graphics/quartz/Font.cpp30
-rw-r--r--src/osx/graphics/quartz/Geometry.cpp79
-rw-r--r--src/osx/graphics/quartz/Image.cpp58
-rw-r--r--src/osx/graphics/quartz/ImageFactory.cpp109
-rw-r--r--src/osx/graphics/quartz/Painter.cpp230
-rw-r--r--src/osx/graphics/quartz/Resource.cpp1
-rw-r--r--src/osx/graphics/quartz/TextLayout.cpp456
11 files changed, 0 insertions, 1124 deletions
diff --git a/src/osx/graphics/quartz/Brush.cpp b/src/osx/graphics/quartz/Brush.cpp
deleted file mode 100644
index cfb8f635..00000000
--- a/src/osx/graphics/quartz/Brush.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "cru/osx/graphics/quartz/Brush.h"
-#include "cru/common/String.h"
-#include "cru/common/Format.h"
-
-namespace cru::platform::graphics::osx::quartz {
-QuartzSolidColorBrush::QuartzSolidColorBrush(IGraphicsFactory* graphics_factory,
- const Color& color)
- : QuartzBrush(graphics_factory), color_(color) {
- cg_color_ =
- CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(),
- color.GetFloatBlue(), color.GetFloatAlpha());
- Ensures(cg_color_);
-}
-
-QuartzSolidColorBrush::~QuartzSolidColorBrush() { CGColorRelease(cg_color_); }
-
-void QuartzSolidColorBrush::SetColor(const Color& color) {
- color_ = color;
- CGColorRelease(cg_color_);
- cg_color_ =
- CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(),
- color.GetFloatBlue(), color.GetFloatAlpha());
- Ensures(cg_color_);
-}
-
-void QuartzSolidColorBrush::Select(CGContextRef context) {
- Expects(context);
- Expects(cg_color_);
- CGContextSetStrokeColorWithColor(context, cg_color_);
- CGContextSetFillColorWithColor(context, cg_color_);
-}
-
-String QuartzSolidColorBrush::GetDebugString() {
- return Format(u"QuartzSolidColorBrush(Color: {})", color_);
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/CMakeLists.txt b/src/osx/graphics/quartz/CMakeLists.txt
deleted file mode 100644
index 1fcaff26..00000000
--- a/src/osx/graphics/quartz/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-add_library(CruPlatformGraphicsQuartz SHARED
- Brush.cpp
- Convert.cpp
- Factory.cpp
- Font.cpp
- Geometry.cpp
- Image.cpp
- ImageFactory.cpp
- Painter.cpp
- Resource.cpp
- TextLayout.cpp
-)
-
-find_library(CORE_GRAPHICS CoreGraphics REQUIRED)
-find_library(CORE_TEXT CoreText REQUIRED)
-find_library(IMAGE_IO ImageIO REQUIRED)
-
-target_link_libraries(CruPlatformGraphicsQuartz PUBLIC ${CORE_GRAPHICS} ${CORE_TEXT} ${IMAGE_IO})
-target_link_libraries(CruPlatformGraphicsQuartz PUBLIC CruPlatformBaseOsx CruPlatformGraphics)
diff --git a/src/osx/graphics/quartz/Convert.cpp b/src/osx/graphics/quartz/Convert.cpp
deleted file mode 100644
index df62a206..00000000
--- a/src/osx/graphics/quartz/Convert.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "cru/osx/graphics/quartz/Convert.h"
-#include <cstdint>
-
-namespace cru::platform::graphics::osx::quartz {
-
-CGPoint Convert(const Point& point) { return CGPoint{point.x, point.y}; }
-Point Convert(const CGPoint& point) { return Point(point.x, point.y); }
-
-CGSize Convert(const Size& size) { return CGSize{size.width, size.height}; }
-Size Convert(const CGSize& size) { return Size(size.width, size.height); }
-
-CGAffineTransform Convert(const Matrix& matrix) {
- return CGAffineTransformMake(matrix.m11, matrix.m12, matrix.m21, matrix.m22,
- matrix.m31, matrix.m32);
-}
-
-Matrix Convert(const CGAffineTransform& matrix) {
- return Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
-}
-
-CGRect Convert(const Rect& rect) {
- return CGRect{CGPoint{rect.left, rect.top}, CGSize{rect.width, rect.height}};
-}
-
-Rect Convert(const CGRect& rect) {
- return Rect{static_cast<float>(rect.origin.x),
- static_cast<float>(rect.origin.y),
- static_cast<float>(rect.size.width),
- static_cast<float>(rect.size.height)};
-}
-
-const CGDataProviderSequentialCallbacks kStreamToCGDataProviderCallbacks{
- 1,
- [](void* stream, void* buffer, size_t size) -> size_t {
- return static_cast<io::Stream*>(stream)->Read(
- static_cast<std::byte*>(buffer), size);
- },
- [](void* stream, off_t offset) -> off_t {
- auto s = static_cast<io::Stream*>(stream);
- auto current_position = s->Tell();
- s->Seek(offset, io::Stream::SeekOrigin::Current);
- return s->Tell() - current_position;
- },
- [](void* stream) { static_cast<io::Stream*>(stream)->Rewind(); },
- [](void* stream) {}};
-
-CGDataProviderRef ConvertStreamToCGDataProvider(io::Stream* stream) {
- return CGDataProviderCreateSequential(stream,
- &kStreamToCGDataProviderCallbacks);
-}
-
-const CGDataConsumerCallbacks kStreamToCGDataConsumerCallbacks{
- [](void* info, const void* buffer, size_t count) -> size_t {
- return static_cast<io::Stream*>(info)->Write(
- static_cast<const std::byte*>(buffer), count);
- },
- [](void* info) {}};
-
-CGDataConsumerRef ConvertStreamToCGDataConsumer(io::Stream* stream) {
- return CGDataConsumerCreate(stream, &kStreamToCGDataConsumerCallbacks);
-}
-
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Factory.cpp b/src/osx/graphics/quartz/Factory.cpp
deleted file mode 100644
index 283341e5..00000000
--- a/src/osx/graphics/quartz/Factory.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "cru/osx/graphics/quartz/Factory.h"
-
-#include "cru/osx/graphics/quartz/Brush.h"
-#include "cru/osx/graphics/quartz/Font.h"
-#include "cru/osx/graphics/quartz/Geometry.h"
-#include "cru/osx/graphics/quartz/ImageFactory.h"
-#include "cru/osx/graphics/quartz/TextLayout.h"
-#include "cru/platform/Check.h"
-#include "cru/platform/graphics/ImageFactory.h"
-
-#include <memory>
-
-namespace cru::platform::graphics::osx::quartz {
-QuartzGraphicsFactory::QuartzGraphicsFactory()
- : OsxQuartzResource(this), image_factory_(new QuartzImageFactory(this)) {}
-
-QuartzGraphicsFactory::~QuartzGraphicsFactory() {}
-
-std::unique_ptr<ISolidColorBrush>
-QuartzGraphicsFactory::CreateSolidColorBrush() {
- return std::make_unique<QuartzSolidColorBrush>(this, colors::black);
-}
-
-std::unique_ptr<IGeometryBuilder>
-QuartzGraphicsFactory::CreateGeometryBuilder() {
- return std::make_unique<QuartzGeometryBuilder>(this);
-}
-
-std::unique_ptr<IFont> QuartzGraphicsFactory::CreateFont(String font_family,
- float font_size) {
- return std::make_unique<OsxCTFont>(this, font_family, font_size);
-}
-
-std::unique_ptr<ITextLayout> QuartzGraphicsFactory::CreateTextLayout(
- std::shared_ptr<IFont> font, String text) {
- auto f = CheckPlatform<OsxCTFont>(font, GetPlatformId());
- return std::make_unique<OsxCTTextLayout>(this, f, text);
-}
-
-IImageFactory* QuartzGraphicsFactory::GetImageFactory() {
- return image_factory_.get();
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Font.cpp b/src/osx/graphics/quartz/Font.cpp
deleted file mode 100644
index a1b8bac2..00000000
--- a/src/osx/graphics/quartz/Font.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "cru/osx/graphics/quartz/Font.h"
-
-#include "cru/osx/Convert.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-#include "cru/osx/graphics/quartz/Resource.h"
-
-namespace cru::platform::graphics::osx::quartz {
-using cru::platform::osx::Convert;
-
-OsxCTFont::OsxCTFont(IGraphicsFactory* graphics_factory, const String& name,
- float size)
- : OsxQuartzResource(graphics_factory), name_(name) {
- CFStringRef n = Convert(name);
-
- if (name.empty()) {
- ct_font_ =
- CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, nullptr);
- } else {
- ct_font_ = CTFontCreateWithName(n, size, nullptr);
- }
- Ensures(ct_font_);
-
- CFRelease(n);
-}
-
-OsxCTFont::~OsxCTFont() { CFRelease(ct_font_); }
-
-String OsxCTFont::GetFontName() { return name_; }
-float OsxCTFont::GetFontSize() { return CTFontGetSize(ct_font_); }
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Geometry.cpp b/src/osx/graphics/quartz/Geometry.cpp
deleted file mode 100644
index c88add87..00000000
--- a/src/osx/graphics/quartz/Geometry.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "cru/osx/graphics/quartz/Geometry.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-
-#include <memory>
-
-namespace cru::platform::graphics::osx::quartz {
-QuartzGeometry::QuartzGeometry(IGraphicsFactory *graphics_factory,
- CGPathRef cg_path)
- : OsxQuartzResource(graphics_factory), cg_path_(cg_path) {}
-
-QuartzGeometry::~QuartzGeometry() { CGPathRelease(cg_path_); }
-
-bool QuartzGeometry::FillContains(const Point &point) {
- return CGPathContainsPoint(cg_path_, nullptr, CGPoint{point.x, point.y},
- kCGPathFill);
-}
-
-Rect QuartzGeometry::GetBounds() {
- auto bounds = CGPathGetPathBoundingBox(cg_path_);
- if (CGRectIsNull(bounds)) return {};
- return Convert(bounds);
-}
-
-std::unique_ptr<IGeometry> QuartzGeometry::Transform(const Matrix &matrix) {
- auto cg_matrix = Convert(matrix);
- auto cg_path = CGPathCreateCopyByTransformingPath(cg_path_, &cg_matrix);
- return std::make_unique<QuartzGeometry>(GetGraphicsFactory(), cg_path);
-}
-
-std::unique_ptr<IGeometry> QuartzGeometry::CreateStrokeGeometry(float width) {
- auto cg_path = CGPathCreateCopyByStrokingPath(
- cg_path_, nullptr, width, kCGLineCapButt, kCGLineJoinMiter, 10);
- return std::make_unique<QuartzGeometry>(GetGraphicsFactory(), cg_path);
-}
-
-QuartzGeometryBuilder::QuartzGeometryBuilder(IGraphicsFactory *graphics_factory)
- : OsxQuartzResource(graphics_factory) {
- cg_mutable_path_ = CGPathCreateMutable();
-}
-
-QuartzGeometryBuilder::~QuartzGeometryBuilder() {
- CGPathRelease(cg_mutable_path_);
-}
-
-Point QuartzGeometryBuilder::GetCurrentPosition() {
- return Convert(CGPathGetCurrentPoint(cg_mutable_path_));
-}
-
-void QuartzGeometryBuilder::MoveTo(const Point &point) {
- CGPathMoveToPoint(cg_mutable_path_, nullptr, point.x, point.y);
-}
-
-void QuartzGeometryBuilder::LineTo(const Point &point) {
- CGPathAddLineToPoint(cg_mutable_path_, nullptr, point.x, point.y);
-}
-
-void QuartzGeometryBuilder::CubicBezierTo(const Point &start_control_point,
- const Point &end_control_point,
- const Point &end_point) {
- CGPathAddCurveToPoint(cg_mutable_path_, nullptr, start_control_point.x,
- start_control_point.y, end_control_point.x,
- end_control_point.y, end_point.x, end_point.y);
-}
-
-void QuartzGeometryBuilder::QuadraticBezierTo(const Point &control_point,
- const Point &end_point) {
- CGPathAddQuadCurveToPoint(cg_mutable_path_, nullptr, control_point.x,
- control_point.y, end_point.x, end_point.y);
-}
-
-void QuartzGeometryBuilder::CloseFigure(bool close) {
- if (close) CGPathCloseSubpath(cg_mutable_path_);
-}
-
-std::unique_ptr<IGeometry> QuartzGeometryBuilder::Build() {
- return std::make_unique<QuartzGeometry>(GetGraphicsFactory(),
- CGPathCreateCopy(cg_mutable_path_));
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Image.cpp b/src/osx/graphics/quartz/Image.cpp
deleted file mode 100644
index 28087000..00000000
--- a/src/osx/graphics/quartz/Image.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "cru/osx/graphics/quartz/Image.h"
-#include "cru/common/Exception.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-#include "cru/osx/graphics/quartz/Painter.h"
-
-namespace cru::platform::graphics::osx::quartz {
-QuartzImage::QuartzImage(IGraphicsFactory* graphics_factory,
- IImageFactory* image_factory, CGImageRef image,
- bool auto_release, unsigned char* buffer)
- : OsxQuartzResource(graphics_factory),
- image_factory_(image_factory),
- image_(image),
- auto_release_(auto_release),
- buffer_(buffer) {
- Expects(image);
-}
-
-QuartzImage::~QuartzImage() {
- if (auto_release_) {
- CGImageRelease(image_);
- }
-}
-
-float QuartzImage::GetWidth() { return CGImageGetWidth(image_); }
-
-float QuartzImage::GetHeight() { return CGImageGetHeight(image_); }
-
-std::unique_ptr<IImage> QuartzImage::CreateWithRect(const Rect& rect) {
- auto new_cg_image = CGImageCreateWithImageInRect(image_, Convert(rect));
-
- return std::make_unique<QuartzImage>(GetGraphicsFactory(), image_factory_,
- new_cg_image, true);
-}
-
-std::unique_ptr<IPainter> QuartzImage::CreatePainter() {
- if (!buffer_)
- throw Exception(
- u"Failed to create painter for image because failed to get its "
- u"buffer.");
-
- auto width = CGImageGetWidth(image_);
- auto height = CGImageGetHeight(image_);
- auto bits_per_component = CGImageGetBitsPerComponent(image_);
- auto bytes_per_row = CGImageGetBytesPerRow(image_);
- auto color_space = CGImageGetColorSpace(image_);
- auto bitmap_info = CGImageGetBitmapInfo(image_);
-
- auto cg_context =
- CGBitmapContextCreate(buffer_, width, height, bits_per_component,
- bytes_per_row, color_space, bitmap_info);
-
- return std::make_unique<QuartzCGContextPainter>(
- GetGraphicsFactory(), cg_context, true, Size(width, height),
- [](QuartzCGContextPainter* painter) {
-
- });
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/ImageFactory.cpp b/src/osx/graphics/quartz/ImageFactory.cpp
deleted file mode 100644
index 5ff262c3..00000000
--- a/src/osx/graphics/quartz/ImageFactory.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "cru/osx/graphics/quartz/ImageFactory.h"
-#include "cru/common/Exception.h"
-#include "cru/common/platform/osx/Convert.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-#include "cru/osx/graphics/quartz/Image.h"
-#include "cru/platform/Check.h"
-#include "cru/platform/graphics/Image.h"
-
-#include <ImageIO/ImageIO.h>
-
-namespace cru::platform::graphics::osx::quartz {
-using cru::platform::osx::Convert;
-
-QuartzImageFactory::QuartzImageFactory(IGraphicsFactory* graphics_factory)
- : OsxQuartzResource(graphics_factory) {}
-
-QuartzImageFactory::~QuartzImageFactory() {}
-
-std::unique_ptr<IImage> QuartzImageFactory::DecodeFromStream(
- io::Stream* stream) {
- CGDataProviderRef data_provider = ConvertStreamToCGDataProvider(stream);
- CGImageSourceRef image_source =
- CGImageSourceCreateWithDataProvider(data_provider, nullptr);
-
- CGImageRef cg_image =
- CGImageSourceCreateImageAtIndex(image_source, 0, nullptr);
-
- CFRelease(image_source);
- CGDataProviderRelease(data_provider);
-
- return std::unique_ptr<IImage>(
- new QuartzImage(GetGraphicsFactory(), this, cg_image, true));
-}
-
-static String GetImageFormatUniformTypeIdentifier(ImageFormat format) {
- switch (format) {
- case ImageFormat::Png:
- return u"public.png";
- case ImageFormat::Jpeg:
- return u"public.jpeg";
- case ImageFormat::Gif:
- return u"com.compuserve.gif";
- default:
- throw Exception(u"Unknown image format.");
- }
-}
-
-void QuartzImageFactory::EncodeToStream(IImage* image, io::Stream* stream,
- ImageFormat format, float quality) {
- if (quality <= 0 || quality > 1) {
- throw Exception(u"Invalid quality value.");
- }
-
- auto quartz_image = CheckPlatform<QuartzImage>(image, GetPlatformId());
- auto cg_image = quartz_image->GetCGImage();
-
- CFStringRef uti = Convert(GetImageFormatUniformTypeIdentifier(format));
- CGDataConsumerRef data_consumer = ConvertStreamToCGDataConsumer(stream);
- CGImageDestinationRef destination =
- CGImageDestinationCreateWithDataConsumer(data_consumer, uti, 1, nullptr);
-
- CFMutableDictionaryRef properties =
- CFDictionaryCreateMutable(nullptr, 0, nullptr, nullptr);
- CFNumberRef quality_wrap =
- CFNumberCreate(nullptr, kCFNumberFloatType, &quality);
- CFDictionaryAddValue(properties, kCGImageDestinationLossyCompressionQuality,
- quality_wrap);
-
- CGImageDestinationAddImage(destination, cg_image, properties);
-
- if (!CGImageDestinationFinalize(destination)) {
- throw Exception(u"Failed to finalize image destination.");
- }
-
- CFRelease(quality_wrap);
- CFRelease(properties);
- CFRelease(destination);
- CFRelease(data_consumer);
- CFRelease(uti);
-}
-
-std::unique_ptr<IImage> QuartzImageFactory::CreateBitmap(int width,
- int height) {
- if (width <= 0) throw Exception(u"Image width should be greater than 0.");
- if (height <= 0) throw Exception(u"Image height should be greater than 0.");
-
- CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
-
- const auto buffer_size = width * height * 4;
- auto buffer = new unsigned char[buffer_size]{0};
-
- auto cg_data_provider = CGDataProviderCreateWithData(
- nullptr, buffer, buffer_size,
- [](void* info, const void* data, size_t size) {
- delete[] static_cast<const unsigned char*>(data);
- });
-
- auto cg_image =
- CGImageCreate(width, height, 8, 32, 4 * width, color_space,
- kCGImageAlphaPremultipliedLast, cg_data_provider, nullptr,
- true, kCGRenderingIntentDefault);
-
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(cg_data_provider);
-
- return std::unique_ptr<IImage>(
- new QuartzImage(GetGraphicsFactory(), this, cg_image, true, buffer));
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp
deleted file mode 100644
index a8c3715a..00000000
--- a/src/osx/graphics/quartz/Painter.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-#include "cru/osx/graphics/quartz/Painter.h"
-
-#include "cru/osx/graphics/quartz/Brush.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-#include "cru/osx/graphics/quartz/Geometry.h"
-#include "cru/osx/graphics/quartz/Image.h"
-#include "cru/osx/graphics/quartz/TextLayout.h"
-#include "cru/platform/Check.h"
-#include "cru/platform/Color.h"
-#include "cru/platform/Exception.h"
-
-namespace cru::platform::graphics::osx::quartz {
-QuartzCGContextPainter::QuartzCGContextPainter(
- IGraphicsFactory* graphics_factory, CGContextRef cg_context,
- bool auto_release, const Size& size,
- std::function<void(QuartzCGContextPainter*)> on_end_draw)
- : OsxQuartzResource(graphics_factory),
- cg_context_(cg_context),
- auto_release_(auto_release),
- 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_));
-}
-
-QuartzCGContextPainter::~QuartzCGContextPainter() {
- DoEndDraw();
- if (auto_release_) {
- CGContextRelease(cg_context_);
- cg_context_ = nullptr;
- }
-}
-
-Matrix QuartzCGContextPainter::GetTransform() { return transform_; }
-
-void QuartzCGContextPainter::SetTransform(const Matrix& matrix) {
- 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) {
- Validate();
-
- CGContextSetRGBFillColor(cg_context_, color.GetFloatRed(),
- color.GetFloatGreen(), color.GetFloatBlue(),
- color.GetFloatAlpha());
- CGContextFillRect(cg_context_, Convert(Rect{Point{}, size_}));
-}
-
-void QuartzCGContextPainter::DrawLine(const Point& start, const Point& end,
- IBrush* brush, float width) {
- Validate();
-
- CGContextBeginPath(cg_context_);
- CGContextMoveToPoint(cg_context_, start.x, start.y);
- CGContextAddLineToPoint(cg_context_, end.x, end.y);
-
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
- b->Select(cg_context_);
- SetLineWidth(width);
-
- CGContextStrokePath(cg_context_);
-}
-
-void QuartzCGContextPainter::StrokeRectangle(const Rect& rectangle,
- IBrush* brush, float width) {
- Validate();
-
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
- b->Select(cg_context_);
- CGContextStrokeRectWithWidth(cg_context_, Convert(rectangle), width);
-}
-
-void QuartzCGContextPainter::FillRectangle(const Rect& rectangle,
- IBrush* brush) {
- Validate();
-
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
- b->Select(cg_context_);
- CGContextFillRect(cg_context_, Convert(rectangle));
-}
-
-void QuartzCGContextPainter::StrokeEllipse(const Rect& outline_rect,
- IBrush* brush, float width) {
- Validate();
-
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
- b->Select(cg_context_);
- SetLineWidth(width);
-
- CGContextStrokeEllipseInRect(cg_context_, Convert(outline_rect));
-}
-
-void QuartzCGContextPainter::FillEllipse(const Rect& outline_rect,
- IBrush* brush) {
- Validate();
-
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
- b->Select(cg_context_);
- CGContextFillEllipseInRect(cg_context_, Convert(outline_rect));
-}
-
-void QuartzCGContextPainter::StrokeGeometry(IGeometry* geometry, IBrush* brush,
- float width) {
- Validate();
-
- QuartzGeometry* g = CheckPlatform<QuartzGeometry>(geometry, GetPlatformId());
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
-
- b->Select(cg_context_);
- SetLineWidth(width);
-
- CGContextBeginPath(cg_context_);
- CGContextAddPath(cg_context_, g->GetCGPath());
- CGContextStrokePath(cg_context_);
-}
-
-void QuartzCGContextPainter::FillGeometry(IGeometry* geometry, IBrush* brush) {
- Validate();
-
- QuartzGeometry* g = CheckPlatform<QuartzGeometry>(geometry, GetPlatformId());
- QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId());
-
- b->Select(cg_context_);
- CGContextBeginPath(cg_context_);
- CGContextAddPath(cg_context_, g->GetCGPath());
- CGContextEOFillPath(cg_context_);
-}
-
-void QuartzCGContextPainter::DrawText(const Point& offset,
- ITextLayout* text_layout, IBrush* brush) {
- Validate();
-
- auto tl = CheckPlatform<OsxCTTextLayout>(text_layout, GetPlatformId());
-
- Color color;
-
- if (auto b = dynamic_cast<QuartzSolidColorBrush*>(brush)) {
- color = b->GetColor();
- } else {
- color = colors::black;
- }
-
- Matrix transform = tl->GetTransform();
-
- 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::DrawImage(const Point& offset, IImage* image) {
- Validate();
- auto i = CheckPlatform<QuartzImage>(image, GetPlatformId());
-
- auto cg_image = i->GetCGImage();
-
- auto width = CGImageGetWidth(cg_image);
- auto height = CGImageGetHeight(cg_image);
-
- CGContextDrawImage(cg_context_, CGRectMake(offset.x, offset.y, width, height),
- cg_image);
-}
-
-void QuartzCGContextPainter::PushLayer(const Rect& bounds) {
- Validate();
- clip_stack_.push_back(bounds);
- CGContextClipToRect(cg_context_, Convert(bounds));
-}
-
-void QuartzCGContextPainter::PopLayer() {
- Validate();
- clip_stack_.pop_back();
- if (clip_stack_.empty()) {
- CGContextResetClip(cg_context_);
- } else {
- CGContextClipToRect(cg_context_, Convert(clip_stack_.back()));
- }
-}
-
-void QuartzCGContextPainter::PushState() {
- Validate();
- CGContextSaveGState(cg_context_);
-}
-
-void QuartzCGContextPainter::PopState() {
- Validate();
- CGContextRestoreGState(cg_context_);
-}
-
-void QuartzCGContextPainter::EndDraw() { DoEndDraw(); }
-
-void QuartzCGContextPainter::SetLineWidth(float width) {
- if (cg_context_) {
- CGContextSetLineWidth(cg_context_, width);
- }
-}
-
-void QuartzCGContextPainter::DoEndDraw() {
- if (cg_context_) {
- CGContextFlush(cg_context_);
- CGContextSynchronize(cg_context_);
-
- on_end_draw_(this);
- }
-}
-
-void QuartzCGContextPainter::Validate() {
- if (cg_context_ == nullptr)
- throw ReuseException(u"QuartzCGContextPainter has already be released.");
-}
-} // namespace cru::platform::graphics::osx::quartz
diff --git a/src/osx/graphics/quartz/Resource.cpp b/src/osx/graphics/quartz/Resource.cpp
deleted file mode 100644
index 00bd5c94..00000000
--- a/src/osx/graphics/quartz/Resource.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "cru/osx/graphics/quartz/Resource.h"
diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp
deleted file mode 100644
index 6013efba..00000000
--- a/src/osx/graphics/quartz/TextLayout.cpp
+++ /dev/null
@@ -1,456 +0,0 @@
-#include "cru/osx/graphics/quartz/TextLayout.h"
-#include "cru/common/Base.h"
-#include "cru/common/Format.h"
-#include "cru/common/StringUtil.h"
-#include "cru/osx/Convert.h"
-#include "cru/osx/graphics/quartz/Convert.h"
-#include "cru/osx/graphics/quartz/Resource.h"
-#include "cru/platform/Check.h"
-#include "cru/platform/graphics/Base.h"
-
-#include <algorithm>
-#include <limits>
-
-namespace cru::platform::graphics::osx::quartz {
-using cru::platform::osx::Convert;
-
-OsxCTTextLayout::OsxCTTextLayout(IGraphicsFactory* graphics_factory,
- std::shared_ptr<OsxCTFont> font,
- const String& str)
- : OsxQuartzResource(graphics_factory),
- max_width_(std::numeric_limits<float>::max()),
- max_height_(std::numeric_limits<float>::max()),
- font_(std::move(font)),
- text_(str) {
- Expects(font_);
-
- DoSetText(std::move(text_));
-
- RecreateFrame();
-}
-
-OsxCTTextLayout::~OsxCTTextLayout() {
- ReleaseResource();
- CFRelease(cf_attributed_text_);
-}
-
-void OsxCTTextLayout::SetFont(std::shared_ptr<IFont> font) {
- font_ = CheckPlatform<OsxCTFont>(font, GetPlatformId());
- RecreateFrame();
-}
-
-void OsxCTTextLayout::DoSetText(String text) {
- text_ = std::move(text);
-
- if (text_.empty()) {
- head_empty_line_count_ = 0;
- tail_empty_line_count_ = 1;
-
- actual_text_ = {};
- } else {
- head_empty_line_count_ = 0;
- tail_empty_line_count_ = 0;
-
- for (auto i = text_.cbegin(); i != text_.cend(); ++i) {
- if (*i == u'\n') {
- head_empty_line_count_++;
- } else {
- break;
- }
- }
-
- for (auto i = text_.crbegin(); i != text_.crend(); ++i) {
- if (*i == u'\n') {
- tail_empty_line_count_++;
- } else {
- break;
- }
- }
-
- if (text_.size() == tail_empty_line_count_) {
- head_empty_line_count_ = 1;
- actual_text_ = {};
- } else {
- actual_text_ = String(text_.cbegin() + head_empty_line_count_,
- text_.cend() - tail_empty_line_count_);
- }
- }
-
- CFStringRef s = Convert(actual_text_);
- cf_attributed_text_ = CFAttributedStringCreateMutable(nullptr, 0);
- CFAttributedStringReplaceString(cf_attributed_text_, CFRangeMake(0, 0), s);
- Ensures(cf_attributed_text_);
- CFAttributedStringSetAttribute(
- cf_attributed_text_,
- CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)),
- kCTFontAttributeName, font_->GetCTFont());
- CFRelease(s);
-}
-
-void OsxCTTextLayout::SetText(String new_text) {
- if (new_text == text_) return;
-
- CFRelease(cf_attributed_text_);
- DoSetText(std::move(new_text));
-
- RecreateFrame();
-}
-
-void OsxCTTextLayout::SetMaxWidth(float max_width) {
- max_width_ = max_width;
- RecreateFrame();
-}
-
-void OsxCTTextLayout::SetMaxHeight(float max_height) {
- max_height_ = max_height;
- RecreateFrame();
-}
-
-bool OsxCTTextLayout::IsEditMode() { return edit_mode_; }
-
-void OsxCTTextLayout::SetEditMode(bool enable) {
- edit_mode_ = enable;
- RecreateFrame();
-}
-
-Index OsxCTTextLayout::GetLineIndexFromCharIndex(Index char_index) {
- if (char_index < 0 || char_index >= text_.size()) {
- return -1;
- }
-
- auto line_index = 0;
- for (Index i = 0; i < char_index; ++i) {
- if (text_[i] == u'\n') {
- line_index++;
- }
- }
-
- return line_index;
-}
-
-Index OsxCTTextLayout::GetLineCount() { return line_count_; }
-
-float OsxCTTextLayout::GetLineHeight(Index line_index) {
- if (line_index < 0 || line_index >= line_count_) {
- return 0.0f;
- }
- return line_heights_[line_index];
-}
-
-Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) {
- if (text_.empty() && edit_mode_) return Rect(0, 0, 0, font_->GetFontSize());
-
- auto result = DoGetTextBoundsIncludingEmptyLines(includingTrailingSpace);
- return Rect(0, 0, result.size.width, result.size.height);
-}
-
-std::vector<Rect> OsxCTTextLayout::TextRangeRect(const TextRange& text_range) {
- if (text_.empty()) return {};
-
- auto tr = text_range;
- tr = text_range.CoerceInto(head_empty_line_count_,
- text_.size() - tail_empty_line_count_);
- tr.position -= head_empty_line_count_;
-
- std::vector<CGRect> results = DoTextRangeRect(tr);
- std::vector<Rect> r;
-
- for (auto& rect : results) {
- r.push_back(transform_.TransformRect(Convert(rect)));
- }
-
- return r;
-}
-
-Rect OsxCTTextLayout::TextSinglePoint(Index position, bool trailing) {
- Expects(position >= 0 && position <= text_.size());
-
- if (text_.empty()) return {0, 0, 0, font_->GetFontSize()};
-
- if (position < head_empty_line_count_) {
- return {0, position * font_->GetFontSize(), 0, font_->GetFontSize()};
- } else if (position > text_.size() - tail_empty_line_count_) {
- return {
- 0,
- static_cast<float>(text_bounds_without_trailing_space_.size.height) +
- (head_empty_line_count_ + position -
- (text_.size() - tail_empty_line_count_) - 1) *
- font_->GetFontSize(),
- 0, font_->GetFontSize()};
- } else {
- auto result =
- DoTextSinglePoint(position - head_empty_line_count_, trailing);
- return transform_.TransformRect(Convert(result));
- }
-}
-
-TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) {
- if (point.y < head_empty_line_count_ * font_->GetFontSize()) {
- if (point.y < 0) {
- return {0, false, false};
- } else {
- for (int i = 1; i <= head_empty_line_count_; ++i) {
- if (point.y < i * font_->GetFontSize()) {
- return {i - 1, false, false};
- }
- }
- }
- }
-
- auto text_bounds = text_bounds_without_trailing_space_;
-
- auto text_height = static_cast<float>(text_bounds.size.height);
- auto th = text_height + head_empty_line_count_ * font_->GetFontSize();
- if (point.y >= th) {
- for (int i = 1; i <= tail_empty_line_count_; ++i) {
- if (point.y < th + i * font_->GetFontSize()) {
- return {text_.size() - (tail_empty_line_count_ - i), false, false};
- }
- }
- return {text_.size(), false, false};
- }
-
- auto p = point;
- p.y -= head_empty_line_count_ * font_->GetFontSize();
- p.y = text_height - p.y;
-
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- auto line_origin = line_origins_[i];
-
- auto range = CTLineGetStringRange(line);
-
- CGRect bounds{line_origin.x, line_origin.y - line_descents_[i],
- CTLineGetOffsetForStringIndex(
- line, range.location + range.length, nullptr),
- line_heights_[i]};
-
- bool force_inside = false;
- if (i == 0 && p.y >= bounds.origin.y + bounds.size.height) {
- force_inside = true;
- }
-
- if (i == line_count_ - 1 && p.y < bounds.origin.y) {
- force_inside = true;
- }
-
- if (p.y >= bounds.origin.y || force_inside) {
- auto pp = p;
- pp.y = bounds.origin.y;
- Index po;
- bool inside_text;
-
- if (pp.x < bounds.origin.x) {
- po = actual_text_.IndexFromCodePointToCodeUnit(range.location);
- inside_text = false;
- } else if (pp.x > bounds.origin.x + bounds.size.width) {
- po = actual_text_.IndexFromCodePointToCodeUnit(range.location +
- range.length);
- inside_text = false;
- } else {
- int position = CTLineGetStringIndexForPosition(
- line,
- CGPointMake(pp.x - line_origins_[i].x, pp.y - line_origins_[i].y));
-
- po = actual_text_.IndexFromCodePointToCodeUnit(position);
- inside_text = true;
- }
-
- if (po != 0 &&
- po == actual_text_.IndexFromCodePointToCodeUnit(range.location +
- range.length) &&
- actual_text_[po - 1] == u'\n') {
- --po;
- }
-
- return {po + head_empty_line_count_, false, inside_text};
- }
- }
-
- return TextHitTestResult{0, false, false};
-}
-
-void OsxCTTextLayout::ReleaseResource() {
- line_count_ = 0;
- line_origins_.clear();
- lines_.clear();
- line_ascents_.clear();
- line_descents_.clear();
- line_heights_.clear();
- if (ct_framesetter_) CFRelease(ct_framesetter_);
- if (ct_frame_) CFRelease(ct_frame_);
-}
-
-void OsxCTTextLayout::RecreateFrame() {
- ReleaseResource();
-
- ct_framesetter_ =
- CTFramesetterCreateWithAttributedString(cf_attributed_text_);
- Ensures(ct_framesetter_);
-
- CFRange fit_range;
-
- suggest_height_ =
- CTFramesetterSuggestFrameSizeWithConstraints(
- ct_framesetter_,
- CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)),
- nullptr, CGSizeMake(max_width_, max_height_), &fit_range)
- .height;
-
- auto path = CGPathCreateMutable();
- Ensures(path);
- CGPathAddRect(path, nullptr, CGRectMake(0, 0, max_width_, suggest_height_));
-
- ct_frame_ = CTFramesetterCreateFrame(
- ct_framesetter_,
- CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), path,
- nullptr);
- Ensures(ct_frame_);
-
- CGPathRelease(path);
-
- const auto lines = CTFrameGetLines(ct_frame_);
- line_count_ = CFArrayGetCount(lines);
- lines_.resize(line_count_);
- line_origins_.resize(line_count_);
- line_ascents_.resize(line_count_);
- line_descents_.resize(line_count_);
- line_heights_.resize(line_count_);
- CTFrameGetLineOrigins(ct_frame_, CFRangeMake(0, 0), line_origins_.data());
- for (int i = 0; i < line_count_; i++) {
- lines_[i] = static_cast<CTLineRef>(CFArrayGetValueAtIndex(lines, i));
- double ascent, descent;
- CTLineGetTypographicBounds(lines_[i], &ascent, &descent, nullptr);
- line_ascents_[i] = static_cast<float>(ascent);
- line_descents_[i] = static_cast<float>(descent);
- line_heights_[i] = line_ascents_[i] + line_descents_[i];
- }
-
- auto bounds = DoGetTextBounds(false);
- text_bounds_without_trailing_space_ = bounds;
- text_bounds_with_trailing_space_ = DoGetTextBounds(true);
-
- auto right = bounds.origin.x + bounds.size.width;
- auto bottom = bounds.origin.y + bounds.size.height;
-
- transform_ =
- Matrix::Translation(-right / 2, -bottom / 2) * Matrix::Scale(1, -1) *
- Matrix::Translation(right / 2, bottom / 2) *
- Matrix::Translation(0, head_empty_line_count_ * font_->GetFontSize());
-}
-
-CTFrameRef OsxCTTextLayout::CreateFrameWithColor(const Color& color) {
- auto path = CGPathCreateMutable();
- CGPathAddRect(path, nullptr, CGRectMake(0, 0, max_width_, suggest_height_));
-
- CGColorRef cg_color =
- CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(),
- color.GetFloatBlue(), color.GetFloatAlpha());
- CFAttributedStringSetAttribute(
- cf_attributed_text_,
- CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)),
- kCTForegroundColorAttributeName, cg_color);
-
- auto frame = CTFramesetterCreateFrame(
- ct_framesetter_,
- CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), path,
- nullptr);
- Ensures(frame);
-
- CGPathRelease(path);
-
- return frame;
-}
-
-String OsxCTTextLayout::GetDebugString() {
- return Format(u"OsxCTTextLayout(text: {}, size: ({}, {}))", text_, max_width_,
- max_height_);
-}
-
-CGRect OsxCTTextLayout::DoGetTextBounds(bool includingTrailingSpace) {
- if (actual_text_.empty()) return CGRect{};
-
- auto rects = DoTextRangeRect(TextRange{0, actual_text_.size()});
-
- float left = std::numeric_limits<float>::max();
- float bottom = std::numeric_limits<float>::max();
- float right = 0;
- float top = 0;
-
- for (auto& rect : rects) {
- if (rect.origin.x < left) left = rect.origin.x;
- if (rect.origin.y < bottom) bottom = rect.origin.y;
- if (rect.origin.x + rect.size.width > right)
- right = rect.origin.x + rect.size.width;
- if (rect.origin.y + rect.size.height > top)
- top = rect.origin.y + rect.size.height;
- }
-
- return CGRectMake(left, bottom, right - left, top - bottom);
-}
-
-CGRect OsxCTTextLayout::DoGetTextBoundsIncludingEmptyLines(
- bool includingTrailingSpace) {
- auto result = includingTrailingSpace ? text_bounds_with_trailing_space_
- : text_bounds_without_trailing_space_;
-
- result.size.height += head_empty_line_count_ * font_->GetFontSize();
- result.size.height += tail_empty_line_count_ * font_->GetFontSize();
-
- return result;
-}
-
-std::vector<CGRect> OsxCTTextLayout::DoTextRangeRect(
- const TextRange& text_range) {
- const auto r =
- actual_text_.RangeFromCodeUnitToCodePoint(text_range).Normalize();
-
- std::vector<CGRect> results;
-
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- auto line_origin = line_origins_[i];
-
- Range range = Convert(CTLineGetStringRange(line));
- range = range.CoerceInto(r.GetStart(), r.GetEnd());
-
- if (range.count) {
- CGRect line_rect{line_origin.x, line_origin.y - line_descents_[i], 0,
- line_heights_[i]};
- float start_offset =
- CTLineGetOffsetForStringIndex(line, range.GetStart(), nullptr);
- float end_offset =
- CTLineGetOffsetForStringIndex(line, range.GetEnd(), nullptr);
- line_rect.origin.x += start_offset;
- line_rect.size.width = end_offset - start_offset;
- results.push_back(line_rect);
- }
- }
-
- return results;
-}
-
-CGRect OsxCTTextLayout::DoTextSinglePoint(Index position, bool trailing) {
- Expects(position >= 0 && position <= actual_text_.size());
-
- if (actual_text_.empty()) return CGRectMake(0, 0, 0, font_->GetFontSize());
-
- position = actual_text_.IndexFromCodeUnitToCodePoint(position);
-
- for (int i = 0; i < line_count_; i++) {
- auto line = lines_[i];
- auto line_origin = line_origins_[i];
-
- CFRange range = CTLineGetStringRange(line);
- if (range.location <= position &&
- position < range.location + range.length ||
- i == line_count_ - 1 && position == range.location + range.length) {
- auto offset = CTLineGetOffsetForStringIndex(line, position, nullptr);
- return CGRectMake(offset + line_origin.x,
- line_origin.y - line_descents_[i], 0, line_heights_[i]);
- }
- }
-
- UnreachableCode();
-}
-} // namespace cru::platform::graphics::osx::quartz