| OLD | NEW |
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include "core/fxcrt/fx_ext.h" | 7 #include "core/fxcrt/fx_ext.h" |
| 8 | 8 |
| 9 #ifndef _SKIA_SUPPORT_ | 9 #ifndef _SKIA_SUPPORT_ |
| 10 #include "core/fxge/agg/fx_agg_driver.h" | 10 #include "core/fxge/agg/fx_agg_driver.h" |
| 11 #endif | 11 #endif |
| 12 | 12 |
| 13 #include "core/fxcrt/fx_memory.h" | 13 #include "core/fxcrt/fx_memory.h" |
| 14 #include "core/fxge/cfx_gemodule.h" | 14 #include "core/fxge/cfx_gemodule.h" |
| 15 #include "core/fxge/cfx_graphstatedata.h" | 15 #include "core/fxge/cfx_graphstatedata.h" |
| 16 #include "core/fxge/cfx_pathdata.h" | 16 #include "core/fxge/cfx_pathdata.h" |
| 17 #include "core/fxge/cfx_renderdevice.h" | 17 #include "core/fxge/cfx_renderdevice.h" |
| 18 #include "core/fxge/dib/dib_int.h" | 18 #include "core/fxge/dib/dib_int.h" |
| 19 #include "core/fxge/fx_freetype.h" | 19 #include "core/fxge/fx_freetype.h" |
| 20 #include "core/fxge/ge/fx_text_int.h" | 20 #include "core/fxge/ge/fx_text_int.h" |
| 21 #include "third_party/base/ptr_util.h" | 21 #include "third_party/base/ptr_util.h" |
| 22 | 22 |
| 23 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ | |
| 24 #include "core/fxge/apple/apple_int.h" | 23 #include "core/fxge/apple/apple_int.h" |
| 25 #include "core/fxge/apple/cfx_quartzdevice.h" | |
| 26 #ifndef CGFLOAT_IS_DOUBLE | 24 #ifndef CGFLOAT_IS_DOUBLE |
| 27 #error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers | 25 #error Expected CGFLOAT_IS_DOUBLE to be defined by CoreGraphics headers |
| 28 #endif | 26 #endif |
| 29 | 27 |
| 30 void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap) { | 28 void* CQuartz2D::createGraphics(CFX_DIBitmap* pBitmap) { |
| 31 if (!pBitmap) { | 29 if (!pBitmap) |
| 32 return nullptr; | 30 return nullptr; |
| 33 } | |
| 34 CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little; | 31 CGBitmapInfo bmpInfo = kCGBitmapByteOrder32Little; |
| 35 switch (pBitmap->GetFormat()) { | 32 switch (pBitmap->GetFormat()) { |
| 36 case FXDIB_Rgb32: | 33 case FXDIB_Rgb32: |
| 37 bmpInfo |= kCGImageAlphaNoneSkipFirst; | 34 bmpInfo |= kCGImageAlphaNoneSkipFirst; |
| 38 break; | 35 break; |
| 39 case FXDIB_Argb: | 36 case FXDIB_Argb: |
| 40 default: | 37 default: |
| 41 return nullptr; | 38 return nullptr; |
| 42 } | 39 } |
| 43 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); | 40 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); |
| 44 CGContextRef context = CGBitmapContextCreate( | 41 CGContextRef context = CGBitmapContextCreate( |
| 45 pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8, | 42 pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8, |
| 46 pBitmap->GetPitch(), colorSpace, bmpInfo); | 43 pBitmap->GetPitch(), colorSpace, bmpInfo); |
| 47 CGColorSpaceRelease(colorSpace); | 44 CGColorSpaceRelease(colorSpace); |
| 48 return context; | 45 return context; |
| 49 } | 46 } |
| 47 |
| 50 void CQuartz2D::destroyGraphics(void* graphics) { | 48 void CQuartz2D::destroyGraphics(void* graphics) { |
| 51 if (graphics) { | 49 if (graphics) |
| 52 CGContextRelease((CGContextRef)graphics); | 50 CGContextRelease((CGContextRef)graphics); |
| 53 } | |
| 54 } | 51 } |
| 52 |
| 55 void* CQuartz2D::CreateFont(const uint8_t* pFontData, uint32_t dwFontSize) { | 53 void* CQuartz2D::CreateFont(const uint8_t* pFontData, uint32_t dwFontSize) { |
| 56 CGDataProviderRef pDataProvider = CGDataProviderCreateWithData( | 54 CGDataProviderRef pDataProvider = CGDataProviderCreateWithData( |
| 57 nullptr, pFontData, (size_t)dwFontSize, nullptr); | 55 nullptr, pFontData, (size_t)dwFontSize, nullptr); |
| 58 if (!pDataProvider) | 56 if (!pDataProvider) |
| 59 return nullptr; | 57 return nullptr; |
| 60 | 58 |
| 61 CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider); | 59 CGFontRef pCGFont = CGFontCreateWithDataProvider(pDataProvider); |
| 62 CGDataProviderRelease(pDataProvider); | 60 CGDataProviderRelease(pDataProvider); |
| 63 return pCGFont; | 61 return pCGFont; |
| 64 } | 62 } |
| 63 |
| 65 void CQuartz2D::DestroyFont(void* pFont) { | 64 void CQuartz2D::DestroyFont(void* pFont) { |
| 66 CGFontRelease((CGFontRef)pFont); | 65 CGFontRelease((CGFontRef)pFont); |
| 67 } | 66 } |
| 67 |
| 68 void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_Matrix* matrix) { | 68 void CQuartz2D::setGraphicsTextMatrix(void* graphics, CFX_Matrix* matrix) { |
| 69 if (!graphics || !matrix) { | 69 if (!graphics || !matrix) |
| 70 return; | 70 return; |
| 71 } | |
| 72 CGContextRef context = (CGContextRef)graphics; | 71 CGContextRef context = (CGContextRef)graphics; |
| 73 CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f; | 72 CGFloat ty = CGBitmapContextGetHeight(context) - matrix->f; |
| 74 CGContextSetTextMatrix( | 73 CGContextSetTextMatrix( |
| 75 context, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, | 74 context, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, |
| 76 matrix->e, ty)); | 75 matrix->e, ty)); |
| 77 } | 76 } |
| 77 |
| 78 bool CQuartz2D::drawGraphicsString(void* graphics, | 78 bool CQuartz2D::drawGraphicsString(void* graphics, |
| 79 void* font, | 79 void* font, |
| 80 FX_FLOAT fontSize, | 80 FX_FLOAT fontSize, |
| 81 uint16_t* glyphIndices, | 81 uint16_t* glyphIndices, |
| 82 CGPoint* glyphPositions, | 82 CGPoint* glyphPositions, |
| 83 int32_t charsCount, | 83 int32_t charsCount, |
| 84 FX_ARGB argb, | 84 FX_ARGB argb, |
| 85 CFX_Matrix* matrix) { | 85 CFX_Matrix* matrix) { |
| 86 if (!graphics) { | 86 if (!graphics) |
| 87 return false; | 87 return false; |
| 88 } | |
| 89 CGContextRef context = (CGContextRef)graphics; | 88 CGContextRef context = (CGContextRef)graphics; |
| 90 CGContextSetFont(context, (CGFontRef)font); | 89 CGContextSetFont(context, (CGFontRef)font); |
| 91 CGContextSetFontSize(context, fontSize); | 90 CGContextSetFontSize(context, fontSize); |
| 92 if (matrix) { | 91 if (matrix) { |
| 93 CGAffineTransform m = CGContextGetTextMatrix(context); | 92 CGAffineTransform m = CGContextGetTextMatrix(context); |
| 94 m = CGAffineTransformConcat( | 93 m = CGAffineTransformConcat( |
| 95 m, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, | 94 m, CGAffineTransformMake(matrix->a, matrix->b, matrix->c, matrix->d, |
| 96 matrix->e, matrix->f)); | 95 matrix->e, matrix->f)); |
| 97 CGContextSetTextMatrix(context, m); | 96 CGContextSetTextMatrix(context, m); |
| 98 } | 97 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 110 CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions; | 109 CGPoint* glyphPositionsCG = (CGPoint*)glyphPositions; |
| 111 #endif | 110 #endif |
| 112 CGContextShowGlyphsAtPositions(context, (CGGlyph*)glyphIndices, | 111 CGContextShowGlyphsAtPositions(context, (CGGlyph*)glyphIndices, |
| 113 glyphPositionsCG, charsCount); | 112 glyphPositionsCG, charsCount); |
| 114 #if CGFLOAT_IS_DOUBLE | 113 #if CGFLOAT_IS_DOUBLE |
| 115 delete[] glyphPositionsCG; | 114 delete[] glyphPositionsCG; |
| 116 #endif | 115 #endif |
| 117 CGContextRestoreGState(context); | 116 CGContextRestoreGState(context); |
| 118 return true; | 117 return true; |
| 119 } | 118 } |
| 119 |
| 120 void CQuartz2D::saveGraphicsState(void* graphics) { | 120 void CQuartz2D::saveGraphicsState(void* graphics) { |
| 121 if (graphics) { | 121 if (graphics) |
| 122 CGContextSaveGState((CGContextRef)graphics); | 122 CGContextSaveGState((CGContextRef)graphics); |
| 123 } | |
| 124 } | |
| 125 void CQuartz2D::restoreGraphicsState(void* graphics) { | |
| 126 if (graphics) { | |
| 127 CGContextRestoreGState((CGContextRef)graphics); | |
| 128 } | |
| 129 } | |
| 130 static CGContextRef createContextWithBitmap(CFX_DIBitmap* pBitmap) { | |
| 131 if (!pBitmap || pBitmap->IsCmykImage() || pBitmap->GetBPP() < 32) { | |
| 132 return nullptr; | |
| 133 } | |
| 134 CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Little; | |
| 135 if (pBitmap->HasAlpha()) { | |
| 136 bitmapInfo |= kCGImageAlphaPremultipliedFirst; | |
| 137 } else { | |
| 138 bitmapInfo |= kCGImageAlphaNoneSkipFirst; | |
| 139 } | |
| 140 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); | |
| 141 CGContextRef context = CGBitmapContextCreate( | |
| 142 pBitmap->GetBuffer(), pBitmap->GetWidth(), pBitmap->GetHeight(), 8, | |
| 143 pBitmap->GetPitch(), colorSpace, bitmapInfo); | |
| 144 CGColorSpaceRelease(colorSpace); | |
| 145 return context; | |
| 146 } | |
| 147 CFX_QuartzDeviceDriver::CFX_QuartzDeviceDriver(CGContextRef context, | |
| 148 int32_t deviceClass) { | |
| 149 m_saveCount = 0; | |
| 150 m_context = context; | |
| 151 m_deviceClass = deviceClass; | |
| 152 CGContextRetain(m_context); | |
| 153 CGRect r = CGContextGetClipBoundingBox(context); | |
| 154 m_width = FXSYS_round(r.size.width); | |
| 155 m_height = FXSYS_round(r.size.height); | |
| 156 m_renderCaps = FXRC_SOFT_CLIP | FXRC_BLEND_MODE | FXRC_ALPHA_PATH | | |
| 157 FXRC_ALPHA_IMAGE | FXRC_BIT_MASK | FXRC_ALPHA_MASK; | |
| 158 if (m_deviceClass != FXDC_DISPLAY) { | |
| 159 } else { | |
| 160 CGImageRef image = CGBitmapContextCreateImage(m_context); | |
| 161 if (image) { | |
| 162 m_renderCaps |= FXRC_GET_BITS; | |
| 163 m_width = CGImageGetWidth(image); | |
| 164 m_height = CGImageGetHeight(image); | |
| 165 CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(image); | |
| 166 if (kCGImageAlphaPremultipliedFirst == alphaInfo || | |
| 167 kCGImageAlphaPremultipliedLast == alphaInfo || | |
| 168 kCGImageAlphaOnly == alphaInfo) { | |
| 169 m_renderCaps |= FXRC_ALPHA_OUTPUT; | |
| 170 } | |
| 171 } | |
| 172 CGImageRelease(image); | |
| 173 } | |
| 174 CGAffineTransform ctm = CGContextGetCTM(m_context); | |
| 175 CGContextSaveGState(m_context); | |
| 176 m_saveCount++; | |
| 177 if (ctm.d >= 0) { | |
| 178 CGFloat offset_x, offset_y; | |
| 179 offset_x = ctm.tx; | |
| 180 offset_y = ctm.ty; | |
| 181 CGContextTranslateCTM(m_context, -offset_x, -offset_y); | |
| 182 CGContextConcatCTM(m_context, CGAffineTransformMake(1, 0, 0, -1, offset_x, | |
| 183 m_height + offset_y)); | |
| 184 } | |
| 185 m_foxitDevice2User = CGAffineTransformIdentity; | |
| 186 m_user2FoxitDevice = CGAffineTransformInvert(m_foxitDevice2User); | |
| 187 } | |
| 188 CFX_QuartzDeviceDriver::~CFX_QuartzDeviceDriver() { | |
| 189 CGContextRestoreGState(m_context); | |
| 190 m_saveCount--; | |
| 191 for (int i = 0; i < m_saveCount; ++i) { | |
| 192 CGContextRestoreGState(m_context); | |
| 193 } | |
| 194 if (m_context) { | |
| 195 CGContextRelease(m_context); | |
| 196 } | |
| 197 } | |
| 198 int CFX_QuartzDeviceDriver::GetDeviceCaps(int capsID) const { | |
| 199 switch (capsID) { | |
| 200 case FXDC_DEVICE_CLASS: | |
| 201 return m_deviceClass; | |
| 202 case FXDC_PIXEL_WIDTH: | |
| 203 return m_width; | |
| 204 case FXDC_PIXEL_HEIGHT: | |
| 205 return m_height; | |
| 206 case FXDC_BITS_PIXEL: | |
| 207 return 32; | |
| 208 case FXDC_RENDER_CAPS: | |
| 209 return m_renderCaps; | |
| 210 default: | |
| 211 return 0; | |
| 212 } | |
| 213 } | |
| 214 CFX_Matrix CFX_QuartzDeviceDriver::GetCTM() const { | |
| 215 CGAffineTransform ctm = CGContextGetCTM(m_context); | |
| 216 return CFX_Matrix(ctm.a, ctm.b, ctm.c, ctm.d, ctm.tx, ctm.ty); | |
| 217 } | |
| 218 void CFX_QuartzDeviceDriver::SaveState() { | |
| 219 CGContextSaveGState(m_context); | |
| 220 m_saveCount++; | |
| 221 } | 123 } |
| 222 | 124 |
| 223 void CFX_QuartzDeviceDriver::RestoreState(bool isKeepSaved) { | 125 void CQuartz2D::restoreGraphicsState(void* graphics) { |
| 224 CGContextRestoreGState(m_context); | 126 if (graphics) |
| 225 if (isKeepSaved) { | 127 CGContextRestoreGState((CGContextRef)graphics); |
| 226 CGContextSaveGState(m_context); | |
| 227 } else { | |
| 228 m_saveCount--; | |
| 229 } | |
| 230 } | 128 } |
| 231 | |
| 232 bool CFX_QuartzDeviceDriver::SetClip_PathFill(const CFX_PathData* pathData, | |
| 233 const CFX_Matrix* matrix, | |
| 234 int fillMode) { | |
| 235 SaveState(); | |
| 236 CGAffineTransform m = CGAffineTransformIdentity; | |
| 237 if (matrix) { | |
| 238 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), | |
| 239 matrix->GetD(), matrix->GetE(), matrix->GetF()); | |
| 240 } | |
| 241 m = CGAffineTransformConcat(m, m_foxitDevice2User); | |
| 242 CGContextConcatCTM(m_context, m); | |
| 243 setPathToContext(pathData); | |
| 244 RestoreState(false); | |
| 245 if ((fillMode & 3) == FXFILL_WINDING) { | |
| 246 CGContextClip(m_context); | |
| 247 } else { | |
| 248 CGContextEOClip(m_context); | |
| 249 } | |
| 250 return true; | |
| 251 } | |
| 252 FX_FLOAT CFX_QuartzDeviceDriver::getLineWidth( | |
| 253 const CFX_GraphStateData* graphState, | |
| 254 CGAffineTransform ctm) { | |
| 255 FX_FLOAT lineWidth = graphState->m_LineWidth; | |
| 256 if (graphState->m_LineWidth <= 0.f) { | |
| 257 CGSize size; | |
| 258 size.width = 1; | |
| 259 size.height = 1; | |
| 260 CGSize temp = CGSizeApplyAffineTransform(size, ctm); | |
| 261 CGFloat x = 1 / temp.width; | |
| 262 CGFloat y = 1 / temp.height; | |
| 263 lineWidth = x > y ? x : y; | |
| 264 } | |
| 265 return lineWidth; | |
| 266 } | |
| 267 bool CFX_QuartzDeviceDriver::SetClip_PathStroke( | |
| 268 const CFX_PathData* pathData, | |
| 269 const CFX_Matrix* matrix, | |
| 270 const CFX_GraphStateData* graphState) { | |
| 271 SaveState(); | |
| 272 CGAffineTransform m = CGAffineTransformIdentity; | |
| 273 if (matrix) { | |
| 274 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), | |
| 275 matrix->GetD(), matrix->GetE(), matrix->GetF()); | |
| 276 } | |
| 277 m = CGAffineTransformConcat(m, m_foxitDevice2User); | |
| 278 CGContextConcatCTM(m_context, m); | |
| 279 FX_FLOAT lineWidth = getLineWidth(graphState, m); | |
| 280 setStrokeInfo(graphState, 0xFF000000, lineWidth); | |
| 281 setPathToContext(pathData); | |
| 282 CGContextReplacePathWithStrokedPath(m_context); | |
| 283 RestoreState(false); | |
| 284 CGContextClip(m_context); | |
| 285 return true; | |
| 286 } | |
| 287 static CGBlendMode GetCGBlendMode(int blend_type) { | |
| 288 CGBlendMode mode = kCGBlendModeNormal; | |
| 289 switch (blend_type) { | |
| 290 case FXDIB_BLEND_NORMAL: | |
| 291 mode = kCGBlendModeNormal; | |
| 292 break; | |
| 293 case FXDIB_BLEND_MULTIPLY: | |
| 294 mode = kCGBlendModeMultiply; | |
| 295 break; | |
| 296 case FXDIB_BLEND_SCREEN: | |
| 297 mode = kCGBlendModeScreen; | |
| 298 break; | |
| 299 case FXDIB_BLEND_OVERLAY: | |
| 300 mode = kCGBlendModeOverlay; | |
| 301 break; | |
| 302 case FXDIB_BLEND_DARKEN: | |
| 303 mode = kCGBlendModeDarken; | |
| 304 break; | |
| 305 case FXDIB_BLEND_LIGHTEN: | |
| 306 mode = kCGBlendModeLighten; | |
| 307 break; | |
| 308 case FXDIB_BLEND_COLORDODGE: | |
| 309 mode = kCGBlendModeColorDodge; | |
| 310 break; | |
| 311 case FXDIB_BLEND_COLORBURN: | |
| 312 mode = kCGBlendModeColorBurn; | |
| 313 break; | |
| 314 case FXDIB_BLEND_HARDLIGHT: | |
| 315 mode = kCGBlendModeHardLight; | |
| 316 break; | |
| 317 case FXDIB_BLEND_SOFTLIGHT: | |
| 318 mode = kCGBlendModeSoftLight; | |
| 319 break; | |
| 320 case FXDIB_BLEND_DIFFERENCE: | |
| 321 mode = kCGBlendModeDifference; | |
| 322 break; | |
| 323 case FXDIB_BLEND_EXCLUSION: | |
| 324 mode = kCGBlendModeExclusion; | |
| 325 break; | |
| 326 case FXDIB_BLEND_HUE: | |
| 327 mode = kCGBlendModeHue; | |
| 328 break; | |
| 329 case FXDIB_BLEND_SATURATION: | |
| 330 mode = kCGBlendModeSaturation; | |
| 331 break; | |
| 332 case FXDIB_BLEND_COLOR: | |
| 333 mode = kCGBlendModeColor; | |
| 334 break; | |
| 335 case FXDIB_BLEND_LUMINOSITY: | |
| 336 mode = kCGBlendModeLuminosity; | |
| 337 break; | |
| 338 default: | |
| 339 mode = kCGBlendModeNormal; | |
| 340 break; | |
| 341 } | |
| 342 return mode; | |
| 343 } | |
| 344 | |
| 345 bool CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData* pathData, | |
| 346 const CFX_Matrix* matrix, | |
| 347 const CFX_GraphStateData* graphState, | |
| 348 uint32_t fillArgb, | |
| 349 uint32_t strokeArgb, | |
| 350 int fillMode, | |
| 351 int blend_type) { | |
| 352 SaveState(); | |
| 353 CGBlendMode mode = GetCGBlendMode(blend_type); | |
| 354 if (mode != kCGBlendModeNormal) { | |
| 355 CGContextSetBlendMode(m_context, mode); | |
| 356 } | |
| 357 CGAffineTransform m = CGAffineTransformIdentity; | |
| 358 if (matrix) { | |
| 359 m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), | |
| 360 matrix->GetD(), matrix->GetE(), matrix->GetF()); | |
| 361 } | |
| 362 m = CGAffineTransformConcat(m, m_foxitDevice2User); | |
| 363 CGContextConcatCTM(m_context, m); | |
| 364 int pathMode = 0; | |
| 365 if (graphState && strokeArgb) { | |
| 366 CGContextSetMiterLimit(m_context, graphState->m_MiterLimit); | |
| 367 FX_FLOAT lineWidth = getLineWidth(graphState, m); | |
| 368 setStrokeInfo(graphState, strokeArgb, lineWidth); | |
| 369 pathMode |= 4; | |
| 370 } | |
| 371 if (fillMode && fillArgb) { | |
| 372 setFillInfo(fillArgb); | |
| 373 if ((fillMode & 3) == FXFILL_WINDING) { | |
| 374 pathMode |= 1; | |
| 375 } else if ((fillMode & 3) == FXFILL_ALTERNATE) { | |
| 376 pathMode |= 2; | |
| 377 } | |
| 378 } | |
| 379 setPathToContext(pathData); | |
| 380 if (fillMode & FXFILL_FULLCOVER) { | |
| 381 CGContextSetShouldAntialias(m_context, false); | |
| 382 } | |
| 383 if (pathMode == 4) { | |
| 384 CGContextStrokePath(m_context); | |
| 385 } else if (pathMode == 1) { | |
| 386 CGContextFillPath(m_context); | |
| 387 } else if (pathMode == 2) { | |
| 388 CGContextEOFillPath(m_context); | |
| 389 } else if (pathMode == 5) { | |
| 390 CGContextDrawPath(m_context, kCGPathFillStroke); | |
| 391 } else if (pathMode == 6) { | |
| 392 CGContextDrawPath(m_context, kCGPathEOFillStroke); | |
| 393 } | |
| 394 RestoreState(false); | |
| 395 return true; | |
| 396 } | |
| 397 | |
| 398 bool CFX_QuartzDeviceDriver::FillRectWithBlend(const FX_RECT* rect, | |
| 399 FX_ARGB fillArgb, | |
| 400 int blend_type) { | |
| 401 CGBlendMode mode = GetCGBlendMode(blend_type); | |
| 402 if (mode != kCGBlendModeNormal) { | |
| 403 CGContextSetBlendMode(m_context, mode); | |
| 404 } | |
| 405 CGRect rect_fx = | |
| 406 CGRectMake(rect->left, rect->top, rect->Width(), rect->Height()); | |
| 407 CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, m_foxitDevice2User); | |
| 408 int32_t a, r, g, b; | |
| 409 ArgbDecode(fillArgb, a, r, g, b); | |
| 410 CGContextSetRGBFillColor(m_context, r / 255.f, g / 255.f, b / 255.f, | |
| 411 a / 255.f); | |
| 412 CGContextFillRect(m_context, rect_usr); | |
| 413 if (mode != kCGBlendModeNormal) { | |
| 414 CGContextSetBlendMode(m_context, kCGBlendModeNormal); | |
| 415 } | |
| 416 return true; | |
| 417 } | |
| 418 | |
| 419 bool CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, | |
| 420 FX_FLOAT y1, | |
| 421 FX_FLOAT x2, | |
| 422 FX_FLOAT y2, | |
| 423 uint32_t argb, | |
| 424 int blend_type) { | |
| 425 CGBlendMode mode = GetCGBlendMode(blend_type); | |
| 426 if (mode != kCGBlendModeNormal) { | |
| 427 CGContextSetBlendMode(m_context, mode); | |
| 428 } | |
| 429 CGPoint pt = | |
| 430 CGPointApplyAffineTransform(CGPointMake(x1, y1), m_foxitDevice2User); | |
| 431 x1 = pt.x; | |
| 432 y1 = pt.y; | |
| 433 pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), m_foxitDevice2User); | |
| 434 x2 = pt.x; | |
| 435 y2 = pt.y; | |
| 436 int32_t a, r, g, b; | |
| 437 ArgbDecode(argb, a, r, g, b); | |
| 438 CGContextSetRGBStrokeColor(m_context, r / 255.f, g / 255.f, b / 255.f, | |
| 439 a / 255.f); | |
| 440 CGContextMoveToPoint(m_context, x1, y1); | |
| 441 CGContextAddLineToPoint(m_context, x2, y2); | |
| 442 CGContextStrokePath(m_context); | |
| 443 if (mode != kCGBlendModeNormal) { | |
| 444 CGContextSetBlendMode(m_context, kCGBlendModeNormal); | |
| 445 } | |
| 446 return true; | |
| 447 } | |
| 448 | |
| 449 bool CFX_QuartzDeviceDriver::GetClipBox(FX_RECT* rect) { | |
| 450 CGRect r = CGContextGetClipBoundingBox(m_context); | |
| 451 r = CGRectApplyAffineTransform(r, m_user2FoxitDevice); | |
| 452 rect->left = FXSYS_floor(r.origin.x); | |
| 453 rect->top = FXSYS_floor(r.origin.y); | |
| 454 rect->right = FXSYS_ceil(r.origin.x + r.size.width); | |
| 455 rect->bottom = FXSYS_ceil(r.origin.y + r.size.height); | |
| 456 return true; | |
| 457 } | |
| 458 | |
| 459 bool CFX_QuartzDeviceDriver::GetDIBits(CFX_DIBitmap* bitmap, | |
| 460 int32_t left, | |
| 461 int32_t top) { | |
| 462 if (FXDC_PRINTER == m_deviceClass || bitmap->GetBPP() < 32 || | |
| 463 !(m_renderCaps | FXRC_GET_BITS)) { | |
| 464 return false; | |
| 465 } | |
| 466 | |
| 467 CGPoint pt = CGPointMake(left, top); | |
| 468 pt = CGPointApplyAffineTransform(pt, m_foxitDevice2User); | |
| 469 CGAffineTransform ctm = CGContextGetCTM(m_context); | |
| 470 pt.x *= FXSYS_fabs(ctm.a); | |
| 471 pt.y *= FXSYS_fabs(ctm.d); | |
| 472 CGImageRef image = CGBitmapContextCreateImage(m_context); | |
| 473 if (!image) | |
| 474 return false; | |
| 475 | |
| 476 CGFloat width = (CGFloat)bitmap->GetWidth(); | |
| 477 CGFloat height = (CGFloat)bitmap->GetHeight(); | |
| 478 if (width + pt.x > m_width) | |
| 479 width -= (width + pt.x - m_width); | |
| 480 if (height + pt.y > m_height) | |
| 481 height -= (height + pt.y - m_height); | |
| 482 | |
| 483 CGImageRef subImage = CGImageCreateWithImageInRect( | |
| 484 image, CGRectMake(pt.x, pt.y, width, height)); | |
| 485 CGContextRef context = createContextWithBitmap(bitmap); | |
| 486 CGRect rect = CGContextGetClipBoundingBox(context); | |
| 487 CGContextClearRect(context, rect); | |
| 488 CGContextDrawImage(context, rect, subImage); | |
| 489 CGContextRelease(context); | |
| 490 CGImageRelease(subImage); | |
| 491 CGImageRelease(image); | |
| 492 if (!bitmap->HasAlpha()) | |
| 493 return true; | |
| 494 | |
| 495 for (int row = 0; row < bitmap->GetHeight(); row++) { | |
| 496 uint8_t* pScanline = (uint8_t*)bitmap->GetScanline(row); | |
| 497 for (int col = 0; col < bitmap->GetWidth(); col++) { | |
| 498 if (pScanline[3] > 0) { | |
| 499 pScanline[0] = (pScanline[0] * 255.f / pScanline[3] + .5f); | |
| 500 pScanline[1] = (pScanline[1] * 255.f / pScanline[3] + .5f); | |
| 501 pScanline[2] = (pScanline[2] * 255.f / pScanline[3] + .5f); | |
| 502 } | |
| 503 pScanline += 4; | |
| 504 } | |
| 505 } | |
| 506 return true; | |
| 507 } | |
| 508 | |
| 509 bool CFX_QuartzDeviceDriver::SetDIBits(const CFX_DIBSource* pBitmap, | |
| 510 FX_ARGB argb, | |
| 511 const FX_RECT* srcRect, | |
| 512 int dest_left, | |
| 513 int dest_top, | |
| 514 int blendType) { | |
| 515 SaveState(); | |
| 516 CGFloat src_left, src_top, src_width, src_height; | |
| 517 if (srcRect) { | |
| 518 src_left = srcRect->left; | |
| 519 src_top = srcRect->top; | |
| 520 src_width = srcRect->Width(); | |
| 521 src_height = srcRect->Height(); | |
| 522 } else { | |
| 523 src_left = src_top = 0; | |
| 524 src_width = pBitmap->GetWidth(); | |
| 525 src_height = pBitmap->GetHeight(); | |
| 526 } | |
| 527 CGAffineTransform ctm = CGContextGetCTM(m_context); | |
| 528 CGFloat scale_x = FXSYS_fabs(ctm.a); | |
| 529 CGFloat scale_y = FXSYS_fabs(ctm.d); | |
| 530 src_left /= scale_x; | |
| 531 src_top /= scale_y; | |
| 532 src_width /= scale_x; | |
| 533 src_height /= scale_y; | |
| 534 CGRect rect_fx = CGRectMake(dest_left, dest_top, src_width, src_height); | |
| 535 CGRect rect_usr = CGRectApplyAffineTransform(rect_fx, m_foxitDevice2User); | |
| 536 CGContextBeginPath(m_context); | |
| 537 CGContextAddRect(m_context, rect_usr); | |
| 538 CGContextClip(m_context); | |
| 539 rect_usr.size = | |
| 540 CGSizeMake(pBitmap->GetWidth() / scale_x, pBitmap->GetHeight() / scale_y); | |
| 541 rect_usr = CGRectOffset(rect_usr, -src_left, -src_top); | |
| 542 CG_SetImageTransform(dest_left, dest_top, src_width, src_height, &rect_usr); | |
| 543 CFX_DIBitmap* pBitmap1 = nullptr; | |
| 544 if (pBitmap->IsAlphaMask()) { | |
| 545 if (pBitmap->GetBuffer()) { | |
| 546 pBitmap1 = (CFX_DIBitmap*)pBitmap; | |
| 547 } else { | |
| 548 pBitmap1 = pBitmap->Clone(); | |
| 549 } | |
| 550 if (!pBitmap1) { | |
| 551 RestoreState(false); | |
| 552 return false; | |
| 553 } | |
| 554 CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData( | |
| 555 nullptr, pBitmap1->GetBuffer(), | |
| 556 pBitmap1->GetPitch() * pBitmap1->GetHeight(), nullptr); | |
| 557 CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray(); | |
| 558 CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault; | |
| 559 CGImageRef pImage = CGImageCreate( | |
| 560 pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(), | |
| 561 pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo, | |
| 562 pBitmapProvider, nullptr, true, kCGRenderingIntentDefault); | |
| 563 CGContextClipToMask(m_context, rect_usr, pImage); | |
| 564 CGContextSetRGBFillColor(m_context, FXARGB_R(argb) / 255.f, | |
| 565 FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f, | |
| 566 FXARGB_A(argb) / 255.f); | |
| 567 CGContextFillRect(m_context, rect_usr); | |
| 568 CGImageRelease(pImage); | |
| 569 CGColorSpaceRelease(pColorSpace); | |
| 570 CGDataProviderRelease(pBitmapProvider); | |
| 571 if (pBitmap1 != pBitmap) { | |
| 572 delete pBitmap1; | |
| 573 } | |
| 574 RestoreState(false); | |
| 575 return true; | |
| 576 } | |
| 577 if (pBitmap->GetBPP() < 32) { | |
| 578 pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32); | |
| 579 } else { | |
| 580 if (pBitmap->GetBuffer()) { | |
| 581 pBitmap1 = (CFX_DIBitmap*)pBitmap; | |
| 582 } else { | |
| 583 pBitmap1 = pBitmap->Clone(); | |
| 584 } | |
| 585 } | |
| 586 if (!pBitmap1) { | |
| 587 RestoreState(false); | |
| 588 return false; | |
| 589 } | |
| 590 if (pBitmap1->HasAlpha()) { | |
| 591 if (pBitmap1 == pBitmap) { | |
| 592 pBitmap1 = pBitmap->Clone(); | |
| 593 if (!pBitmap1) { | |
| 594 RestoreState(false); | |
| 595 return false; | |
| 596 } | |
| 597 } | |
| 598 for (int row = 0; row < pBitmap1->GetHeight(); row++) { | |
| 599 uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row); | |
| 600 for (int col = 0; col < pBitmap1->GetWidth(); col++) { | |
| 601 pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f); | |
| 602 pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f); | |
| 603 pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f); | |
| 604 pScanline += 4; | |
| 605 } | |
| 606 } | |
| 607 } | |
| 608 CGContextRef ctx = createContextWithBitmap(pBitmap1); | |
| 609 CGImageRef image = CGBitmapContextCreateImage(ctx); | |
| 610 int blend_mode = blendType; | |
| 611 if (FXDIB_BLEND_HARDLIGHT == blendType) { | |
| 612 blend_mode = kCGBlendModeSoftLight; | |
| 613 } else if (FXDIB_BLEND_SOFTLIGHT == blendType) { | |
| 614 blend_mode = kCGBlendModeHardLight; | |
| 615 } else if (blendType >= FXDIB_BLEND_NONSEPARABLE && | |
| 616 blendType <= FXDIB_BLEND_LUMINOSITY) { | |
| 617 blend_mode = blendType - 9; | |
| 618 } else if (blendType > FXDIB_BLEND_LUMINOSITY || blendType < 0) { | |
| 619 blend_mode = kCGBlendModeNormal; | |
| 620 } | |
| 621 CGContextSetBlendMode(m_context, (CGBlendMode)blend_mode); | |
| 622 CGContextDrawImage(m_context, rect_usr, image); | |
| 623 CGImageRelease(image); | |
| 624 CGContextRelease(ctx); | |
| 625 if (pBitmap1 != pBitmap) { | |
| 626 delete pBitmap1; | |
| 627 } | |
| 628 RestoreState(false); | |
| 629 return true; | |
| 630 } | |
| 631 | |
| 632 bool CFX_QuartzDeviceDriver::StretchDIBits(const CFX_DIBSource* pBitmap, | |
| 633 FX_ARGB argb, | |
| 634 int dest_left, | |
| 635 int dest_top, | |
| 636 int dest_width, | |
| 637 int dest_height, | |
| 638 const FX_RECT* clipRect, | |
| 639 uint32_t flags, | |
| 640 int blend_type) { | |
| 641 SaveState(); | |
| 642 if (clipRect) { | |
| 643 CGContextBeginPath(m_context); | |
| 644 CGRect rect_clip = CGRectMake(clipRect->left, clipRect->top, | |
| 645 clipRect->Width(), clipRect->Height()); | |
| 646 rect_clip = CGRectApplyAffineTransform(rect_clip, m_foxitDevice2User); | |
| 647 CGContextAddRect(m_context, rect_clip); | |
| 648 CGContextClip(m_context); | |
| 649 } | |
| 650 CGRect rect = CGRectMake(dest_left, dest_top, dest_width, dest_height); | |
| 651 rect = CGRectApplyAffineTransform(rect, m_foxitDevice2User); | |
| 652 if (FXDIB_BICUBIC_INTERPOL == flags) | |
| 653 CGContextSetInterpolationQuality(m_context, kCGInterpolationHigh); | |
| 654 else if (FXDIB_DOWNSAMPLE == flags) | |
| 655 CGContextSetInterpolationQuality(m_context, kCGInterpolationNone); | |
| 656 else | |
| 657 CGContextSetInterpolationQuality(m_context, kCGInterpolationMedium); | |
| 658 | |
| 659 CG_SetImageTransform(dest_left, dest_top, dest_width, dest_height, nullptr); | |
| 660 CFX_DIBitmap* pBitmap1 = nullptr; | |
| 661 if (pBitmap->IsAlphaMask()) { | |
| 662 if (pBitmap->GetBuffer()) | |
| 663 pBitmap1 = (CFX_DIBitmap*)pBitmap; | |
| 664 else | |
| 665 pBitmap1 = pBitmap->Clone(); | |
| 666 if (!pBitmap1) { | |
| 667 RestoreState(false); | |
| 668 return false; | |
| 669 } | |
| 670 CGDataProviderRef pBitmapProvider = CGDataProviderCreateWithData( | |
| 671 nullptr, pBitmap1->GetBuffer(), | |
| 672 pBitmap1->GetPitch() * pBitmap1->GetHeight(), nullptr); | |
| 673 CGColorSpaceRef pColorSpace = CGColorSpaceCreateDeviceGray(); | |
| 674 CGBitmapInfo bitmapInfo = kCGImageAlphaNone | kCGBitmapByteOrderDefault; | |
| 675 CGImageRef pImage = CGImageCreate( | |
| 676 pBitmap1->GetWidth(), pBitmap1->GetHeight(), pBitmap1->GetBPP(), | |
| 677 pBitmap1->GetBPP(), pBitmap1->GetPitch(), pColorSpace, bitmapInfo, | |
| 678 pBitmapProvider, nullptr, true, kCGRenderingIntentDefault); | |
| 679 CGContextClipToMask(m_context, rect, pImage); | |
| 680 CGContextSetRGBFillColor(m_context, FXARGB_R(argb) / 255.f, | |
| 681 FXARGB_G(argb) / 255.f, FXARGB_B(argb) / 255.f, | |
| 682 FXARGB_A(argb) / 255.f); | |
| 683 CGContextFillRect(m_context, rect); | |
| 684 CGImageRelease(pImage); | |
| 685 CGColorSpaceRelease(pColorSpace); | |
| 686 CGDataProviderRelease(pBitmapProvider); | |
| 687 if (pBitmap1 != pBitmap) | |
| 688 delete pBitmap1; | |
| 689 | |
| 690 RestoreState(false); | |
| 691 return true; | |
| 692 } | |
| 693 if (pBitmap->GetBPP() < 32) { | |
| 694 pBitmap1 = pBitmap->CloneConvert(FXDIB_Rgb32); | |
| 695 } else { | |
| 696 if (pBitmap->GetBuffer()) | |
| 697 pBitmap1 = (CFX_DIBitmap*)pBitmap; | |
| 698 else | |
| 699 pBitmap1 = pBitmap->Clone(); | |
| 700 } | |
| 701 if (!pBitmap1) { | |
| 702 RestoreState(false); | |
| 703 return false; | |
| 704 } | |
| 705 if (pBitmap1->HasAlpha()) { | |
| 706 if (pBitmap1 == pBitmap) { | |
| 707 pBitmap1 = pBitmap->Clone(); | |
| 708 if (!pBitmap1) { | |
| 709 RestoreState(false); | |
| 710 return false; | |
| 711 } | |
| 712 } | |
| 713 for (int row = 0; row < pBitmap1->GetHeight(); row++) { | |
| 714 uint8_t* pScanline = (uint8_t*)pBitmap1->GetScanline(row); | |
| 715 for (int col = 0; col < pBitmap1->GetWidth(); col++) { | |
| 716 pScanline[0] = (uint8_t)(pScanline[0] * pScanline[3] / 255.f + .5f); | |
| 717 pScanline[1] = (uint8_t)(pScanline[1] * pScanline[3] / 255.f + .5f); | |
| 718 pScanline[2] = (uint8_t)(pScanline[2] * pScanline[3] / 255.f + .5f); | |
| 719 pScanline += 4; | |
| 720 } | |
| 721 } | |
| 722 } | |
| 723 CGContextRef ctx = createContextWithBitmap(pBitmap1); | |
| 724 CGImageRef image = CGBitmapContextCreateImage(ctx); | |
| 725 CGContextDrawImage(m_context, rect, image); | |
| 726 CGImageRelease(image); | |
| 727 CGContextRelease(ctx); | |
| 728 if (pBitmap1 != pBitmap) | |
| 729 delete pBitmap1; | |
| 730 | |
| 731 RestoreState(false); | |
| 732 return true; | |
| 733 } | |
| 734 | |
| 735 bool CFX_QuartzDeviceDriver::StartDIBits(const CFX_DIBSource* pBitmap, | |
| 736 int bitmap_alpha, | |
| 737 uint32_t color, | |
| 738 const CFX_Matrix* pMatrix, | |
| 739 uint32_t flags, | |
| 740 void*& handle, | |
| 741 int blend_type) { | |
| 742 return false; | |
| 743 } | |
| 744 | |
| 745 bool CFX_QuartzDeviceDriver::CG_DrawGlyphRun(int nChars, | |
| 746 const FXTEXT_CHARPOS* pCharPos, | |
| 747 CFX_Font* pFont, | |
| 748 const CFX_Matrix* pGlyphMatrix, | |
| 749 const CFX_Matrix* pObject2Device, | |
| 750 FX_FLOAT font_size, | |
| 751 uint32_t argb) { | |
| 752 if (nChars == 0) | |
| 753 return true; | |
| 754 | |
| 755 CQuartz2D& quartz2d = | |
| 756 static_cast<CApplePlatform*>(CFX_GEModule::Get()->GetPlatformData()) | |
| 757 ->m_quartz2d; | |
| 758 if (!pFont->GetPlatformFont()) { | |
| 759 if (pFont->GetPsName() == "DFHeiStd-W5") | |
| 760 return false; | |
| 761 | |
| 762 pFont->SetPlatformFont( | |
| 763 quartz2d.CreateFont(pFont->GetFontData(), pFont->GetSize())); | |
| 764 if (!pFont->GetPlatformFont()) { | |
| 765 return false; | |
| 766 } | |
| 767 } | |
| 768 CFX_FixedBufGrow<uint16_t, 32> glyph_indices(nChars); | |
| 769 CFX_FixedBufGrow<CGPoint, 32> glyph_positions(nChars); | |
| 770 for (int i = 0; i < nChars; i++) { | |
| 771 glyph_indices[i] = pCharPos[i].m_ExtGID; | |
| 772 glyph_positions[i].x = pCharPos[i].m_OriginX; | |
| 773 glyph_positions[i].y = pCharPos[i].m_OriginY; | |
| 774 } | |
| 775 CFX_Matrix text_matrix; | |
| 776 if (pObject2Device) | |
| 777 text_matrix.Concat(*pObject2Device); | |
| 778 | |
| 779 CGAffineTransform matrix_cg = | |
| 780 CGAffineTransformMake(text_matrix.a, text_matrix.b, text_matrix.c, | |
| 781 text_matrix.d, text_matrix.e, text_matrix.f); | |
| 782 matrix_cg = CGAffineTransformConcat(matrix_cg, m_foxitDevice2User); | |
| 783 CGContextSetTextMatrix(m_context, matrix_cg); | |
| 784 CGContextSetFont(m_context, (CGFontRef)pFont->GetPlatformFont()); | |
| 785 CGContextSetFontSize(m_context, FXSYS_fabs(font_size)); | |
| 786 int32_t a, r, g, b; | |
| 787 ArgbDecode(argb, a, r, g, b); | |
| 788 CGContextSetRGBFillColor(m_context, r / 255.f, g / 255.f, b / 255.f, | |
| 789 a / 255.f); | |
| 790 SaveState(); | |
| 791 if (pGlyphMatrix) { | |
| 792 CGPoint origin = CGPointMake(glyph_positions[0].x, glyph_positions[0].y); | |
| 793 origin = CGPointApplyAffineTransform(origin, matrix_cg); | |
| 794 CGContextTranslateCTM(m_context, origin.x, origin.y); | |
| 795 CGAffineTransform glyph_matrix = CGAffineTransformMake( | |
| 796 pGlyphMatrix->a, pGlyphMatrix->b, pGlyphMatrix->c, pGlyphMatrix->d, | |
| 797 pGlyphMatrix->e, pGlyphMatrix->f); | |
| 798 if (m_foxitDevice2User.d < 0) | |
| 799 glyph_matrix = CGAffineTransformInvert(glyph_matrix); | |
| 800 | |
| 801 CGContextConcatCTM(m_context, glyph_matrix); | |
| 802 CGContextTranslateCTM(m_context, -origin.x, -origin.y); | |
| 803 } | |
| 804 CGContextShowGlyphsAtPositions(m_context, (CGGlyph*)glyph_indices, | |
| 805 glyph_positions, nChars); | |
| 806 RestoreState(false); | |
| 807 return true; | |
| 808 } | |
| 809 | |
| 810 bool CFX_QuartzDeviceDriver::DrawDeviceText(int nChars, | |
| 811 const FXTEXT_CHARPOS* pCharPos, | |
| 812 CFX_Font* pFont, | |
| 813 const CFX_Matrix* pObject2Device, | |
| 814 FX_FLOAT font_size, | |
| 815 uint32_t color) { | |
| 816 if (!pFont || !m_context) | |
| 817 return false; | |
| 818 | |
| 819 bool bBold = pFont->IsBold(); | |
| 820 if (!bBold && pFont->GetSubstFont() && | |
| 821 pFont->GetSubstFont()->m_Weight >= 500 && | |
| 822 pFont->GetSubstFont()->m_Weight <= 600) { | |
| 823 return false; | |
| 824 } | |
| 825 SaveState(); | |
| 826 CGContextSetTextDrawingMode(m_context, kCGTextFillClip); | |
| 827 bool ret = false; | |
| 828 int32_t i = 0; | |
| 829 while (i < nChars) { | |
| 830 if (pCharPos[i].m_bGlyphAdjust || font_size < 0) { | |
| 831 if (i > 0) { | |
| 832 ret = CG_DrawGlyphRun(i, pCharPos, pFont, nullptr, pObject2Device, | |
| 833 font_size, color); | |
| 834 if (!ret) { | |
| 835 RestoreState(false); | |
| 836 return ret; | |
| 837 } | |
| 838 } | |
| 839 const FXTEXT_CHARPOS* char_pos = pCharPos + i; | |
| 840 CFX_Matrix glphy_matrix; | |
| 841 if (font_size < 0) { | |
| 842 glphy_matrix.Concat(-1, 0, 0, -1, 0, 0); | |
| 843 } | |
| 844 if (char_pos->m_bGlyphAdjust) { | |
| 845 glphy_matrix.Concat( | |
| 846 char_pos->m_AdjustMatrix[0], char_pos->m_AdjustMatrix[1], | |
| 847 char_pos->m_AdjustMatrix[2], char_pos->m_AdjustMatrix[3], 0, 0); | |
| 848 } | |
| 849 ret = CG_DrawGlyphRun(1, char_pos, pFont, &glphy_matrix, pObject2Device, | |
| 850 font_size, color); | |
| 851 if (!ret) { | |
| 852 RestoreState(false); | |
| 853 return ret; | |
| 854 } | |
| 855 i++; | |
| 856 pCharPos += i; | |
| 857 nChars -= i; | |
| 858 i = 0; | |
| 859 } else { | |
| 860 i++; | |
| 861 } | |
| 862 } | |
| 863 if (i > 0) { | |
| 864 ret = CG_DrawGlyphRun(i, pCharPos, pFont, nullptr, pObject2Device, | |
| 865 font_size, color); | |
| 866 } | |
| 867 RestoreState(false); | |
| 868 return ret; | |
| 869 } | |
| 870 | |
| 871 void CFX_QuartzDeviceDriver::setStrokeInfo(const CFX_GraphStateData* graphState, | |
| 872 FX_ARGB argb, | |
| 873 FX_FLOAT lineWidth) { | |
| 874 if (!graphState) | |
| 875 return; | |
| 876 | |
| 877 CGContextSetLineWidth(m_context, lineWidth); | |
| 878 CGLineCap cap; | |
| 879 switch (graphState->m_LineCap) { | |
| 880 case CFX_GraphStateData::LineCapRound: { | |
| 881 cap = kCGLineCapRound; | |
| 882 break; | |
| 883 } | |
| 884 case CFX_GraphStateData::LineCapSquare: { | |
| 885 cap = kCGLineCapSquare; | |
| 886 break; | |
| 887 } | |
| 888 case CFX_GraphStateData::LineCapButt: | |
| 889 default: { cap = kCGLineCapButt; } | |
| 890 } | |
| 891 CGContextSetLineCap(m_context, cap); | |
| 892 CGLineJoin join; | |
| 893 switch (graphState->m_LineJoin) { | |
| 894 case CFX_GraphStateData::LineJoinRound: { | |
| 895 join = kCGLineJoinRound; | |
| 896 break; | |
| 897 } | |
| 898 case CFX_GraphStateData::LineJoinBevel: { | |
| 899 join = kCGLineJoinBevel; | |
| 900 break; | |
| 901 } | |
| 902 case CFX_GraphStateData::LineJoinMiter: | |
| 903 default: { join = kCGLineJoinMiter; } | |
| 904 } | |
| 905 CGContextSetLineJoin(m_context, join); | |
| 906 if (graphState->m_DashCount) { | |
| 907 #if CGFLOAT_IS_DOUBLE | |
| 908 CGFloat* dashArray = new CGFloat[graphState->m_DashCount]; | |
| 909 for (int index = 0; index < graphState->m_DashCount; ++index) { | |
| 910 dashArray[index] = graphState->m_DashArray[index]; | |
| 911 } | |
| 912 #else | |
| 913 CGFloat* dashArray = (CGFloat*)graphState->m_DashArray; | |
| 914 #endif | |
| 915 CGContextSetLineDash(m_context, graphState->m_DashPhase, dashArray, | |
| 916 graphState->m_DashCount); | |
| 917 #if CGFLOAT_IS_DOUBLE | |
| 918 delete[] dashArray; | |
| 919 #endif | |
| 920 } | |
| 921 int32_t a, r, g, b; | |
| 922 ArgbDecode(argb, a, r, g, b); | |
| 923 CGContextSetRGBStrokeColor(m_context, r / 255.f, g / 255.f, b / 255.f, | |
| 924 a / 255.f); | |
| 925 } | |
| 926 void CFX_QuartzDeviceDriver::setFillInfo(FX_ARGB argb) { | |
| 927 int32_t a, r, g, b; | |
| 928 ArgbDecode(argb, a, r, g, b); | |
| 929 CGContextSetRGBFillColor(m_context, r / 255.f, g / 255.f, b / 255.f, | |
| 930 a / 255.f); | |
| 931 } | |
| 932 void CFX_QuartzDeviceDriver::setPathToContext(const CFX_PathData* pathData) { | |
| 933 int32_t count = pathData->GetPointCount(); | |
| 934 FX_PATHPOINT* points = pathData->GetPoints(); | |
| 935 CGContextBeginPath(m_context); | |
| 936 for (int32_t i = 0; i < count; i++) { | |
| 937 switch (points[i].m_Flag & FXPT_TYPE) { | |
| 938 case FXPT_MOVETO: | |
| 939 CGContextMoveToPoint(m_context, points[i].m_PointX, points[i].m_PointY); | |
| 940 break; | |
| 941 case FXPT_LINETO: | |
| 942 CGContextAddLineToPoint(m_context, points[i].m_PointX, | |
| 943 points[i].m_PointY); | |
| 944 break; | |
| 945 case FXPT_BEZIERTO: { | |
| 946 CGContextAddCurveToPoint(m_context, points[i].m_PointX, | |
| 947 points[i].m_PointY, points[i + 1].m_PointX, | |
| 948 points[i + 1].m_PointY, points[i + 2].m_PointX, | |
| 949 points[i + 2].m_PointY); | |
| 950 i += 2; | |
| 951 } | |
| 952 } | |
| 953 if (points[i].m_Flag & FXPT_CLOSEFIGURE) { | |
| 954 CGContextClosePath(m_context); | |
| 955 } | |
| 956 } | |
| 957 } | |
| 958 | |
| 959 void CFX_QuartzDeviceDriver::CG_SetImageTransform(int dest_left, | |
| 960 int dest_top, | |
| 961 int dest_width, | |
| 962 int dest_height, | |
| 963 CGRect* rect) { | |
| 964 int flip_y = m_foxitDevice2User.d * dest_height < 0 ? 1 : -1; | |
| 965 int flip_x = m_foxitDevice2User.a * dest_width > 0 ? 1 : -1; | |
| 966 if (flip_y >= 0 && flip_x >= 0) | |
| 967 return; | |
| 968 | |
| 969 if (dest_height < 0) { | |
| 970 dest_height = -dest_height; | |
| 971 dest_top -= dest_height; | |
| 972 } | |
| 973 CGRect rt = CGRectApplyAffineTransform( | |
| 974 CGRectMake(dest_left, dest_top, dest_width, dest_height), | |
| 975 m_foxitDevice2User); | |
| 976 CGFloat offset_x = (rt.origin.x) + rt.size.width / 2.f, | |
| 977 offset_y = (rt.origin.y) + rt.size.height / 2.f; | |
| 978 CGAffineTransform transform = CGAffineTransformIdentity; | |
| 979 transform = CGAffineTransformConcat( | |
| 980 transform, CGAffineTransformMake(1, 0, 0, 1, -offset_x, -offset_y)); | |
| 981 transform = CGAffineTransformConcat( | |
| 982 transform, CGAffineTransformMake(flip_x, 0, 0, flip_y, 0, 0)); | |
| 983 transform = CGAffineTransformConcat( | |
| 984 transform, CGAffineTransformMake(1, 0, 0, 1, offset_x, offset_y)); | |
| 985 CGContextConcatCTM(m_context, transform); | |
| 986 if (rect) | |
| 987 *rect = CGRectApplyAffineTransform(*rect, transform); | |
| 988 } | |
| 989 | |
| 990 void CFX_QuartzDeviceDriver::ClearDriver() { | |
| 991 if (!m_context) | |
| 992 return; | |
| 993 | |
| 994 for (int i = 0; i < m_saveCount; ++i) { | |
| 995 CGContextRestoreGState(m_context); | |
| 996 } | |
| 997 m_saveCount = 0; | |
| 998 if (m_context) { | |
| 999 CGContextRelease(m_context); | |
| 1000 } | |
| 1001 } | |
| 1002 CFX_QuartzDevice::CFX_QuartzDevice() { | |
| 1003 m_bOwnedBitmap = false; | |
| 1004 m_pContext = nullptr; | |
| 1005 } | |
| 1006 CFX_QuartzDevice::~CFX_QuartzDevice() { | |
| 1007 if (m_pContext) { | |
| 1008 CGContextRelease(m_pContext); | |
| 1009 } | |
| 1010 if (m_bOwnedBitmap) { | |
| 1011 delete GetBitmap(); | |
| 1012 } | |
| 1013 } | |
| 1014 CGContextRef CFX_QuartzDevice::GetContext() { | |
| 1015 return m_pContext; | |
| 1016 } | |
| 1017 bool CFX_QuartzDevice::Attach(CGContextRef context, int32_t nDeviceClass) { | |
| 1018 if (m_pContext) { | |
| 1019 CGContextRelease(m_pContext); | |
| 1020 } | |
| 1021 m_pContext = context; | |
| 1022 CGContextRetain(m_pContext); | |
| 1023 SetDeviceDriver( | |
| 1024 pdfium::MakeUnique<CFX_QuartzDeviceDriver>(m_pContext, nDeviceClass)); | |
| 1025 return true; | |
| 1026 } | |
| 1027 | |
| 1028 bool CFX_QuartzDevice::Attach(CFX_DIBitmap* pBitmap) { | |
| 1029 SetBitmap(pBitmap); | |
| 1030 m_pContext = createContextWithBitmap(pBitmap); | |
| 1031 if (!m_pContext) | |
| 1032 return false; | |
| 1033 | |
| 1034 SetDeviceDriver( | |
| 1035 pdfium::MakeUnique<CFX_QuartzDeviceDriver>(m_pContext, FXDC_DISPLAY)); | |
| 1036 return true; | |
| 1037 } | |
| 1038 | |
| 1039 bool CFX_QuartzDevice::Create(int32_t width, | |
| 1040 int32_t height, | |
| 1041 FXDIB_Format format) { | |
| 1042 if ((uint8_t)format < 32) { | |
| 1043 return false; | |
| 1044 } | |
| 1045 std::unique_ptr<CFX_DIBitmap> pBitmap(new CFX_DIBitmap); | |
| 1046 if (!pBitmap->Create(width, height, format)) | |
| 1047 return false; | |
| 1048 m_bOwnedBitmap = true; | |
| 1049 return Attach(pBitmap.release()); | |
| 1050 } | |
| 1051 #endif // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ | |
| OLD | NEW |