1 /* Lasem
2 *
3 * Copyright © 2009-2012 Emmanuel Pacaud
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author:
21 * Emmanuel Pacaud <emmanuel@gnome.org>
22 */
23
24 /**
25 * SECTION:lsmdomview
26 * @short_description: Base class for DOM views
27 */
28
29 #include <lsmdebug.h>
30 #include <lsmdomdocument.h>
31 #include <lsmdomview.h>
32
33 static GObjectClass *parent_class;
34
35 /**
36 * lsm_dom_view_get_resolution:
37 * @self: A #LsmDomView
38 *
39 * Returns: view resolution, in pixel per inch.
40 */
41
42 double
lsm_dom_view_get_resolution(LsmDomView * self)43 lsm_dom_view_get_resolution (LsmDomView *self)
44 {
45 g_return_val_if_fail (LSM_IS_DOM_VIEW (self), 0.0);
46
47 return self->resolution_ppi;
48 }
49
50 /**
51 * lsm_dom_view_set_resolution:
52 * @self: a #LsmDomView
53 * @ppi: resolution, in pixel per inch.
54 *
55 * Set the view resolution, in pixel per inch.
56 */
57
58 void
lsm_dom_view_set_resolution(LsmDomView * self,double ppi)59 lsm_dom_view_set_resolution (LsmDomView *self, double ppi)
60 {
61 g_return_if_fail (LSM_IS_DOM_VIEW (self));
62
63 if (ppi < 0.0)
64 self->resolution_ppi = LSM_DOM_VIEW_DEFAULT_RESOLUTION;
65 else
66 self->resolution_ppi = ppi;
67 }
68
69 /**
70 * lsm_dom_view_set_viewport:
71 * @self: a #LsmDomView
72 * @viewport_pt: viewport size, in points
73 *
74 * Set the viewport size.
75 */
76
77 void
lsm_dom_view_set_viewport(LsmDomView * self,const LsmBox * viewport_pt)78 lsm_dom_view_set_viewport (LsmDomView *self, const LsmBox *viewport_pt)
79 {
80 g_return_if_fail (LSM_IS_DOM_VIEW (self));
81 g_return_if_fail (viewport_pt != NULL);
82
83 self->viewport_pt = *viewport_pt;
84 }
85
86 /**
87 * lsm_dom_view_set_viewport_pixels:
88 * @self: a #LsmDomView
89 * @viewport: viewport size, in pixels
90 *
91 * Set the viewport size.
92 */
93
94 void
lsm_dom_view_set_viewport_pixels(LsmDomView * self,const LsmBox * viewport)95 lsm_dom_view_set_viewport_pixels (LsmDomView *self, const LsmBox *viewport)
96 {
97 g_return_if_fail (LSM_IS_DOM_VIEW (self));
98 g_return_if_fail (viewport != NULL);
99
100 self->viewport_pt.x = viewport->x * 72.0 / self->resolution_ppi;
101 self->viewport_pt.y = viewport->y * 72.0 / self->resolution_ppi;
102 self->viewport_pt.width = viewport->width * 72.0 / self->resolution_ppi;
103 self->viewport_pt.height = viewport->height * 72.0 / self->resolution_ppi;
104 }
105
106 /**
107 * lsm_dom_view_get_viewport:
108 * @self: a #LsmDomView
109 *
110 * Returns: viewport size, in points.
111 */
112
113 LsmBox
lsm_dom_view_get_viewport(LsmDomView * self)114 lsm_dom_view_get_viewport (LsmDomView *self)
115 {
116 static const LsmBox null_viewport = {0, 0, 0, 0};
117
118 g_return_val_if_fail (LSM_IS_DOM_VIEW (self), null_viewport);
119
120 return self->viewport_pt;
121 }
122
123 /**
124 * lsm_dom_view_get_viewport_pixels:
125 * @self: a #LsmDomView
126 *
127 * Returns: viewport size, in pixels.
128 */
129
130 LsmBox
lsm_dom_view_get_viewport_pixels(LsmDomView * self)131 lsm_dom_view_get_viewport_pixels (LsmDomView *self)
132 {
133 LsmBox viewport = {0, 0, 0, 0};
134
135 g_return_val_if_fail (LSM_IS_DOM_VIEW (self), viewport);
136
137 viewport.x = self->viewport_pt.x * self->resolution_ppi / 72.0;
138 viewport.y = self->viewport_pt.y * self->resolution_ppi / 72.0;
139 viewport.width = self->viewport_pt.width * self->resolution_ppi / 72.0;
140 viewport.height = self->viewport_pt.height * self->resolution_ppi / 72.0;
141
142 return viewport;
143 }
144
145 /**
146 * lsm_dom_view_get_size:
147 * @view: a #LsmDomView
148 * @width: (out) (optional): view width placeholder, in points
149 * @height: (out) (optional): view height placeholder, in points
150 * @baseline: (out) (optional): view baseline, in points
151 *
152 * Get the view size and baseline. Baseline is for use of view inside bloc of text.
153 */
154
155 void
lsm_dom_view_get_size(LsmDomView * view,double * width,double * height,double * baseline)156 lsm_dom_view_get_size (LsmDomView *view, double *width, double *height, double *baseline)
157 {
158 LsmDomViewClass *view_class;
159 double dummy_width = 0.0;
160 double dummy_height = 0.0;
161
162 g_return_if_fail (LSM_IS_DOM_VIEW (view));
163 g_return_if_fail (view->document != NULL);
164
165 if (width == NULL)
166 width = &dummy_width;
167 if (height == NULL)
168 height = &dummy_height;
169
170 view_class = LSM_DOM_VIEW_GET_CLASS (view);
171 if (view_class->measure != NULL)
172 view_class->measure (view, width, height, baseline);
173 }
174
175 /**
176 * lsm_dom_view_get_size_pixels:
177 * @view: a #LsmDomView
178 * @width: (out) (optional): view width placeholder, in pixels
179 * @height: (out) (optional): view height placeholder, in pixels
180 * @baseline: (out) (optional): view baseline, in pixels
181 *
182 * Get the view size and baseline. Baseline is for use of view inside bloc of text.
183 */
184
185 void
lsm_dom_view_get_size_pixels(LsmDomView * view,unsigned int * width,unsigned int * height,unsigned int * baseline)186 lsm_dom_view_get_size_pixels (LsmDomView *view, unsigned int *width, unsigned int *height, unsigned int *baseline)
187 {
188 double resolution_ppi;
189 double width_pt;
190 double height_pt;
191 double baseline_pt;
192
193 g_return_if_fail (LSM_IS_DOM_VIEW (view));
194 g_return_if_fail (view->document != NULL);
195
196 resolution_ppi = view->resolution_ppi;
197 g_return_if_fail (resolution_ppi > 0.0);
198
199 width_pt = width != NULL ? *width * 72.0 / resolution_ppi : 0.0;
200 height_pt = height != NULL ? *height * 72.0 / resolution_ppi : 0.0;
201 baseline_pt = baseline != NULL? *baseline * 72.0 /resolution_ppi : 0.0;
202
203 lsm_dom_view_get_size (view, &width_pt, &height_pt,&baseline_pt);
204
205 if (width != NULL)
206 *width = (double) (0.5 + width_pt * resolution_ppi / 72.0);
207 if (height != NULL)
208 *height = (double) (0.5 + height_pt * resolution_ppi / 72.0);
209 if (baseline != NULL)
210 *baseline = (double) (0.5 + baseline_pt * resolution_ppi / 72.0);
211 }
212
213 static void
lsm_dom_view_set_cairo_context(LsmDomView * view,cairo_t * cairo)214 lsm_dom_view_set_cairo_context (LsmDomView *view, cairo_t *cairo)
215 {
216 PangoContext *context;
217 cairo_font_options_t *font_options;
218 const cairo_font_options_t *current_font_options;
219 cairo_surface_t *surface;
220 cairo_surface_type_t type;
221
222 g_return_if_fail (LSM_IS_DOM_VIEW (view));
223
224 if (view->cairo == cairo)
225 return;
226
227 if (view->cairo != NULL) {
228 cairo_destroy (view->cairo);
229 g_object_unref (view->pango_layout);
230 }
231
232 if (cairo == NULL) {
233 view->cairo = NULL;
234 view->pango_layout = NULL;
235
236 return;
237 }
238
239 cairo_reference (cairo);
240 view->cairo = cairo;
241 view->pango_layout = pango_cairo_create_layout (cairo);
242
243 surface = cairo_get_target (cairo);
244
245 type = cairo_surface_get_type (surface);
246
247 view->is_vector = (type == CAIRO_SURFACE_TYPE_SVG ||
248 type == CAIRO_SURFACE_TYPE_PDF ||
249 type == CAIRO_SURFACE_TYPE_PS);
250
251 context = pango_layout_get_context (view->pango_layout);
252 pango_cairo_context_set_resolution (context, 72);
253
254 current_font_options = pango_cairo_context_get_font_options (context);
255 if (current_font_options == NULL)
256 font_options = cairo_font_options_create ();
257 else
258 font_options = cairo_font_options_copy (current_font_options);
259 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
260 pango_cairo_context_set_font_options (context, font_options);
261 cairo_font_options_destroy (font_options);
262 }
263
264 /**
265 * lsm_dom_view_render:
266 * @view: a #LsmDomView
267 * @cairo: cairo context
268 * @x: x posiiton for rendering
269 * @y: y position for rendering
270 *
271 * Render @view in the @cairo context.
272 */
273
274 void
lsm_dom_view_render(LsmDomView * view,cairo_t * cairo,double x,double y)275 lsm_dom_view_render (LsmDomView *view, cairo_t *cairo, double x, double y)
276 {
277 LsmDomViewClass *view_class;
278
279 g_return_if_fail (LSM_IS_DOM_VIEW (view));
280 g_return_if_fail (LSM_IS_DOM_DOCUMENT (view->document));
281 g_return_if_fail (cairo != NULL);
282
283 lsm_dom_view_set_cairo_context (view, cairo);
284
285 cairo_save (view->cairo);
286
287 cairo_translate (view->cairo, x, y);
288
289 view_class = LSM_DOM_VIEW_GET_CLASS (view);
290 if (view_class->render != NULL)
291 view_class->render (view);
292
293 cairo_restore (view->cairo);
294 cairo_new_path (cairo);
295
296 lsm_debug_render ("[LsmDomView::render] cairo status = %s",
297 cairo_status_to_string (cairo_status (view->cairo)));
298
299 lsm_dom_view_set_cairo_context (view, NULL);
300 }
301
302 /**
303 * lsm_dom_view_set_document:
304 * @view: a #LsmDomView
305 * @document: (transfer full): a #LsmDomDocument
306 *
307 * Change the document attached to @view. The previously attached document is unreferenced.
308 */
309
310 void
lsm_dom_view_set_document(LsmDomView * view,LsmDomDocument * document)311 lsm_dom_view_set_document (LsmDomView *view, LsmDomDocument *document)
312 {
313 g_return_if_fail (LSM_IS_DOM_VIEW (view));
314 g_return_if_fail (document == NULL || LSM_IS_DOM_DOCUMENT (document));
315
316 if (view->document == document)
317 return;
318
319 if (view->document != NULL)
320 g_object_unref (view->document);
321
322 if (document != NULL)
323 g_object_ref (document);
324
325 view->document = document;
326 }
327
328 /**
329 * lsm_dom_view_set_debug:
330 * @view: a #LsmDomView
331 * @feature: name of the feature to debug
332 * @enable: wether to enable debugging
333 *
334 * Configure feature debug.
335 */
336
337 void
lsm_dom_view_set_debug(LsmDomView * view,const char * feature,gboolean enable)338 lsm_dom_view_set_debug (LsmDomView *view, const char *feature, gboolean enable)
339 {
340 LsmDomViewClass *view_class;
341
342 g_return_if_fail (LSM_IS_DOM_VIEW (view));
343 g_return_if_fail (feature != NULL);
344
345
346 view_class = LSM_DOM_VIEW_GET_CLASS (view);
347 if (view_class->set_debug)
348 view_class->set_debug (view, feature, enable);
349 }
350
351 static void
lsm_dom_view_init(LsmDomView * view)352 lsm_dom_view_init (LsmDomView *view)
353 {
354 PangoFontMap *font_map;
355 PangoContext *pango_context;
356 cairo_font_options_t *font_options;
357
358 view->resolution_ppi = LSM_DOM_VIEW_DEFAULT_RESOLUTION;
359 view->viewport_pt.x = 0;
360 view->viewport_pt.y = 0;
361 view->viewport_pt.width = LSM_DOM_VIEW_DEFAULT_VIEWBOX_WIDTH;
362 view->viewport_pt.height = LSM_DOM_VIEW_DEFAULT_VIEWBOX_HEIGHT;
363
364 view->font_description = pango_font_description_new ();
365
366 font_map = pango_cairo_font_map_get_default ();
367
368 #if PANGO_VERSION_CHECK(1,22,0)
369 pango_context = pango_font_map_create_context (font_map);
370 #else
371 pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (font_map));
372 #endif
373 pango_cairo_context_set_resolution (pango_context, 72.0);
374
375 view->measure_pango_layout = pango_layout_new (pango_context);
376
377 font_options = cairo_font_options_create ();
378
379 cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
380 cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
381
382 pango_cairo_context_set_font_options (pango_context, font_options);
383
384 cairo_font_options_destroy (font_options);
385
386 g_object_unref (pango_context);
387
388 view->pango_layout = NULL;
389 view->cairo = NULL;
390 view->is_vector = FALSE;
391 }
392
393 static void
lsm_dom_view_finalize(GObject * object)394 lsm_dom_view_finalize (GObject *object)
395 {
396 LsmDomView *view = LSM_DOM_VIEW (object);
397
398 if (view->document)
399 g_object_unref (view->document);
400
401 if (view->pango_layout != NULL)
402 g_object_unref (view->pango_layout);
403 if (view->cairo != NULL)
404 cairo_destroy (view->cairo);
405
406 g_object_unref (view->measure_pango_layout);
407
408 pango_font_description_free (view->font_description);
409
410 parent_class->finalize (object);
411 }
412
413 static void
lsm_dom_view_class_init(LsmDomViewClass * view_class)414 lsm_dom_view_class_init (LsmDomViewClass *view_class)
415 {
416 GObjectClass *object_class = G_OBJECT_CLASS (view_class);
417
418 parent_class = g_type_class_peek_parent (view_class);
419
420 object_class->finalize = lsm_dom_view_finalize;
421 }
422
423 G_DEFINE_ABSTRACT_TYPE (LsmDomView, lsm_dom_view, G_TYPE_OBJECT)
424