1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22
23 #include <sys/time.h>
24 #include <cstring>
25 #include <cmath>
26 #include <iostream>
27 #include <iterator>
28 #include <functional>
29 #include <boost/utility.hpp>
30
31 #include "log.h"
32 #include "RGBA.h"
33 #include "GnashImage.h"
34 #include "GnashNumeric.h"
35 #include "FillStyle.h"
36 #include "LineStyle.h"
37 #include "Transform.h"
38 #include "log.h"
39 #include "utility.h"
40 #include "Range2d.h"
41 #include "SWFCxForm.h"
42 #include "openvg/OpenVGRenderer.h"
43 #include "openvg/OpenVGBitmap.h"
44 #include "openvg/OpenVGStyle.h"
45 #include "SWFMatrix.h"
46 #include "swf/ShapeRecord.h"
47 #include "CachedBitmap.h"
48
49 #include <VG/vgu.h>
50 #ifdef HAVE_VG_EXT_H
51 # include <VG/ext.h>
52 #else
53 # ifdef HAVE_VG_VGEXT_H
54 # include <VG/vgext.h>
55 # endif
56 #endif
57 #include <VG/openvg.h>
58 #define GNASH_IMAGE_QUALITY VG_IMAGE_QUALITY_FASTER
59 #define GNASH_RENDER_QUALITY VG_RENDERING_QUALITY_FASTER
60
61 #define MAX_POINTS (4096)
62
63 /// \file Renderer_ovg.cpp
64 /// \brief The OpenVG renderer and related code.
65 ///
66
67 static const int TwipsPerInch = 1440;
68
69 namespace gnash {
70
71 typedef std::vector<Path> PathVec;
72 typedef std::vector<geometry::Range2d<int> > ClipBounds;
73
74 namespace renderer {
75
76 namespace openvg {
77
78 /// Transforms the current OpenVG SWFMatrix using the given SWFMatrix.
79 /// When it goes out of scope, the SWFMatrix will be reset to what it
80 /// was before the new SWFMatrix was applied.
81 class eglScopeMatrix : public boost::noncopyable
82 {
83 public:
eglScopeMatrix(const SWFMatrix & m)84 eglScopeMatrix(const SWFMatrix& m)
85 {
86 // GNASH_REPORT_FUNCTION;
87
88 vgGetMatrix(_orig_mat);
89 // Renderer_ovg::printVGMatrix(_orig_mat);
90
91 float mat[9];
92 memset(mat, 0, sizeof(mat));
93 mat[0] = m.a() / 65536.0f;
94 mat[1] = m.b() / 65536.0f;
95 mat[3] = m.c() / 65536.0f;
96 mat[4] = m.d() / 65536.0f;
97 mat[6] = m.tx();
98 mat[7] = m.ty();
99 vgMultMatrix(mat);
100 // Renderer_ovg::printVGMatrix(mat);
101 }
102
~eglScopeMatrix()103 ~eglScopeMatrix()
104 {
105 vgLoadMatrix(_orig_mat);
106 }
107 private:
108 VGfloat _orig_mat[9];
109 };
110
111 /// @note
112 /// A VGpath is constructed from a series of appended path
113 /// segments. When drawing shapes from flash, we start each path by
114 /// moving to a known location. Then segments are appended, and then
115 /// the path is closed. This is also used for fills.
116
117 #define MAX_SEG (256)
118
119 /// Start a VGPath by moving to a specified location
120 ///
121 /// @param path The VGPath to start
122 /// @returns nothing
123 inline void
startpath(VGPath path,const int x,const int y)124 startpath(VGPath path, const int x, const int y)
125 {
126 VGubyte gseg[1];
127 VGfloat gdata[2];
128
129 gseg[0] = VG_MOVE_TO;
130 gdata[0] = x;
131 gdata[1] = y;
132 vgAppendPathData (path, 1, gseg, gdata);
133 }
134
135 /// Close the VGPath started by startpath()
136 ///
137 /// @param path The VGPath to close
138 /// @returns nothing
139 inline void
closepath(VGPath path)140 closepath(VGPath path)
141 {
142 VGubyte gseg[1];
143 VGfloat gdata[2];
144
145 gseg[0] = VG_CLOSE_PATH;
146 vgAppendPathData (path, 1, gseg, gdata);
147 }
148
149 /// Add a series of edges to the existing path created by startpath()
150 ///
151 /// @param path The VGPath to append segments to
152 /// @param edges The segments to append to the path
153 /// @param anchor_x The X coordinate to start from
154 /// @param anchor_y The Y coordinate to start from
155 /// @returns nothing
156 inline void
preparepath(VGPath path,const std::vector<Edge> & edges,const float & anchor_x,const float & anchor_y)157 preparepath(VGPath path, const std::vector<Edge>& edges,
158 const float& anchor_x, const float& anchor_y)
159 {
160 VGubyte gseg[MAX_SEG];
161 VGfloat gdata[MAX_SEG*3*2];
162 int scount = 0;
163 int dcount = 0;
164
165 point start(anchor_x, anchor_y);
166 point anchor(anchor_x, anchor_y);
167
168 for (std::vector<Edge>::const_iterator it = edges.begin(), end = edges.end();
169 it != end; ++it) {
170 const Edge& the_edge = *it;
171
172 point target(the_edge.ap.x, the_edge.ap.y);
173
174 if (the_edge.straight()) {
175 gseg[scount++] = VG_LINE_TO;
176 gdata[dcount++] = target.x;
177 gdata[dcount++] = target.y;
178 } else {
179 gseg[scount++] = VG_QUAD_TO;
180 gdata[dcount++] = the_edge.cp.x;
181 gdata[dcount++] = the_edge.cp.y;
182 gdata[dcount++] = target.x;
183 gdata[dcount++] = target.y;
184 }
185 if (scount >= MAX_SEG-2) {
186 vgAppendPathData(path, scount, gseg, gdata);
187 scount = 0;
188 dcount = 0;
189 }
190 anchor = target;
191 }
192
193 if (scount > 0)
194 vgAppendPathData (path, scount, gseg, gdata);
195 }
196
197 template<typename C, typename T, typename R, typename A>
198 void
for_each(C & container,R (T::* pmf)(const A &),const A & arg)199 for_each(C& container, R (T::*pmf)(const A&),const A& arg)
200 {
201 std::for_each(container.begin(), container.end(),
202 std::bind(pmf, _1, std::ref(arg)));
203 }
204
Renderer_ovg()205 Renderer_ovg::Renderer_ovg()
206 : _display_width(0.0),
207 _display_height(0.0),
208 _drawing_mask(false),
209 #ifdef OPENVG_VERSION_1_1
210 _mask_layer(VG_INVALID_HANDLE),
211 #endif
212 _fillpaint(VG_INVALID_HANDLE),
213 _strokepaint(VG_INVALID_HANDLE),
214 _aspect_ratio(0.75) // 4:3 aspect ratio
215 {
216 // GNASH_REPORT_FUNCTION;
217 }
218
Renderer_ovg(renderer::GnashDevice::dtype_t)219 Renderer_ovg::Renderer_ovg(renderer::GnashDevice::dtype_t /* dtype */)
220 : _display_width(0.0),
221 _display_height(0.0),
222 _drawing_mask(false),
223 #ifdef OPENVG_VERSION_1_1
224 _mask_layer(VG_INVALID_HANDLE),
225 #endif
226 _fillpaint(VG_INVALID_HANDLE),
227 _strokepaint(VG_INVALID_HANDLE),
228 _aspect_ratio(0.75) // 4:3 aspect ratio
229 {
230 // GNASH_REPORT_FUNCTION;
231
232 set_scale(1.0f, 1.0f);
233
234 #if 0
235 _fillpaint = vgCreatePaint();
236
237 _strokepaint = vgCreatePaint();
238
239 // this paint object is used for solid, gradient, and pattern fills.
240 vgSetPaint (_fillpaint, VG_FILL_PATH);
241
242 // this pain object is used for paths
243 vgSetPaint (_strokepaint, VG_STROKE_PATH);
244 #endif
245 }
246
247 void
init(float x,float y)248 Renderer_ovg::init(float x, float y)
249 {
250 // GNASH_REPORT_FUNCTION;
251
252 _display_width = x;
253 _display_height = y;
254
255 // this paint object is used for solid, gradient, and pattern fills.
256 _fillpaint = vgCreatePaint();
257 vgSetPaint (_fillpaint, VG_FILL_PATH);
258
259 // this pain object is used for paths
260 _strokepaint = vgCreatePaint();
261 vgSetPaint (_strokepaint, VG_STROKE_PATH);
262
263 // Turn on alpha blending.
264 vgSeti (VG_BLEND_MODE, VG_BLEND_SRC_OVER);
265
266 vgSeti(VG_RENDERING_QUALITY, GNASH_RENDER_QUALITY);
267 vgSetf(VG_STROKE_LINE_WIDTH, 20.0f);
268
269 VGfloat clearColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
270 vgSetfv( VG_CLEAR_COLOR, 4, clearColor );
271
272 #ifdef OPENVG_VERSION_1_1
273 _mask_layer = vgCreateMaskLayer(x, y);
274 #endif
275
276 log_debug(_("VG Vendor is %s, VG Version is %s, VG Renderer is %s"),
277 vgGetString(VG_VENDOR), vgGetString(VG_VERSION),
278 vgGetString(VG_RENDERER));
279 log_debug(_("VG Extensions are: "), vgGetString(VG_EXTENSIONS));
280 printVGParams();
281
282 // vgSeti(VG_SCISSORING, VG_FALSE);
283 vgClear(0, 0, x*2, y*2);
284 }
285
~Renderer_ovg()286 Renderer_ovg::~Renderer_ovg()
287 {
288 // GNASH_REPORT_FUNCTION;
289
290 vgDestroyPaint(_fillpaint);
291 vgDestroyPaint(_strokepaint);
292 #ifdef OPENVG_VERSION_1_1
293 vgDestroyMaskLayer(_mask_layer);
294 #endif
295 }
296
297 // Given an image, returns a pointer to a CachedBitmap class
298 // that can later be passed to fill_styleX_bitmap(), to set a
299 // bitmap fill style. We only cache the GnashImage here, as a
300 // VGImage can't be created yet until the renderer is initialized.
301 CachedBitmap *
createCachedBitmap(std::unique_ptr<image::GnashImage> im)302 Renderer_ovg::createCachedBitmap(std::unique_ptr<image::GnashImage> im)
303 {
304 // GNASH_REPORT_FUNCTION;
305
306 CachedBitmap *cbinfo = reinterpret_cast<CachedBitmap *>(new OpenVGBitmap(im.release(),
307 _fillpaint));
308 return cbinfo;
309 }
310
311 // Since we store drawing operations in display lists, we take special care
312 // to store video frame operations in their own display list, lest they be
313 // anti-aliased with the rest of the drawing. Since display lists cannot be
314 // concatenated this means we'll add up with several display lists for normal
315 // drawing operations.
316 void
drawVideoFrame(image::GnashImage *,const SWFMatrix *,const SWFRect *,bool)317 Renderer_ovg::drawVideoFrame(image::GnashImage* /* frame */, const SWFMatrix* /* m */,
318 const SWFRect* /* bounds */, bool /*smooth*/)
319 {
320 log_unimpl(_("drawVideoFrame"));
321 }
322
323 void
world_to_pixel(int & x,int & y,float world_x,float world_y) const324 Renderer_ovg::world_to_pixel(int& x, int& y, float world_x, float world_y) const
325 {
326 // GNASH_REPORT_FUNCTION;
327
328 // negative pixels seems ok here... we don't
329 // clip to valid range, use world_to_pixel(rect&)
330 // and Intersect() against valid range instead.
331 point p(world_x, world_y);
332 stage_matrix.transform(p);
333 x = (int)p.x;
334 y = (int)p.y;
335 }
336
337 geometry::Range2d<int>
world_to_pixel(const SWFRect & wb) const338 Renderer_ovg::world_to_pixel(const SWFRect& wb) const
339 {
340 // GNASH_REPORT_FUNCTION;
341
342 using namespace gnash::geometry;
343
344 if ( wb.is_null() ) return Range2d<int>(nullRange);
345 if ( wb.is_world() ) return Range2d<int>(worldRange);
346
347 int xmin, ymin, xmax, ymax;
348
349 world_to_pixel(xmin, ymin, wb.get_x_min(), wb.get_y_min());
350 world_to_pixel(xmax, ymax, wb.get_x_max(), wb.get_y_max());
351
352 return Range2d<int>(xmin, ymin, xmax, ymax);
353 }
354
355 geometry::Range2d<int>
world_to_pixel(const geometry::Range2d<float> & wb) const356 Renderer_ovg::world_to_pixel(const geometry::Range2d<float>& wb) const
357 {
358 // GNASH_REPORT_FUNCTION;
359
360 if (wb.isNull() || wb.isWorld()) return wb;
361
362 int xmin, ymin, xmax, ymax;
363
364 world_to_pixel(xmin, ymin, wb.getMinX(), wb.getMinY());
365 world_to_pixel(xmax, ymax, wb.getMaxX(), wb.getMaxY());
366
367 return geometry::Range2d<int>(xmin, ymin, xmax, ymax);
368 }
369
370 point
pixel_to_world(int x,int y) const371 Renderer_ovg::pixel_to_world(int x, int y) const
372 {
373 // GNASH_REPORT_FUNCTION;
374
375 point p(x, y);
376 SWFMatrix mat = stage_matrix;
377 mat.invert().transform(p);
378 return p;
379 }
380
381 /// Setup the renderer to display by setting the Matrix for scaling,
382 /// shearing, and transformations.
383 ///
384 /// @param width - stage width
385 /// @param height - stage height
386 /// @param x0 - minimum frame size in X dimension in twips
387 /// @param x1 - maximum frame size in X dimension in twips
388 /// @param y0 - minimum frame size in Y dimension in twips
389 /// @param y1 - maximum frame size in Y dimension in twips
390 void
begin_display(gnash::rgba const &,int width,int height,float x0,float x1,float y0,float y1)391 Renderer_ovg::begin_display(gnash::rgba const&, int width, int height,
392 float x0, float x1, float y0, float y1)
393 {
394 // GNASH_REPORT_FUNCTION;
395
396 // Disable masking
397 vgSeti (VG_MASKING, VG_FALSE);
398
399 VGfloat mat[9];
400 memset(mat, 0, sizeof(mat));
401 // sx and sy define scaling in the x and y directions, respectively;
402 // shx and shy define shearing in the x and y directions, respectively;
403 // tx and ty define translation in the x and y directions, respectively.
404
405 // Flash internally calculates anything that uses pixels with
406 // twips (or 1/20 of a pixel). Sprites, movie clips and any other
407 // object on the stage are positioned with twips. As a result, the
408 // coordinates of (for example) sprites are always multiples of
409 // 0.05 (i.e. 1/20).
410 mat[0] = (VGfloat)width / VGfloat(x1 - x0); // scale sx = 0.05
411 mat[1] = 0; // shx
412 mat[3] = 0; // shy
413 mat[4] = -((VGfloat)height / VGfloat(y1 - y0)); // scale sy = -0.05
414 mat[6] = 0; // shift tx in pixels
415 mat[7] = height; // shift ty in pixels
416
417 vgSeti (VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
418 // The default values after vgLoadIdentity() are:
419 // [ 1 0 0 ]
420 // M =| 0 1 0 |
421 // [ 0 0 1 ]
422 vgLoadIdentity();
423
424 // An affine transformation maps a point (x, y) (represented using
425 // homogeneous coordinates as the column vector [x, y, 1]T) into the
426 // point (x*sx + y*shx + tx, x*shy + y*sy + ty) using matrix multiplication:
427 // [ sx shx tx ] [ x ] [ x∗sx + y∗shx + tx ]
428 // | shy sy ty |.[ y | = | x∗shy + y∗sy + ty |
429 // [ 0 0 1 ] [ 1 ] [ 1 ]
430 //
431 // If not VG_MATRIX_IMAGE_USER_TO_SURFACE, w0, w1, and w2 are ignored.
432 vgLoadMatrix (mat);
433
434 // vgSeti(VG_SCISSORING, VG_FALSE);
435 vgClear(0, 0, _display_width, _display_height);
436 }
437
438 void
end_display()439 Renderer_ovg::end_display()
440 {
441 // GNASH_REPORT_FUNCTION;
442 }
443
444 /// Draw a line-strip directly, using a thin, solid line.
445 //
446 /// Can be used to draw empty boxes and cursors.
447 void
drawLine(const std::vector<point> & coords,const rgba & fill,const SWFMatrix & mat)448 Renderer_ovg::drawLine(const std::vector<point>& coords, const rgba& fill,
449 const SWFMatrix& mat)
450 {
451 // GNASH_REPORT_FUNCTION;
452
453 VGubyte gseg[MAX_SEG];
454 VGfloat gdata[MAX_SEG*3*2];
455 int scount = 0;
456 int dcount = 0;
457
458 if (coords.empty()) return;
459
460 eglScopeMatrix scope_mat(mat);
461
462 VGfloat color[] = {
463 fill.m_r / 255.0f,
464 fill.m_g / 255.0f,
465 fill.m_b / 255.0f,
466 1.0f
467 };
468 VGPath vg_path;
469 vg_path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
470 VG_PATH_DATATYPE_F,
471 1, 0, 0, 0,
472 VG_PATH_CAPABILITY_ALL);
473 vgSetf (VG_FILL_RULE, VG_EVEN_ODD );
474 vgSetParameteri (_strokepaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
475 vgSetParameterfv (_strokepaint, VG_PAINT_COLOR, 4, color);
476
477 std::vector<point>::const_iterator it = coords.begin();
478 std::vector<point>::const_iterator end = coords.end();
479
480 gseg[scount++] = VG_MOVE_TO;
481 gdata[dcount++] = (float)(*it).x;
482 gdata[dcount++] = (float)(*it).y;
483 ++it;
484
485 for (; it != end; ++it) {
486 gseg[scount++] = VG_LINE_TO;
487 gdata[dcount++] = (float)(*it).x;
488 gdata[dcount++] = (float)(*it).y;
489 if (scount >= MAX_SEG-1) {
490 vgAppendPathData(vg_path, scount, gseg, gdata);
491 scount = 0;
492 dcount = 0;
493 }
494 }
495
496 if (scount > 0) {
497 vgAppendPathData(vg_path, scount, gseg, gdata);
498
499 }
500
501 vgSetf (VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
502 vgSetf (VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
503 vgSetf (VG_STROKE_LINE_WIDTH, 20.0f);
504
505 vgDrawPath (vg_path, VG_STROKE_PATH);
506 vgDestroyPath(vg_path);
507 }
508
509 void
draw_poly(const std::vector<point> & corners,const rgba & fill,const rgba &,const SWFMatrix & mat,bool)510 Renderer_ovg::draw_poly(const std::vector<point>& corners,
511 const rgba& fill, const rgba& /* outline */,
512 const SWFMatrix& mat, bool /* masked */)
513 {
514 // GNASH_REPORT_FUNCTION;
515
516 VGubyte gseg[MAX_SEG];
517 VGfloat gdata[MAX_SEG*3*2];
518 int scount = 0;
519 int dcount = 0;
520
521 if (corners.empty()) {
522 return;
523 }
524
525 eglScopeMatrix scope_mat(mat);
526
527 VGfloat color[] = {
528 fill.m_r / 255.0f,
529 fill.m_g / 255.0f,
530 fill.m_b / 255.0f,
531 fill.m_a / 255.0f
532 };
533 VGPath vg_path;
534 vg_path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
535 VG_PATH_DATATYPE_F,
536 1, 0, 0, 0,
537 VG_PATH_CAPABILITY_ALL);
538 vgSetf (VG_FILL_RULE, VG_NON_ZERO );
539
540 vgSetParameteri (_fillpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
541 vgSetParameterfv (_fillpaint, VG_PAINT_COLOR, 4, color);
542
543 const point *ptr = &corners.front();
544 gseg[scount++] = VG_MOVE_TO;
545 gdata[dcount++] = (float)ptr->x;
546 gdata[dcount++] = (float)ptr->y;
547 ptr++;
548
549 for (size_t i = 1; i < corners.size(); i++) {
550 gseg[scount++] = VG_LINE_TO;
551 gdata[dcount++] = (float)ptr->x;
552 gdata[dcount++] = (float)ptr->y;
553 ptr++;
554 if (scount >= MAX_SEG-2) {
555 vgAppendPathData(vg_path, scount, gseg, gdata);
556 scount = 0;
557 dcount = 0;
558 }
559 }
560 gseg[scount++] = VG_CLOSE_PATH;
561 vgAppendPathData (vg_path, scount, gseg, gdata);
562
563 vgDrawPath (vg_path, VG_FILL_PATH);
564 vgDestroyPath(vg_path);
565 }
566
567 void
set_antialiased(bool)568 Renderer_ovg::set_antialiased(bool /* enable */)
569 {
570 log_unimpl(_("set_antialiased"));
571 }
572
573 void
begin_submit_mask()574 Renderer_ovg::begin_submit_mask()
575 {
576 // GNASH_REPORT_FUNCTION;
577
578 PathVec mask;
579 _masks.push_back(mask);
580 _drawing_mask = true;
581 }
582
583 void
end_submit_mask()584 Renderer_ovg::end_submit_mask()
585 {
586 // GNASH_REPORT_FUNCTION;
587
588 // If masking is disabled, rhen we can't use it
589 if (_drawing_mask == true) {
590 _drawing_mask = false;
591 apply_mask();
592 }
593 }
594
595 /// Apply the current mask; nesting is supported.
596 ///
597 /// This method marks the stencil buffer by incrementing every stencil pixel
598 /// by one every time a solid from one of the current masks is drawn. When
599 /// all the mask solids are drawn, we change the stencil operation to permit
600 /// only drawing where all masks have drawn, in other words, where all masks
601 /// intersect, or in even other words, where the stencil pixel buffer equals
602 /// the number of masks.
603 void
apply_mask()604 Renderer_ovg::apply_mask()
605 {
606 // GNASH_REPORT_FUNCTION;
607
608 if (_masks.empty()) {
609 return;
610 }
611
612 float mat[9];
613 float omat[9];
614
615 vgSeti (VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
616 vgLoadIdentity();
617 vgGetMatrix (omat); // get the current matrix
618
619 memset(mat, 0, sizeof(mat));
620 mat[0] = stage_matrix.get_x_scale(); // scale sx
621 mat[1] = 0.0f; // shx
622 mat[3] = 0.0f; // shy
623 mat[4] = -stage_matrix.get_x_scale(); // scale sy
624 mat[6] = 0; // shift tx
625 mat[7] = _display_height; // shift ty
626 vgLoadMatrix(mat);
627 // Renderer_ovg::printVGMatrix(mat);
628
629 #ifdef OPENVG_VERSION_1_1
630 vgMask(_mask_layer, VG_FILL_MASK, 0, 0, _display_width, _display_height);
631 #endif
632 // Call add_paths for each mask.
633 std::for_each(_masks.begin(), _masks.end(),
634 std::bind(&Renderer_ovg::add_paths, this, _1));
635 vgSeti(VG_MASKING, VG_TRUE);
636
637 vgLoadMatrix (omat); // restore the current matrix
638 }
639
640 void
disable_mask()641 Renderer_ovg::disable_mask()
642 {
643 // GNASH_REPORT_FUNCTION;
644
645 // if (vgGeti(VG_MASKING) == VG_TRUE) {
646 _masks.pop_back();
647
648 if (_masks.empty()) {
649 vgSeti (VG_MASKING, VG_FALSE);
650 } else {
651 apply_mask();
652 }
653 // }
654 }
655
656 void
add_paths(const PathVec & path_vec)657 Renderer_ovg::add_paths(const PathVec& path_vec)
658 {
659 // GNASH_REPORT_FUNCTION;
660
661 SWFCxForm dummy_cx;
662
663 FillStyle coloring = FillStyle(SolidFill(rgba(0, 255, 0, 255)));
664
665 draw_submask(path_vec, SWFMatrix(), dummy_cx, coloring);
666 }
667
668 Path
reverse_path(const Path & cur_path)669 Renderer_ovg::reverse_path(const Path& cur_path)
670 {
671 // GNASH_REPORT_FUNCTION;
672
673 const Edge& cur_end = cur_path.m_edges.back();
674
675 float prev_cx = cur_end.cp.x;
676 float prev_cy = cur_end.cp.y;
677
678 Path newpath(cur_end.ap.x, cur_end.ap.y, cur_path.m_fill1, cur_path.m_fill0, cur_path.m_line, cur_path.m_new_shape);
679
680 float prev_ax = cur_end.ap.x;
681 float prev_ay = cur_end.ap.y;
682
683 for (std::vector<Edge>::const_reverse_iterator it = cur_path.m_edges.rbegin()+1, end = cur_path.m_edges.rend(); it != end; ++it) {
684 const Edge& cur_edge = *it;
685
686 if (prev_ax == prev_cx && prev_ay == prev_cy) {
687 prev_cx = cur_edge.ap.x;
688 prev_cy = cur_edge.ap.y;
689 }
690
691 Edge newedge(prev_cx, prev_cy, cur_edge.ap.x, cur_edge.ap.y);
692
693 newpath.m_edges.push_back(newedge);
694
695 prev_cx = cur_edge.cp.x;
696 prev_cy = cur_edge.cp.y;
697 prev_ax = cur_edge.ap.x;
698 prev_ay = cur_edge.ap.y;
699
700 }
701
702 Edge newlastedge(prev_cx, prev_cy, cur_path.ap.x, cur_path.ap.y);
703 newpath.m_edges.push_back(newlastedge);
704
705 return newpath;
706 }
707
708 const Path *
find_connecting_path(const Path & to_connect,std::list<const Path * > path_refs)709 Renderer_ovg::find_connecting_path(const Path& to_connect,
710 std::list<const Path*> path_refs)
711 {
712 // GNASH_REPORT_FUNCTION;
713
714 float target_x = to_connect.m_edges.back().ap.x;
715 float target_y = to_connect.m_edges.back().ap.y;
716
717 if (target_x == to_connect.ap.x &&
718 target_y == to_connect.ap.y) {
719 return NULL;
720 }
721
722 for (std::list<const Path*>::const_iterator it = path_refs.begin(),
723 end = path_refs.end(); it != end; ++it) {
724 const Path* cur_path = *it;
725
726 if (cur_path == &to_connect) {
727 continue;
728 }
729
730 if (cur_path->ap.x == target_x && cur_path->ap.y == target_y) {
731 if (cur_path->m_fill1 != to_connect.m_fill1) {
732 continue;
733 }
734 return cur_path;
735 }
736 }
737
738 return NULL;
739 }
740
741 PathVec
normalize_paths(const PathVec & paths)742 Renderer_ovg::normalize_paths(const PathVec &paths)
743 {
744 // GNASH_REPORT_FUNCTION;
745
746 PathVec normalized;
747
748 for (PathVec::const_iterator it = paths.begin(), end = paths.end();
749 it != end; ++it) {
750 const Path& cur_path = *it;
751
752 if (cur_path.m_edges.empty()) {
753 continue;
754
755 } else if (cur_path.m_fill0 && cur_path.m_fill1) {
756
757 // Two fill styles; duplicate and then reverse the left-filled one.
758 normalized.push_back(cur_path);
759 normalized.back().m_fill0 = 0;
760
761 Path newpath = reverse_path(cur_path);
762 newpath.m_fill0 = 0;
763
764 normalized.push_back(newpath);
765
766 } else if (cur_path.m_fill0) {
767 // Left fill style.
768 Path newpath = reverse_path(cur_path);
769 newpath.m_fill0 = 0;
770
771 normalized.push_back(newpath);
772 } else if (cur_path.m_fill1) {
773 // Right fill style.
774 normalized.push_back(cur_path);
775 } else {
776 // No fill styles; copy without modifying.
777 normalized.push_back(cur_path);
778 }
779
780 }
781
782 return normalized;
783 }
784
785
786 /// Analyzes a set of paths to detect real presence of fills and/or outlines
787 /// TODO: This should be something the character tells us and should be
788 /// cached.
789 void
analyze_paths(const PathVec & paths,bool & have_shape,bool & have_outline)790 Renderer_ovg::analyze_paths(const PathVec &paths, bool& have_shape,
791 bool& have_outline)
792 {
793 // GNASH_REPORT_FUNCTION;
794
795 have_shape = false;
796 have_outline = false;
797
798 int pcount = paths.size();
799
800 for (int pno= 0; pno<pcount; pno++) {
801
802 const Path &the_path = paths[pno];
803
804 // If a left or right fill is set, then this is an outline
805 if ((the_path.m_fill0 > 0) || (the_path.m_fill1 > 0)) {
806 have_shape = true;
807 if (have_outline) return; // have both
808 }
809
810 // If a line is set, then it's a shape. A path can be both
811 if (the_path.m_line > 0) {
812 have_outline = true;
813 if (have_shape) return; // have both
814 }
815 }
816 }
817
818 bool
apply_line_style(const LineStyle & style,const SWFCxForm & cx,const SWFMatrix & mat)819 Renderer_ovg::apply_line_style(const LineStyle& style, const SWFCxForm& cx,
820 const SWFMatrix& mat)
821 {
822 // GNASH_REPORT_FUNCTION;
823
824 bool rv = true;
825
826 switch(style.joinStyle()) {
827 case JOIN_ROUND:
828 vgSetf (VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
829 break;
830 case JOIN_BEVEL:
831 vgSetf (VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL);
832 break;
833 case JOIN_MITER:
834 vgSetf (VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
835 break;
836 default:
837 log_unimpl(_("join style"));
838 }
839
840 switch(style.startCapStyle()) {
841 case CAP_ROUND:
842 vgSetf (VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
843 break;
844 case CAP_NONE:
845 vgSetf (VG_STROKE_CAP_STYLE, VG_CAP_BUTT);
846 break;
847 case CAP_SQUARE:
848 vgSetf (VG_STROKE_CAP_STYLE, VG_CAP_SQUARE);
849 break;
850 default:
851 log_unimpl(_("cap style"));
852 }
853
854 vgSetf (VG_STROKE_MITER_LIMIT, style.miterLimitFactor());
855
856 float width = style.getThickness();
857
858 if (!width) {
859 vgSetf(VG_STROKE_LINE_WIDTH, 20.0f);
860 rv = false; // Don't draw rounded lines.
861 } else if ( (!style.scaleThicknessVertically()) && (!style.scaleThicknessHorizontally()) ) {
862 vgSetf(VG_STROKE_LINE_WIDTH, width);
863 } else {
864 if ( (!style.scaleThicknessVertically()) || (!style.scaleThicknessHorizontally()) ) {
865 LOG_ONCE( log_unimpl(_("Unidirectionally scaled strokes in OGL renderer")) );
866 }
867
868 float stroke_scale = fabsf(mat.get_x_scale()) + fabsf(mat.get_y_scale());
869 stroke_scale /= 2.0f;
870 stroke_scale *= (stage_matrix.get_x_scale() + stage_matrix.get_y_scale()) / 2.0f;
871 width *= stroke_scale;
872
873 if (width < 20.0f) {
874 width = 20.0f;
875 }
876
877 vgSetf(VG_STROKE_LINE_WIDTH, width);
878 }
879
880 rgba c = cx.transform(style.get_color());
881 VGfloat color[] = {
882 c.m_r / 255.0f,
883 c.m_g / 255.0f,
884 c.m_b / 255.0f,
885 c.m_a / 255.0f
886 };
887
888
889 vgSetParameteri (_strokepaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
890 vgSetParameterfv (_strokepaint, VG_PAINT_COLOR, 4, color);
891
892 return rv;
893 }
894
895 typedef std::vector<const Path*> PathPtrVec;
896
897 void
draw_outlines(const PathVec & path_vec,const SWFMatrix & mat,const SWFCxForm & cx,const std::vector<LineStyle> & line_styles)898 Renderer_ovg::draw_outlines(const PathVec& path_vec, const SWFMatrix& mat,
899 const SWFCxForm& cx, const std::vector<LineStyle>& line_styles)
900 {
901 // GNASH_REPORT_FUNCTION;
902
903 for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
904 it != end; ++it) {
905
906 const Path& cur_path = *it;
907
908 if (!cur_path.m_line) {
909 continue;
910 }
911
912 VGPath vpath;
913 vpath = vgCreatePath (VG_PATH_FORMAT_STANDARD,
914 VG_PATH_DATATYPE_F,
915 1, 0, 0, 0,
916 VG_PATH_CAPABILITY_ALL);
917 vgSetf (VG_FILL_RULE, VG_EVEN_ODD );
918 startpath(vpath, cur_path.ap.x, cur_path.ap.y);
919 preparepath(vpath, cur_path.m_edges, cur_path.ap.x,
920 cur_path.ap.y);
921
922 apply_line_style(line_styles[cur_path.m_line-1], cx, mat);
923 vgDrawPath (vpath, VG_STROKE_PATH);
924 vgDestroyPath(vpath);
925 }
926 }
927
928 std::list<PathPtrVec>
get_contours(const PathPtrVec & paths)929 Renderer_ovg::get_contours(const PathPtrVec &paths)
930 {
931 // GNASH_REPORT_FUNCTION;
932
933 std::list<const Path*> path_refs;
934 std::list<PathPtrVec> contours;
935
936 for (PathPtrVec::const_iterator it = paths.begin(), end = paths.end();
937 it != end; ++it) {
938 const Path* cur_path = *it;
939 path_refs.push_back(cur_path);
940 }
941
942 for (std::list<const Path*>::const_iterator it = path_refs.begin(), end = path_refs.end();
943 it != end; ++it) {
944 const Path* cur_path = *it;
945
946 if (cur_path->m_edges.empty()) {
947 continue;
948 }
949
950 if (!cur_path->m_fill0 && !cur_path->m_fill1) {
951 continue;
952 }
953
954 PathPtrVec contour;
955
956 contour.push_back(cur_path);
957
958 const Path* connector = find_connecting_path(*cur_path, path_refs);
959
960 while (connector) {
961 contour.push_back(connector);
962
963 const Path* tmp = connector;
964 connector = find_connecting_path(*connector, std::list<const Path*>(std::next(it), end));
965
966 // make sure we don't iterate over the connecting path in the for loop.
967 path_refs.remove(tmp);
968
969 }
970
971 contours.push_back(contour);
972 }
973
974 return contours;
975 }
976
977 void
draw_mask(const PathVec & path_vec)978 Renderer_ovg::draw_mask(const PathVec& path_vec)
979 {
980 // GNASH_REPORT_FUNCTION;
981
982 if (_drawing_mask == true) {
983 for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
984 it != end; ++it) {
985 const Path& cur_path = *it;
986
987 if (cur_path.m_fill0 || cur_path.m_fill1) {
988 _masks.back().push_back(cur_path);
989 _masks.back().back().m_line = 0;
990 }
991 }
992 }
993 }
994
995 PathPtrVec
paths_by_style(const PathVec & path_vec,unsigned int style)996 Renderer_ovg::paths_by_style(const PathVec& path_vec, unsigned int style)
997 {
998 // GNASH_REPORT_FUNCTION;
999
1000 PathPtrVec paths;
1001 for (PathVec::const_iterator it = path_vec.begin(), end = path_vec.end();
1002 it != end; ++it) {
1003 const Path& cur_path = *it;
1004
1005 if (cur_path.m_fill0 == style) {
1006 paths.push_back(&cur_path);
1007 }
1008
1009 if (cur_path.m_fill1 == style) {
1010 paths.push_back(&cur_path);
1011 }
1012
1013 }
1014 return paths;
1015 }
1016
1017
1018 std::vector<PathVec::const_iterator>
find_subshapes(const PathVec & path_vec)1019 Renderer_ovg::find_subshapes(const PathVec& path_vec)
1020 {
1021 // GNASH_REPORT_FUNCTION;
1022
1023 std::vector<PathVec::const_iterator> subshapes;
1024
1025 PathVec::const_iterator it = path_vec.begin(),
1026 end = path_vec.end();
1027
1028 subshapes.push_back(it);
1029 ++it;
1030
1031 for (;it != end; ++it) {
1032 const Path& cur_path = *it;
1033
1034 if (cur_path.m_new_shape) {
1035 subshapes.push_back(it);
1036 }
1037 }
1038
1039 if (subshapes.back() != end) {
1040 subshapes.push_back(end);
1041 }
1042
1043 return subshapes;
1044 }
1045
1046 /// Takes a path and translates it using the given SWFMatrix.
1047 void
apply_matrix_to_paths(std::vector<Path> & paths,const SWFMatrix & mat)1048 Renderer_ovg::apply_matrix_to_paths(std::vector<Path>& paths, const SWFMatrix& mat)
1049 {
1050 // GNASH_REPORT_FUNCTION;
1051
1052 std::for_each(paths.begin(), paths.end(),
1053 std::bind(&Path::transform, _1, std::ref(mat)));
1054 }
1055
1056 void
draw_subshape(const PathVec & path_vec,const SWFMatrix & mat,const SWFCxForm & cx,const std::vector<FillStyle> & fill_styles,const std::vector<LineStyle> & line_styles)1057 Renderer_ovg::draw_subshape(const PathVec& path_vec,
1058 const SWFMatrix& mat,
1059 const SWFCxForm& cx,
1060 const std::vector<FillStyle>& fill_styles,
1061 const std::vector<LineStyle>& line_styles)
1062 {
1063 // GNASH_REPORT_FUNCTION;
1064
1065 PathVec normalized = normalize_paths(path_vec);
1066
1067 for (size_t i = 0; i < fill_styles.size(); ++i) {
1068 PathPtrVec paths = paths_by_style(normalized, i+1);
1069
1070 if (!paths.size()) {
1071 continue;
1072 }
1073
1074 std::list<PathPtrVec> contours = get_contours(paths);
1075
1076 VGPath vg_path;
1077 vg_path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
1078 VG_PATH_DATATYPE_F,
1079 1, 0, 0, 0,
1080 VG_PATH_CAPABILITY_ALL);
1081 vgSetf (VG_FILL_RULE, VG_EVEN_ODD );
1082
1083 for (std::list<PathPtrVec>::const_iterator iter = contours.begin(),
1084 final = contours.end(); iter != final; ++iter) {
1085 const PathPtrVec& refs = *iter;
1086
1087 startpath(vg_path, (*(refs[0])).ap.x, (*(refs[0])).ap.y);
1088
1089 // Create a Linear or Radial gradient
1090 // All positions are specified in twips, which are 20 to the
1091 // pixel.
1092 const StyleHandler st(cx, _fillpaint,
1093 (*(refs[0])).ap.x/20, (*(refs[0])).ap.y/20);
1094 boost::apply_visitor(st, fill_styles[i].fill);
1095
1096 for (PathPtrVec::const_iterator it = refs.begin(), end = refs.end();
1097 it != end; ++it) {
1098 const Path& cur_path = *(*it);
1099 if (!cur_path.m_fill0 && !cur_path.m_fill1)
1100 continue;
1101 preparepath(vg_path, cur_path.m_edges, cur_path.ap.x,
1102 cur_path.ap.y);
1103 }
1104 closepath(vg_path);
1105 }
1106 vgDrawPath (vg_path, VG_FILL_PATH);
1107 vgDestroyPath(vg_path);
1108 }
1109
1110 draw_outlines(normalized, mat, cx, line_styles);
1111 }
1112
1113 void
draw_submask(const PathVec & path_vec,const SWFMatrix &,const SWFCxForm &,const FillStyle &)1114 Renderer_ovg::draw_submask(const PathVec& path_vec,
1115 const SWFMatrix& /* mat */,
1116 const SWFCxForm& /* cx */,
1117 const FillStyle& /* f_style */)
1118 {
1119 // GNASH_REPORT_FUNCTION;
1120
1121 PathVec normalized = normalize_paths(path_vec);
1122
1123 PathPtrVec paths = paths_by_style(normalized, 1);
1124
1125 std::list<PathPtrVec> contours = get_contours(paths);
1126
1127 VGfloat color[] = {1.0f, 1.0f, 1.0f, 1.0f};
1128
1129 vgSetParameteri (_fillpaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
1130 vgSetParameterfv (_fillpaint, VG_PAINT_COLOR, 4, color);
1131
1132
1133 VGPath vg_path;
1134 vg_path = vgCreatePath (VG_PATH_FORMAT_STANDARD,
1135 VG_PATH_DATATYPE_F,
1136 1, 0, 0, 0,
1137 VG_PATH_CAPABILITY_ALL);
1138 vgSetf (VG_FILL_RULE, VG_EVEN_ODD );
1139
1140 for (std::list<PathPtrVec>::const_iterator iter = contours.begin(),
1141 final = contours.end(); iter != final; ++iter) {
1142 const PathPtrVec& refs = *iter;
1143 startpath(vg_path, (*(refs[0])).ap.x, (*(refs[0])).ap.y);
1144 for (PathPtrVec::const_iterator it = refs.begin(), end = refs.end();
1145 it != end; ++it) {
1146 const Path& cur_path = *(*it);
1147 preparepath(vg_path, cur_path.m_edges, cur_path.ap.x,
1148 cur_path.ap.y);
1149 }
1150 closepath(vg_path);
1151 }
1152
1153 #ifdef OPENVG_VERSION_1_1
1154 vgRenderToMask(vg_path, VG_FILL_PATH, VG_INTERSECT_MASK);
1155 #endif
1156 vgDestroyPath(vg_path);
1157 }
1158
1159 // Drawing procedure:
1160 // 1. Separate paths by subshape.
1161 // 2. Separate subshapes by fill style.
1162 // 3. For every subshape/fill style combo:
1163 // a. Separate contours: find closed shapes by connecting ends.
1164 // b. Apply fill style.
1165 // c. Feed the contours in the tesselator. (Render.)
1166 // d. Draw outlines for every path in the subshape with a line style.
1167 void
drawShape(gnash::SWF::ShapeRecord const & shape,gnash::Transform const & xform)1168 Renderer_ovg::drawShape(gnash::SWF::ShapeRecord const &shape,
1169 gnash::Transform const& xform)
1170 {
1171 // GNASH_REPORT_FUNCTION;
1172
1173 const PathVec& path_vec = shape.paths();
1174
1175 if (!path_vec.size()) {
1176 // No paths. Nothing to draw...
1177 return;
1178 }
1179 if (_drawing_mask) {
1180 PathVec scaled_path_vec = path_vec;
1181 apply_matrix_to_paths(scaled_path_vec, xform.matrix);
1182 draw_mask(scaled_path_vec);
1183 return;
1184 }
1185
1186 bool have_shape, have_outline;
1187
1188 analyze_paths(path_vec, have_shape, have_outline);
1189
1190 if (!have_shape && !have_outline) {
1191 return;
1192 }
1193
1194 eglScopeMatrix scope_mat(xform.matrix);
1195
1196 std::vector<PathVec::const_iterator> subshapes = find_subshapes(path_vec);
1197
1198 const std::vector<FillStyle>& fill_styles = shape.fillStyles();
1199 const std::vector<LineStyle>& line_styles = shape.lineStyles();
1200
1201 for (size_t i = 0; i < subshapes.size()-1; ++i) {
1202 PathVec subshape_paths;
1203
1204 if (subshapes[i] != subshapes[i+1]) {
1205 subshape_paths = PathVec(subshapes[i], subshapes[i+1]);
1206 } else {
1207 subshape_paths.push_back(*subshapes[i]);
1208 }
1209
1210 draw_subshape(subshape_paths, xform.matrix, xform.colorTransform,
1211 fill_styles, line_styles);
1212 }
1213 }
1214
1215 void
drawGlyph(const SWF::ShapeRecord & rec,const rgba & c,const SWFMatrix & mat)1216 Renderer_ovg::drawGlyph(const SWF::ShapeRecord& rec, const rgba& c,
1217 const SWFMatrix& mat)
1218 {
1219 // GNASH_REPORT_FUNCTION;
1220
1221 if (_drawing_mask) {
1222 abort();
1223 }
1224
1225 if (rec.getBounds().is_null()) {
1226 return;
1227 }
1228
1229 SWFCxForm dummy_cx;
1230 std::vector<FillStyle> glyph_fs;
1231
1232 FillStyle coloring = FillStyle(SolidFill(c));
1233
1234 glyph_fs.push_back(coloring);
1235
1236 std::vector<LineStyle> dummy_ls;
1237
1238 eglScopeMatrix scope_mat(mat);
1239
1240 draw_subshape(rec.paths(), mat, dummy_cx, glyph_fs, dummy_ls);
1241
1242 }
1243
1244 void
set_scale(float xscale,float yscale)1245 Renderer_ovg::set_scale(float xscale, float yscale)
1246 {
1247 // GNASH_REPORT_FUNCTION;
1248
1249 _xscale = xscale;
1250 _yscale = yscale;
1251 stage_matrix.set_identity();
1252 stage_matrix.set_scale(xscale/20.0f, yscale/20.0f);
1253 }
1254
1255 void
set_invalidated_regions(const InvalidatedRanges &)1256 Renderer_ovg::set_invalidated_regions(const InvalidatedRanges& /* ranges */)
1257 {
1258 // GNASH_REPORT_FUNCTION;
1259
1260 // do nothing obviously. This method is required by the base class though,
1261 // so something has to be here.
1262 }
1263
1264 DSOEXPORT Renderer *
create_handler(const char *)1265 create_handler(const char */* pixelformat */)
1266 {
1267 // GNASH_REPORT_FUNCTION;
1268
1269 Renderer_ovg *renderer = new Renderer_ovg;
1270 return renderer;
1271 }
1272
1273
1274 // These methods are only for debugging and development
1275 void
printVGParams()1276 Renderer_ovg::printVGParams()
1277 {
1278 // vgGetVectorSize();
1279
1280 std::string str;
1281 switch(vgGeti(VG_MATRIX_MODE)) {
1282 case VG_MATRIX_PATH_USER_TO_SURFACE:
1283 str = "VG_MATRIX_PATH_USER_TO_SURFACE";
1284 break;
1285 case VG_MATRIX_IMAGE_USER_TO_SURFACE:
1286 str = "VG_MATRIX_IMAGE_USER_TO_SURFACE";
1287 break;
1288 case VG_MATRIX_FILL_PAINT_TO_USER:
1289 str = "VG_MATRIX_FILL_PAINT_TO_USER";
1290 break;
1291 case VG_MATRIX_STROKE_PAINT_TO_USER:
1292 str = "VG_MATRIX_STROKE_PAINT_TO_USER";
1293 break;
1294 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1295 case VG_MATRIX_MODE_FORCE_SIZE:
1296 str = "VG_MATRIX_MODE_FORCE_SIZE";
1297 break;
1298 #endif
1299 default:
1300 log_error(_("unsupported VG_MATRIX_MODE!"));
1301 }
1302 log_debug(_("VG_MATRIX_MODE is %s"), str);
1303 str.clear();
1304
1305 switch(vgGeti(VG_FILL_RULE)) {
1306 case VG_EVEN_ODD:
1307 str = "VG_EVEN_ODD";
1308 break;
1309 case VG_NON_ZERO:
1310 str = "VG_NON_ZERO";
1311 break;
1312 default:
1313 log_error(_("unsupported VG_FILL_RULE!"));
1314 }
1315 log_debug(_("VG_FILL_RULE is %s"), str);
1316 str.clear();
1317
1318 switch(vgGeti(VG_IMAGE_QUALITY)) {
1319 case VG_IMAGE_QUALITY_NONANTIALIASED:
1320 str = "VG_IMAGE_QUALITY_NONANTIALIASED";
1321 break;
1322 case VG_IMAGE_QUALITY_FASTER:
1323 str = "VG_IMAGE_QUALITY_FASTER";
1324 break;
1325 case VG_IMAGE_QUALITY_BETTER:
1326 str = "VG_IMAGE_QUALITY_BETTER";
1327 break;
1328 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1329 case VG_IMAGE_QUALITY_FORCE_SIZE:
1330 str = "VG_IMAGE_QUALITY_FORCE_SIZE";
1331 break;
1332 #endif
1333 default:
1334 log_error(_("unsupported VG_IMAGE_QUALITY!"));
1335 }
1336 log_debug(_("VG_IMAGE_QUALITY is %s"), str);
1337 str.clear();
1338
1339 switch(vgGeti(VG_RENDERING_QUALITY)) {
1340 case VG_RENDERING_QUALITY_NONANTIALIASED:
1341 str = "VG_RENDERING_QUALITY_NONANTIALIASED";
1342 break;
1343 case VG_RENDERING_QUALITY_FASTER:
1344 str = "VG_RENDERING_QUALITY_FASTER";
1345 break;
1346 case VG_RENDERING_QUALITY_BETTER:
1347 str = "VG_RENDERING_QUALITY_BETTER";
1348 break;
1349 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1350 case VG_RENDERING_QUALITY_FORCE_SIZE:
1351 str = "VG_RENDERING_QUALITY_FORCE_SIZE";
1352 break;
1353 #endif
1354 default:
1355 log_error(_("unsupported VG_RENDERING_QUALITY!"));
1356 }
1357 log_debug(_("VG_RENDERING_QUALITY is %s"), str);
1358 str.clear();
1359
1360 switch(vgGeti(VG_BLEND_MODE)) {
1361 case VG_BLEND_SRC:
1362 str = "VG_BLEND_SRC";
1363 break;
1364 case VG_BLEND_SRC_OVER:
1365 str = "VG_BLEND_SRC_OVER";
1366 break;
1367 case VG_BLEND_DST_OVER:
1368 str = "VG_BLEND_DST_OVER";
1369 break;
1370 case VG_BLEND_SRC_IN:
1371 str = "VG_BLEND_SRC_IN";
1372 break;
1373 case VG_BLEND_DST_IN:
1374 str = "VG_BLEND_DST_IN";
1375 break;
1376 case VG_BLEND_MULTIPLY:
1377 str = "VG_BLEND_MULTIPLY";
1378 break;
1379 case VG_BLEND_SCREEN:
1380 str = "VG_BLEND_SCREEN";
1381 break;
1382 case VG_BLEND_DARKEN:
1383 str = "VG_BLEND_DARKEN";
1384 break;
1385 case VG_BLEND_LIGHTEN:
1386 str = "VG_BLEND_LIGHTEN";
1387 break;
1388 case VG_BLEND_ADDITIVE:
1389 str = "VG_BLEND_ADDITIVE";
1390 break;
1391 default:
1392 log_error(_("unsupported VG_BLEND_MODE!"));
1393 }
1394 log_debug(_("VG_BLEND_MODE is %s"), str);
1395 str.clear();
1396
1397 switch(vgGeti(VG_IMAGE_MODE)) {
1398 case VG_DRAW_IMAGE_NORMAL:
1399 str = "VG_DRAW_IMAGE_MULTIPLY";
1400 break;
1401 case VG_DRAW_IMAGE_MULTIPLY:
1402 str = "VG_DRAW_IMAGE_MULTIPLY";
1403 break;
1404 case VG_DRAW_IMAGE_STENCIL:
1405 str = "VG_DRAW_IMAGE_STENCIL";
1406 break;
1407 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1408 case VG_IMAGE_MODE_FORCE_SIZE:
1409 str = "VG_IMAGE_MODE_FORCE_SIZE";
1410 break;
1411 #endif
1412 default:
1413 log_error(_("unsupported VG_IMAGE_MODE!"));
1414 }
1415 log_debug(_("VG_IMAGE_MODE is %s"), str);
1416 str.clear();
1417
1418 log_debug(_("VG_STROKE_LINE_WIDTH is %d"), vgGeti(VG_STROKE_LINE_WIDTH));
1419 str.clear();
1420
1421 switch(vgGeti(VG_STROKE_CAP_STYLE)) {
1422 case VG_CAP_BUTT:
1423 str = "VG_CAP_BUTT";
1424 break;
1425 case VG_CAP_ROUND:
1426 str = "VG_CAP_ROUND";
1427 break;
1428 case VG_CAP_SQUARE:
1429 str = "VG_CAP_SQUARE";
1430 break;
1431 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1432 case VG_CAP_STYLE_FORCE_SIZE:
1433 str = "VG_CAP_STYLE_FORCE_SIZE";
1434 break;
1435 #endif
1436 default:
1437 log_error(_("unsupported VG_STROKE_CAP_STYLE!"));
1438 }
1439 log_debug(_("VG_STROKE_CAP_STYLE is %s"), str);
1440 str.clear();
1441
1442 switch(vgGeti(VG_STROKE_JOIN_STYLE)) {
1443 case VG_JOIN_MITER:
1444 str = "VG_JOIN_MITER";
1445 break;
1446 case VG_JOIN_ROUND:
1447 str = "VG_JOIN_ROUND";
1448 break;
1449 case VG_JOIN_BEVEL:
1450 str = "VG_JOIN_BEVEL";
1451 break;
1452 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1453 case VG_JOIN_STYLE_FORCE_SIZE:
1454 str = "VG_JOIN_STYLE_FORCE_SIZE";
1455 break;
1456 #endif
1457 default:
1458 log_error(_("unsupported VG_STROKE_JOIN_STYLE!"));
1459 }
1460 log_debug(_("VG_STROKE_JOIN_STYLE is %s"), str);
1461 str.clear();
1462
1463 log_debug(_("VG_STROKE_MITER_LIMIT is %d"), vgGeti(VG_STROKE_MITER_LIMIT));
1464 log_debug(_("VG_MASKING is %d"), vgGeti(VG_MASKING));
1465 log_debug(_("VG_SCISSORING is %d"), vgGeti(VG_SCISSORING));
1466 str.clear();
1467
1468 switch(vgGeti(VG_PIXEL_LAYOUT)) {
1469 case VG_PIXEL_LAYOUT_UNKNOWN:
1470 str = "VG_PIXEL_LAYOUT_UNKNOWN";
1471 break;
1472 case VG_PIXEL_LAYOUT_RGB_VERTICAL:
1473 str = "VG_PIXEL_LAYOUT_RGB_VERTICAL";
1474 break;
1475 case VG_PIXEL_LAYOUT_BGR_VERTICAL:
1476 str = "VG_PIXEL_LAYOUT_BGR_VERTICAL";
1477 break;
1478 case VG_PIXEL_LAYOUT_RGB_HORIZONTAL:
1479 str = "VG_PIXEL_LAYOUT_RGB_HORIZONTAL";
1480 break;
1481 case VG_PIXEL_LAYOUT_BGR_HORIZONTAL:
1482 str = "VG_PIXEL_LAYOUT_BGR_HORIZONTAL";
1483 break;
1484 #ifdef VG_MATRIX_MODE_FORCE_SIZE
1485 case VG_PIXEL_LAYOUT_FORCE_SIZE:
1486 str = "VG_PIXEL_LAYOUT_FORCE_SIZE";
1487 break;
1488 #endif
1489 default:
1490 log_error(_("unsupported VG_PIXEL_LAYOUT!"));
1491 }
1492 log_debug(_("VG_PIXEL_LAYOUT is %s"), str);
1493
1494 log_debug(_("VG_STROKE_DASH_PHASE_RESET is %s"),
1495 (vgGeti(VG_STROKE_DASH_PHASE_RESET) == true) ? "true" : "false");
1496 log_debug(_("VG_FILTER_FORMAT_LINEAR is %s"),
1497 (vgGeti(VG_FILTER_FORMAT_LINEAR) == true) ? "true" : "false");
1498 log_debug(_("VG_FILTER_FORMAT_PREMULTIPLIED is %s"),
1499 (vgGeti(VG_FILTER_FORMAT_PREMULTIPLIED) == true) ? "true" : "false");
1500 str.clear();
1501
1502 VGint value = vgGeti(VG_FILTER_CHANNEL_MASK);
1503 if (value & VG_RED) {
1504 str += " VG_RED";
1505 }
1506 if (value & VG_GREEN) {
1507 str += " VG_GREEN";
1508 }
1509 if (value & VG_BLUE) {
1510 str += " VG_BLUE";
1511 }
1512 if (value & VG_ALPHA) {
1513 str += " VG_ALPHA";
1514 }
1515 log_debug(_("VG_FILTER_CHANNEL_MASK is %s"), str);
1516
1517 log_debug(_("VG_MAX_IMAGE_WIDTH is %d"), vgGeti(VG_MAX_IMAGE_WIDTH));
1518 log_debug(_("VG_MAX_IMAGE_HEIGHT is %d"), vgGeti(VG_MAX_IMAGE_HEIGHT));
1519 log_debug(_("VG_MAX_IMAGE_PIXELS is %d"), vgGeti(VG_MAX_IMAGE_PIXELS));
1520 log_debug(_("VG_MAX_IMAGE_BYTES is %d"), vgGeti(VG_MAX_IMAGE_BYTES));
1521
1522 }
1523
1524 void
printVGPath(VGPath path)1525 Renderer_ovg::printVGPath(VGPath path)
1526 {
1527 log_debug(_("VG_PATH_FORMAT is %d"), vgGetParameteri(path, VG_PATH_FORMAT));
1528 log_debug(_("VG_PATH_DATATYPE is %d"), vgGetParameteri(path, VG_PATH_DATATYPE));
1529 log_debug(_("VG_PATH_CAPABILITY_APPEND_TO is %d"), vgGetParameteri(path, VG_PATH_CAPABILITY_APPEND_TO));
1530 log_debug(_("VG_PATH_SCALE is %g"), vgGetParameteri(path, VG_PATH_SCALE));
1531 log_debug(_("VG_PATH_BIA is %g"), vgGetParameteri(path, VG_PATH_BIAS));
1532
1533 log_debug(_("VG_PATH_NUM_SEGMENTS is %d"), vgGetParameteri(path, VG_PATH_NUM_SEGMENTS));
1534 log_debug(_("VG_PATH_NUM_COORDS is %d"), vgGetParameteri(path, VG_PATH_NUM_COORDS));
1535 }
1536
1537 // Print an OpenVG matric, which is 3 x 3. Elements 2 and 5 are
1538 // ignored, as they are the w0 and w1 paramaters.
1539 // It looks like this: { sx, shy, w0, shx, sy, w1, tx, ty, w2 }
1540 void
printVGMatrix(VGfloat * mat)1541 Renderer_ovg::printVGMatrix(VGfloat *mat)
1542 {
1543 std::cerr << "sx, shx, tx: " << mat[0] << ", " << mat[1]<< ", "
1544 << std::fixed << mat[3] << std::endl;
1545 std::cerr << "sy, shy, ty: " << mat[4]<< ", " << mat[6] << ", "
1546 << std::scientific << mat[7] << std::endl;
1547 }
1548
1549 void
printVGMatrix(const SWFMatrix & mat)1550 Renderer_ovg::printVGMatrix(const SWFMatrix &mat)
1551 {
1552 std::cerr << "a, shx, tx: " << mat.a() << ", " << mat.b() << ", " << mat.tx() << std::endl;
1553 std::cerr << "sy, shy, ty: " << mat.c() << ", " << mat.d() << ", " << mat.ty() << std::endl;
1554 }
1555
1556 Renderer *
startInternalRender(gnash::image::GnashImage &)1557 Renderer_ovg::startInternalRender(gnash::image::GnashImage&)
1558 {
1559 // GNASH_REPORT_FUNCTION;
1560
1561 return 0;
1562 }
1563
1564 void
endInternalRender()1565 Renderer_ovg::endInternalRender()
1566 {
1567 // GNASH_REPORT_FUNCTION;
1568 }
1569
1570 void
drawVideoFrame(gnash::image::GnashImage *,gnash::Transform const &,gnash::SWFRect const *,bool)1571 Renderer_ovg::drawVideoFrame(gnash::image::GnashImage*, gnash::Transform const&, gnash::SWFRect const*, bool)
1572 {
1573 GNASH_REPORT_FUNCTION;
1574 }
1575
1576 unsigned int
getBitsPerPixel()1577 Renderer_ovg::getBitsPerPixel()
1578 {
1579 return 0;
1580 }
1581
1582 const char *
getErrorString(VGErrorCode error)1583 Renderer_ovg::getErrorString(VGErrorCode error)
1584 {
1585 switch (error) {
1586 case VG_NO_ERROR:
1587 return "No Error";
1588 break;
1589 case VG_BAD_HANDLE_ERROR:
1590 return "Bad Handle";
1591 break;
1592 case VG_ILLEGAL_ARGUMENT_ERROR:
1593 return "Illegal Argument";
1594 break;
1595 case VG_OUT_OF_MEMORY_ERROR:
1596 return "Our Of Memory";
1597 break;
1598 case VG_PATH_CAPABILITY_ERROR:
1599 return "Path Capability";
1600 break;
1601 case VG_UNSUPPORTED_IMAGE_FORMAT_ERROR:
1602 return "Unsupported Image Format";
1603 break;
1604 case VG_UNSUPPORTED_PATH_FORMAT_ERROR:
1605 return "Unsupported Path Format";
1606 break;
1607 case VG_IMAGE_IN_USE_ERROR:
1608 return "VG Image In Use";
1609 break;
1610 case VG_NO_CONTEXT_ERROR:
1611 return "No COntext";
1612 break;
1613 #ifdef VG_ERROR_CODE_FORCE_SIZE
1614 case VG_ERROR_CODE_FORCE_SIZE:
1615 return "Code Force Size";
1616 break;
1617 #endif
1618 default:
1619 return "Unknown error";
1620 break;
1621 }
1622 }
1623
1624 } // namespace gnash::renderer::gles1
1625 } // namespace gnash::renderer
1626 } // namespace gnash
1627
1628 // local Variables:
1629 // mode: C++
1630 // indent-tabs-mode: nil
1631 // End:
1632