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