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/include/fx_agg_driver.h" 11 #include "core/src/fxge/dib/dib_int.h" 12 #include "core/src/fxge/ge/text_int.h" 13 14 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ 15 #include "apple_int.h" 16 #include "core/include/fxge/fx_ge_apple.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_ 1049