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