diff options
Diffstat (limited to 'src/osx/graphics/quartz')
-rw-r--r-- | src/osx/graphics/quartz/Brush.cpp | 36 | ||||
-rw-r--r-- | src/osx/graphics/quartz/CMakeLists.txt | 19 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Convert.cpp | 63 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Factory.cpp | 43 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Font.cpp | 30 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Geometry.cpp | 79 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Image.cpp | 58 | ||||
-rw-r--r-- | src/osx/graphics/quartz/ImageFactory.cpp | 109 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Painter.cpp | 230 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Resource.cpp | 1 | ||||
-rw-r--r-- | src/osx/graphics/quartz/TextLayout.cpp | 456 |
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 |