Line data Source code
1 : /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 : /* cairo - a vector graphics library with display and print output
3 : *
4 : * Copyright © 2008 Adrian Johnson
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it either under the terms of the GNU Lesser General Public
8 : * License version 2.1 as published by the Free Software Foundation
9 : * (the "LGPL") or, at your option, under the terms of the Mozilla
10 : * Public License Version 1.1 (the "MPL"). If you do not alter this
11 : * notice, a recipient may use your version of this file under either
12 : * the MPL or the LGPL.
13 : *
14 : * You should have received a copy of the LGPL along with this library
15 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 : * You should have received a copy of the MPL along with this library
18 : * in the file COPYING-MPL-1.1
19 : *
20 : * The contents of this file are subject to the Mozilla Public License
21 : * Version 1.1 (the "License"); you may not use this file except in
22 : * compliance with the License. You may obtain a copy of the License at
23 : * http://www.mozilla.org/MPL/
24 : *
25 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 : * the specific language governing rights and limitations.
28 : *
29 : * The Original Code is the cairo graphics library.
30 : *
31 : * The Initial Developer of the Original Code is Adrian Johnson.
32 : *
33 : * Contributor(s):
34 : * Adrian Johnson <ajohnson@redneon.com>
35 : */
36 :
37 : #include "cairoint.h"
38 :
39 : #if CAIRO_HAS_FONT_SUBSET
40 :
41 : #include "cairo-type3-glyph-surface-private.h"
42 : #include "cairo-output-stream-private.h"
43 : #include "cairo-recording-surface-private.h"
44 : #include "cairo-analysis-surface-private.h"
45 : #include "cairo-error-private.h"
46 : #include "cairo-surface-clipper-private.h"
47 :
48 : static const cairo_surface_backend_t cairo_type3_glyph_surface_backend;
49 :
50 : static cairo_status_t
51 0 : _cairo_type3_glyph_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
52 : cairo_path_fixed_t *path,
53 : cairo_fill_rule_t fill_rule,
54 : double tolerance,
55 : cairo_antialias_t antialias)
56 : {
57 0 : cairo_type3_glyph_surface_t *surface = cairo_container_of (clipper,
58 : cairo_type3_glyph_surface_t,
59 : clipper);
60 :
61 0 : if (path == NULL) {
62 0 : _cairo_output_stream_printf (surface->stream, "Q q\n");
63 0 : return CAIRO_STATUS_SUCCESS;
64 : }
65 :
66 0 : return _cairo_pdf_operators_clip (&surface->pdf_operators,
67 : path,
68 : fill_rule);
69 : }
70 :
71 : cairo_surface_t *
72 0 : _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
73 : cairo_output_stream_t *stream,
74 : cairo_type3_glyph_surface_emit_image_t emit_image,
75 : cairo_scaled_font_subsets_t *font_subsets)
76 : {
77 : cairo_type3_glyph_surface_t *surface;
78 : cairo_matrix_t invert_y_axis;
79 :
80 0 : if (unlikely (stream != NULL && stream->status))
81 0 : return _cairo_surface_create_in_error (stream->status);
82 :
83 0 : surface = malloc (sizeof (cairo_type3_glyph_surface_t));
84 0 : if (unlikely (surface == NULL))
85 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
86 :
87 0 : _cairo_surface_init (&surface->base,
88 : &cairo_type3_glyph_surface_backend,
89 : NULL, /* device */
90 : CAIRO_CONTENT_COLOR_ALPHA);
91 :
92 0 : surface->scaled_font = scaled_font;
93 0 : surface->stream = stream;
94 0 : surface->emit_image = emit_image;
95 :
96 : /* Setup the transform from the user-font device space to Type 3
97 : * font space. The Type 3 font space is defined by the FontMatrix
98 : * entry in the Type 3 dictionary. In the PDF backend this is an
99 : * identity matrix. */
100 0 : surface->cairo_to_pdf = scaled_font->scale_inverse;
101 0 : cairo_matrix_init_scale (&invert_y_axis, 1, -1);
102 0 : cairo_matrix_multiply (&surface->cairo_to_pdf, &surface->cairo_to_pdf, &invert_y_axis);
103 :
104 0 : _cairo_pdf_operators_init (&surface->pdf_operators,
105 : surface->stream,
106 : &surface->cairo_to_pdf,
107 : font_subsets);
108 :
109 0 : _cairo_surface_clipper_init (&surface->clipper,
110 : _cairo_type3_glyph_surface_clipper_intersect_clip_path);
111 :
112 0 : return &surface->base;
113 : }
114 :
115 : static cairo_status_t
116 0 : _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface,
117 : cairo_image_surface_t *image,
118 : cairo_matrix_t *image_matrix)
119 : {
120 : cairo_status_t status;
121 :
122 : /* The only image type supported by Type 3 fonts are 1-bit masks */
123 0 : image = _cairo_image_surface_coerce_to_format (image, CAIRO_FORMAT_A1);
124 0 : status = image->base.status;
125 0 : if (unlikely (status))
126 0 : return status;
127 :
128 0 : _cairo_output_stream_printf (surface->stream,
129 : "q %f %f %f %f %f %f cm\n",
130 : image_matrix->xx,
131 : image_matrix->xy,
132 : image_matrix->yx,
133 : image_matrix->yy,
134 : image_matrix->x0,
135 : image_matrix->y0);
136 :
137 0 : status = surface->emit_image (image, surface->stream);
138 0 : cairo_surface_destroy (&image->base);
139 :
140 0 : _cairo_output_stream_printf (surface->stream,
141 : "Q\n");
142 :
143 0 : return status;
144 : }
145 :
146 : static cairo_status_t
147 0 : _cairo_type3_glyph_surface_emit_image_pattern (cairo_type3_glyph_surface_t *surface,
148 : cairo_image_surface_t *image,
149 : const cairo_matrix_t *pattern_matrix)
150 : {
151 : cairo_matrix_t mat, upside_down;
152 : cairo_status_t status;
153 :
154 0 : if (image->width == 0 || image->height == 0)
155 0 : return CAIRO_STATUS_SUCCESS;
156 :
157 0 : mat = *pattern_matrix;
158 :
159 : /* Get the pattern space to user space matrix */
160 0 : status = cairo_matrix_invert (&mat);
161 :
162 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
163 0 : assert (status == CAIRO_STATUS_SUCCESS);
164 :
165 : /* Make this a pattern space to Type 3 font space matrix */
166 0 : cairo_matrix_multiply (&mat, &mat, &surface->cairo_to_pdf);
167 :
168 : /* PDF images are in a 1 unit by 1 unit image space. Turn the 1 by
169 : * 1 image upside down to convert to flip the Y-axis going from
170 : * cairo to PDF. Then scale the image up to the required size. */
171 0 : cairo_matrix_scale (&mat, image->width, image->height);
172 0 : cairo_matrix_init (&upside_down, 1, 0, 0, -1, 0, 1);
173 0 : cairo_matrix_multiply (&mat, &upside_down, &mat);
174 :
175 0 : return _cairo_type3_glyph_surface_emit_image (surface, image, &mat);
176 : }
177 :
178 : static cairo_status_t
179 0 : _cairo_type3_glyph_surface_finish (void *abstract_surface)
180 : {
181 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
182 :
183 0 : return _cairo_pdf_operators_fini (&surface->pdf_operators);
184 : }
185 :
186 : static cairo_int_status_t
187 0 : _cairo_type3_glyph_surface_paint (void *abstract_surface,
188 : cairo_operator_t op,
189 : const cairo_pattern_t *source,
190 : cairo_clip_t *clip)
191 : {
192 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
193 : const cairo_surface_pattern_t *pattern;
194 : cairo_image_surface_t *image;
195 : void *image_extra;
196 : cairo_status_t status;
197 :
198 0 : if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
199 0 : return CAIRO_INT_STATUS_IMAGE_FALLBACK;
200 :
201 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
202 0 : if (unlikely (status))
203 0 : return status;
204 :
205 0 : pattern = (const cairo_surface_pattern_t *) source;
206 0 : status = _cairo_surface_acquire_source_image (pattern->surface,
207 : &image, &image_extra);
208 0 : if (unlikely (status))
209 0 : goto fail;
210 :
211 0 : status = _cairo_type3_glyph_surface_emit_image_pattern (surface,
212 : image,
213 : &pattern->base.matrix);
214 :
215 : fail:
216 0 : _cairo_surface_release_source_image (pattern->surface, image, image_extra);
217 :
218 0 : return status;
219 : }
220 :
221 : static cairo_int_status_t
222 0 : _cairo_type3_glyph_surface_mask (void *abstract_surface,
223 : cairo_operator_t op,
224 : const cairo_pattern_t *source,
225 : const cairo_pattern_t *mask,
226 : cairo_clip_t *clip)
227 : {
228 0 : return _cairo_type3_glyph_surface_paint (abstract_surface,
229 : op, mask,
230 : clip);
231 : }
232 :
233 : static cairo_int_status_t
234 0 : _cairo_type3_glyph_surface_stroke (void *abstract_surface,
235 : cairo_operator_t op,
236 : const cairo_pattern_t *source,
237 : cairo_path_fixed_t *path,
238 : const cairo_stroke_style_t *style,
239 : const cairo_matrix_t *ctm,
240 : const cairo_matrix_t *ctm_inverse,
241 : double tolerance,
242 : cairo_antialias_t antialias,
243 : cairo_clip_t *clip)
244 : {
245 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
246 : cairo_int_status_t status;
247 :
248 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
249 0 : if (unlikely (status))
250 0 : return status;
251 :
252 0 : return _cairo_pdf_operators_stroke (&surface->pdf_operators,
253 : path,
254 : style,
255 : ctm,
256 : ctm_inverse);
257 : }
258 :
259 : static cairo_int_status_t
260 0 : _cairo_type3_glyph_surface_fill (void *abstract_surface,
261 : cairo_operator_t op,
262 : const cairo_pattern_t *source,
263 : cairo_path_fixed_t *path,
264 : cairo_fill_rule_t fill_rule,
265 : double tolerance,
266 : cairo_antialias_t antialias,
267 : cairo_clip_t *clip)
268 : {
269 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
270 : cairo_int_status_t status;
271 :
272 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
273 0 : if (unlikely (status))
274 0 : return status;
275 :
276 0 : return _cairo_pdf_operators_fill (&surface->pdf_operators,
277 : path,
278 : fill_rule);
279 : }
280 :
281 : static cairo_int_status_t
282 0 : _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
283 : cairo_operator_t op,
284 : const cairo_pattern_t *source,
285 : cairo_glyph_t *glyphs,
286 : int num_glyphs,
287 : cairo_scaled_font_t *scaled_font,
288 : cairo_clip_t *clip,
289 : int *remaining_glyphs)
290 : {
291 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
292 : cairo_int_status_t status;
293 : cairo_scaled_font_t *font;
294 : cairo_matrix_t new_ctm, invert_y_axis;
295 :
296 0 : status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
297 0 : if (unlikely (status))
298 0 : return status;
299 :
300 0 : cairo_matrix_init_scale (&invert_y_axis, 1, -1);
301 0 : cairo_matrix_multiply (&new_ctm, &invert_y_axis, &scaled_font->ctm);
302 0 : cairo_matrix_multiply (&new_ctm, &surface->cairo_to_pdf, &new_ctm);
303 0 : font = cairo_scaled_font_create (scaled_font->font_face,
304 0 : &scaled_font->font_matrix,
305 : &new_ctm,
306 0 : &scaled_font->options);
307 0 : if (unlikely (font->status))
308 0 : return font->status;
309 :
310 0 : status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
311 : NULL, 0,
312 : glyphs, num_glyphs,
313 : NULL, 0,
314 : FALSE,
315 : font);
316 :
317 0 : cairo_scaled_font_destroy (font);
318 :
319 0 : return status;
320 : }
321 :
322 : static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
323 : CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH,
324 : NULL, /* _cairo_type3_glyph_surface_create_similar */
325 : _cairo_type3_glyph_surface_finish,
326 : NULL, /* acquire_source_image */
327 : NULL, /* release_source_image */
328 : NULL, /* acquire_dest_image */
329 : NULL, /* release_dest_image */
330 : NULL, /* clone_similar */
331 : NULL, /* composite */
332 : NULL, /* fill_rectangles */
333 : NULL, /* composite_trapezoids */
334 : NULL, /* create_span_renderer */
335 : NULL, /* check_span_renderer */
336 : NULL, /* cairo_type3_glyph_surface_copy_page */
337 : NULL, /* _cairo_type3_glyph_surface_show_page */
338 : NULL, /* _cairo_type3_glyph_surface_get_extents */
339 : NULL, /* old_show_glyphs */
340 : NULL, /* _cairo_type3_glyph_surface_get_font_options */
341 : NULL, /* flush */
342 : NULL, /* mark_dirty_rectangle */
343 : NULL, /* scaled_font_fini */
344 : NULL, /* scaled_glyph_fini */
345 : _cairo_type3_glyph_surface_paint,
346 : _cairo_type3_glyph_surface_mask,
347 : _cairo_type3_glyph_surface_stroke,
348 : _cairo_type3_glyph_surface_fill,
349 : _cairo_type3_glyph_surface_show_glyphs,
350 : NULL, /* snapshot */
351 : };
352 :
353 : static void
354 0 : _cairo_type3_glyph_surface_set_stream (cairo_type3_glyph_surface_t *surface,
355 : cairo_output_stream_t *stream)
356 : {
357 0 : surface->stream = stream;
358 0 : _cairo_pdf_operators_set_stream (&surface->pdf_operators, stream);
359 0 : }
360 :
361 : static cairo_status_t
362 0 : _cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *surface,
363 : unsigned long glyph_index)
364 : {
365 : cairo_scaled_glyph_t *scaled_glyph;
366 : cairo_status_t status;
367 : cairo_image_surface_t *image;
368 : cairo_matrix_t mat;
369 : double x, y;
370 :
371 0 : status = _cairo_scaled_glyph_lookup (surface->scaled_font,
372 : glyph_index,
373 : CAIRO_SCALED_GLYPH_INFO_METRICS |
374 : CAIRO_SCALED_GLYPH_INFO_SURFACE,
375 : &scaled_glyph);
376 0 : if (unlikely (status))
377 0 : return status;
378 :
379 0 : image = scaled_glyph->surface;
380 0 : if (image->width == 0 || image->height == 0)
381 0 : return CAIRO_STATUS_SUCCESS;
382 :
383 0 : x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
384 0 : y = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y);
385 0 : mat.xx = image->width;
386 0 : mat.xy = 0;
387 0 : mat.yx = 0;
388 0 : mat.yy = image->height;
389 0 : mat.x0 = x;
390 0 : mat.y0 = y;
391 0 : cairo_matrix_multiply (&mat, &mat, &surface->scaled_font->scale_inverse);
392 0 : mat.y0 *= -1;
393 :
394 0 : return _cairo_type3_glyph_surface_emit_image (surface, image, &mat);
395 : }
396 :
397 : void
398 0 : _cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface,
399 : cairo_pdf_operators_use_font_subset_t use_font_subset,
400 : void *closure)
401 : {
402 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
403 :
404 0 : if (unlikely (surface->base.status))
405 0 : return;
406 :
407 0 : _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
408 : use_font_subset,
409 : closure);
410 : }
411 :
412 : cairo_status_t
413 0 : _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface,
414 : unsigned long glyph_index)
415 : {
416 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
417 : cairo_scaled_glyph_t *scaled_glyph;
418 : cairo_status_t status, status2;
419 : cairo_output_stream_t *null_stream;
420 :
421 0 : if (unlikely (surface->base.status))
422 0 : return surface->base.status;
423 :
424 0 : null_stream = _cairo_null_stream_create ();
425 0 : if (unlikely (null_stream->status))
426 0 : return null_stream->status;
427 :
428 0 : _cairo_type3_glyph_surface_set_stream (surface, null_stream);
429 :
430 0 : _cairo_scaled_font_freeze_cache (surface->scaled_font);
431 0 : status = _cairo_scaled_glyph_lookup (surface->scaled_font,
432 : glyph_index,
433 : CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
434 : &scaled_glyph);
435 :
436 0 : if (_cairo_status_is_error (status))
437 0 : goto cleanup;
438 :
439 0 : if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
440 0 : status = CAIRO_STATUS_SUCCESS;
441 0 : goto cleanup;
442 : }
443 :
444 0 : status = _cairo_recording_surface_replay (scaled_glyph->recording_surface,
445 : &surface->base);
446 0 : if (unlikely (status))
447 0 : goto cleanup;
448 :
449 0 : status = _cairo_pdf_operators_flush (&surface->pdf_operators);
450 0 : if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
451 0 : status = CAIRO_STATUS_SUCCESS;
452 :
453 : cleanup:
454 0 : _cairo_scaled_font_thaw_cache (surface->scaled_font);
455 :
456 0 : status2 = _cairo_output_stream_destroy (null_stream);
457 0 : if (status == CAIRO_STATUS_SUCCESS)
458 0 : status = status2;
459 :
460 0 : return status;
461 : }
462 :
463 : cairo_status_t
464 0 : _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
465 : cairo_output_stream_t *stream,
466 : unsigned long glyph_index,
467 : cairo_box_t *bbox,
468 : double *width)
469 : {
470 0 : cairo_type3_glyph_surface_t *surface = abstract_surface;
471 : cairo_scaled_glyph_t *scaled_glyph;
472 : cairo_status_t status, status2;
473 : double x_advance, y_advance;
474 : cairo_matrix_t font_matrix_inverse;
475 :
476 0 : if (unlikely (surface->base.status))
477 0 : return surface->base.status;
478 :
479 0 : _cairo_type3_glyph_surface_set_stream (surface, stream);
480 :
481 0 : _cairo_scaled_font_freeze_cache (surface->scaled_font);
482 0 : status = _cairo_scaled_glyph_lookup (surface->scaled_font,
483 : glyph_index,
484 : CAIRO_SCALED_GLYPH_INFO_METRICS |
485 : CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
486 : &scaled_glyph);
487 0 : if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
488 0 : status = _cairo_scaled_glyph_lookup (surface->scaled_font,
489 : glyph_index,
490 : CAIRO_SCALED_GLYPH_INFO_METRICS,
491 : &scaled_glyph);
492 0 : if (status == CAIRO_STATUS_SUCCESS)
493 0 : status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
494 : }
495 0 : if (_cairo_status_is_error (status)) {
496 0 : _cairo_scaled_font_thaw_cache (surface->scaled_font);
497 0 : return status;
498 : }
499 :
500 0 : x_advance = scaled_glyph->metrics.x_advance;
501 0 : y_advance = scaled_glyph->metrics.y_advance;
502 0 : font_matrix_inverse = surface->scaled_font->font_matrix;
503 0 : status2 = cairo_matrix_invert (&font_matrix_inverse);
504 :
505 : /* The invertability of font_matrix is tested in
506 : * pdf_operators_show_glyphs before any glyphs are mapped to the
507 : * subset. */
508 0 : assert (status2 == CAIRO_STATUS_SUCCESS);
509 :
510 0 : cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
511 0 : *width = x_advance;
512 :
513 0 : *bbox = scaled_glyph->bbox;
514 0 : _cairo_matrix_transform_bounding_box_fixed (&surface->scaled_font->scale_inverse,
515 : bbox, NULL);
516 :
517 0 : _cairo_output_stream_printf (surface->stream,
518 : "%f 0 %f %f %f %f d1\n",
519 : x_advance,
520 : _cairo_fixed_to_double (bbox->p1.x),
521 0 : - _cairo_fixed_to_double (bbox->p2.y),
522 : _cairo_fixed_to_double (bbox->p2.x),
523 0 : - _cairo_fixed_to_double (bbox->p1.y));
524 :
525 0 : if (status == CAIRO_STATUS_SUCCESS) {
526 : cairo_output_stream_t *mem_stream;
527 :
528 0 : mem_stream = _cairo_memory_stream_create ();
529 0 : status = mem_stream->status;
530 0 : if (unlikely (status))
531 0 : goto FAIL;
532 :
533 0 : _cairo_type3_glyph_surface_set_stream (surface, mem_stream);
534 :
535 0 : _cairo_output_stream_printf (surface->stream, "q\n");
536 0 : status = _cairo_recording_surface_replay (scaled_glyph->recording_surface,
537 : &surface->base);
538 :
539 0 : status2 = _cairo_pdf_operators_flush (&surface->pdf_operators);
540 0 : if (status == CAIRO_STATUS_SUCCESS)
541 0 : status = status2;
542 :
543 0 : _cairo_output_stream_printf (surface->stream, "Q\n");
544 :
545 0 : _cairo_type3_glyph_surface_set_stream (surface, stream);
546 0 : if (status == CAIRO_STATUS_SUCCESS)
547 0 : _cairo_memory_stream_copy (mem_stream, stream);
548 :
549 0 : status2 = _cairo_output_stream_destroy (mem_stream);
550 0 : if (status == CAIRO_STATUS_SUCCESS)
551 0 : status = status2;
552 : }
553 :
554 0 : if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
555 0 : status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);
556 :
557 : FAIL:
558 0 : _cairo_scaled_font_thaw_cache (surface->scaled_font);
559 :
560 0 : return status;
561 : }
562 :
563 : #endif /* CAIRO_HAS_FONT_SUBSET */
|