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 |