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