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