| // Copyright 2014 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fxge/apple/fx_quartz_device.h" |
| |
| #include <CoreGraphics/CoreGraphics.h> |
| |
| #include "core/fxcrt/fixed_size_data_vector.h" |
| #include "core/fxcrt/fx_extension.h" |
| #include "core/fxcrt/fx_memory_wrappers.h" |
| #include "core/fxcrt/zip.h" |
| #include "core/fxge/cfx_graphstatedata.h" |
| #include "core/fxge/cfx_path.h" |
| #include "core/fxge/cfx_renderdevice.h" |
| #include "core/fxge/dib/cfx_dibitmap.h" |
| |
| #ifndef CGFLOAT_IS_DOUBLE |
| #error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers |
| #endif |
| |
| FX_DATA_PARTITION_EXCEPTION(CGPoint); |
| |
| void* CQuartz2D::CreateGraphics(const RetainPtr<CFX_DIBitmap>& pBitmap) { |
| if (!pBitmap) |
| return nullptr; |
| CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little; |
| switch (pBitmap->GetFormat()) { |
| case FXDIB_Format::kRgb32: |
| bmpInfo |= kCGImageAlphaNoneSkipFirst; |
| break; |
| case FXDIB_Format::kArgb: |
| default: |
| return nullptr; |
| } |
| CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); |
| CGContextRef context = CGBitmapContextCreate( |
| pBitmap->GetWritableBuffer().data(), pBitmap->GetWidth(), |
| pBitmap->GetHeight(), 8, pBitmap->GetPitch(), colorSpace, bmpInfo); |
| CGColorSpaceRelease(colorSpace); |
| return context; |
| } |
| |
| void CQuartz2D::DestroyGraphics(void* graphics) { |
| if (graphics) |
| CGContextRelease((CGContextRef)graphics); |
| } |
| |
| void* CQuartz2D::CreateFont(pdfium::span<const uint8_t> font_data) { |
| CGDataProviderRef data_provider = CGDataProviderCreateWithData( |
| nullptr, font_data.data(), font_data.size(), nullptr); |
| if (!data_provider) { |
| return nullptr; |
| } |
| |
| CGFontRef cg_font = CGFontCreateWithDataProvider(data_provider); |
| CGDataProviderRelease(data_provider); |
| return cg_font; |
| } |
| |
| void CQuartz2D::DestroyFont(void* font) { |
| CGFontRelease((CGFontRef)font); |
| } |
| |
| void CQuartz2D::SetGraphicsTextMatrix(void* graphics, |
| const CFX_Matrix& matrix) { |
| if (!graphics) |
| return; |
| CGContextRef context = reinterpret_cast<CGContextRef>(graphics); |
| CGFloat ty = CGBitmapContextGetHeight(context) - matrix.f; |
| CGContextSetTextMatrix( |
| context, CGAffineTransformMake(matrix.a, matrix.b, matrix.c, matrix.d, |
| matrix.e, ty)); |
| } |
| |
| bool CQuartz2D::DrawGraphicsString(void* graphics, |
| void* font, |
| float font_size, |
| pdfium::span<uint16_t> glyph_indices, |
| pdfium::span<CGPoint> glyph_positions, |
| FX_ARGB argb) { |
| if (!graphics) |
| return false; |
| |
| CGContextRef context = (CGContextRef)graphics; |
| CGContextSetFont(context, (CGFontRef)font); |
| CGContextSetFontSize(context, font_size); |
| |
| const FX_BGRA_STRUCT<uint8_t> bgra = ArgbToBGRAStruct(argb); |
| CGContextSetRGBFillColor(context, bgra.red / 255.f, bgra.green / 255.f, |
| bgra.blue / 255.f, bgra.alpha / 255.f); |
| CGContextSaveGState(context); |
| #if CGFLOAT_IS_DOUBLE |
| auto glyph_positions_cg = |
| FixedSizeDataVector<CGPoint>::Uninit(glyph_positions.size()); |
| for (auto [input, output] : |
| fxcrt::Zip(glyph_positions, glyph_positions_cg.span())) { |
| output.x = input.x; |
| output.y = input.y; |
| } |
| const CGPoint* glyph_positions_cg_ptr = glyph_positions_cg.span().data(); |
| #else |
| const CGPoint* glyph_positions_cg_ptr = glyph_positions.data(); |
| #endif |
| CGContextShowGlyphsAtPositions( |
| context, reinterpret_cast<CGGlyph*>(glyph_indices.data()), |
| glyph_positions_cg_ptr, glyph_positions.size()); |
| CGContextRestoreGState(context); |
| return true; |
| } |