mathematical 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (263) hide show
  1. checksums.yaml +4 -4
  2. data/ext/mathematical/extconf.rb +14 -0
  3. data/ext/mathematical/itex2MML.h +63 -0
  4. data/ext/mathematical/lasemrender.c +257 -0
  5. data/ext/mathematical/lex.yy.c +6548 -0
  6. data/ext/mathematical/lsm.c +31 -0
  7. data/ext/mathematical/lsm.h +39 -0
  8. data/ext/mathematical/lsmattributes.c +279 -0
  9. data/ext/mathematical/lsmattributes.h +75 -0
  10. data/ext/mathematical/lsmcairo.c +598 -0
  11. data/ext/mathematical/lsmcairo.h +51 -0
  12. data/ext/mathematical/lsmdebug.c +183 -0
  13. data/ext/mathematical/lsmdebug.h +73 -0
  14. data/ext/mathematical/lsmdom.h +43 -0
  15. data/ext/mathematical/lsmdomcharacterdata.c +114 -0
  16. data/ext/mathematical/lsmdomcharacterdata.h +59 -0
  17. data/ext/mathematical/lsmdomdocument.c +255 -0
  18. data/ext/mathematical/lsmdomdocument.h +75 -0
  19. data/ext/mathematical/lsmdomdocumentfragment.c +81 -0
  20. data/ext/mathematical/lsmdomdocumentfragment.h +55 -0
  21. data/ext/mathematical/lsmdomelement.c +148 -0
  22. data/ext/mathematical/lsmdomelement.h +62 -0
  23. data/ext/mathematical/lsmdomentities.c +2166 -0
  24. data/ext/mathematical/lsmdomentities.h +35 -0
  25. data/ext/mathematical/lsmdomenumtypes.c +99 -0
  26. data/ext/mathematical/lsmdomenumtypes.h +26 -0
  27. data/ext/mathematical/lsmdomimplementation.c +82 -0
  28. data/ext/mathematical/lsmdomimplementation.h +41 -0
  29. data/ext/mathematical/lsmdomnamednodemap.c +118 -0
  30. data/ext/mathematical/lsmdomnamednodemap.h +64 -0
  31. data/ext/mathematical/lsmdomnode.c +737 -0
  32. data/ext/mathematical/lsmdomnode.h +122 -0
  33. data/ext/mathematical/lsmdomnodelist.c +70 -0
  34. data/ext/mathematical/lsmdomnodelist.h +58 -0
  35. data/ext/mathematical/lsmdomparser.c +461 -0
  36. data/ext/mathematical/lsmdomparser.h +54 -0
  37. data/ext/mathematical/lsmdomtext.c +82 -0
  38. data/ext/mathematical/lsmdomtext.h +55 -0
  39. data/ext/mathematical/lsmdomtypes.h +44 -0
  40. data/ext/mathematical/lsmdomview.c +422 -0
  41. data/ext/mathematical/lsmdomview.h +94 -0
  42. data/ext/mathematical/lsmitex.c +76 -0
  43. data/ext/mathematical/lsmitex.h +36 -0
  44. data/ext/mathematical/lsmmathml.h +66 -0
  45. data/ext/mathematical/lsmmathmlactionelement.c +93 -0
  46. data/ext/mathematical/lsmmathmlactionelement.h +57 -0
  47. data/ext/mathematical/lsmmathmlaligngroupelement.c +102 -0
  48. data/ext/mathematical/lsmmathmlaligngroupelement.h +56 -0
  49. data/ext/mathematical/lsmmathmlalignmarkelement.c +102 -0
  50. data/ext/mathematical/lsmmathmlalignmarkelement.h +56 -0
  51. data/ext/mathematical/lsmmathmlattributes.c +197 -0
  52. data/ext/mathematical/lsmmathmlattributes.h +126 -0
  53. data/ext/mathematical/lsmmathmldocument.c +304 -0
  54. data/ext/mathematical/lsmmathmldocument.h +61 -0
  55. data/ext/mathematical/lsmmathmlelement.c +491 -0
  56. data/ext/mathematical/lsmmathmlelement.h +107 -0
  57. data/ext/mathematical/lsmmathmlenums.c +429 -0
  58. data/ext/mathematical/lsmmathmlenums.h +182 -0
  59. data/ext/mathematical/lsmmathmlenumtypes.c +666 -0
  60. data/ext/mathematical/lsmmathmlenumtypes.h +90 -0
  61. data/ext/mathematical/lsmmathmlerrorelement.c +58 -0
  62. data/ext/mathematical/lsmmathmlerrorelement.h +56 -0
  63. data/ext/mathematical/lsmmathmlfencedelement.c +178 -0
  64. data/ext/mathematical/lsmmathmlfencedelement.h +65 -0
  65. data/ext/mathematical/lsmmathmlfractionelement.c +253 -0
  66. data/ext/mathematical/lsmmathmlfractionelement.h +62 -0
  67. data/ext/mathematical/lsmmathmlglyphtableams.c +597 -0
  68. data/ext/mathematical/lsmmathmlglyphtableams.h +45 -0
  69. data/ext/mathematical/lsmmathmlitexelement.c +187 -0
  70. data/ext/mathematical/lsmmathmlitexelement.h +60 -0
  71. data/ext/mathematical/lsmmathmllayoututils.c +191 -0
  72. data/ext/mathematical/lsmmathmllayoututils.h +58 -0
  73. data/ext/mathematical/lsmmathmlmathelement.c +204 -0
  74. data/ext/mathematical/lsmmathmlmathelement.h +81 -0
  75. data/ext/mathematical/lsmmathmloperatordictionary.c +3332 -0
  76. data/ext/mathematical/lsmmathmloperatordictionary.h +54 -0
  77. data/ext/mathematical/lsmmathmloperatorelement.c +307 -0
  78. data/ext/mathematical/lsmmathmloperatorelement.h +73 -0
  79. data/ext/mathematical/lsmmathmlpaddedelement.c +58 -0
  80. data/ext/mathematical/lsmmathmlpaddedelement.h +56 -0
  81. data/ext/mathematical/lsmmathmlphantomelement.c +71 -0
  82. data/ext/mathematical/lsmmathmlphantomelement.h +56 -0
  83. data/ext/mathematical/lsmmathmlpresentationcontainer.c +43 -0
  84. data/ext/mathematical/lsmmathmlpresentationcontainer.h +54 -0
  85. data/ext/mathematical/lsmmathmlpresentationtoken.c +303 -0
  86. data/ext/mathematical/lsmmathmlpresentationtoken.h +83 -0
  87. data/ext/mathematical/lsmmathmlradicalelement.c +266 -0
  88. data/ext/mathematical/lsmmathmlradicalelement.h +71 -0
  89. data/ext/mathematical/lsmmathmlrowelement.c +58 -0
  90. data/ext/mathematical/lsmmathmlrowelement.h +56 -0
  91. data/ext/mathematical/lsmmathmlscriptelement.c +282 -0
  92. data/ext/mathematical/lsmmathmlscriptelement.h +78 -0
  93. data/ext/mathematical/lsmmathmlsemanticselement.c +84 -0
  94. data/ext/mathematical/lsmmathmlsemanticselement.h +56 -0
  95. data/ext/mathematical/lsmmathmlspaceelement.c +142 -0
  96. data/ext/mathematical/lsmmathmlspaceelement.h +60 -0
  97. data/ext/mathematical/lsmmathmlstringelement.c +123 -0
  98. data/ext/mathematical/lsmmathmlstringelement.h +58 -0
  99. data/ext/mathematical/lsmmathmlstyle.c +130 -0
  100. data/ext/mathematical/lsmmathmlstyle.h +81 -0
  101. data/ext/mathematical/lsmmathmlstyleelement.c +307 -0
  102. data/ext/mathematical/lsmmathmlstyleelement.h +87 -0
  103. data/ext/mathematical/lsmmathmltablecellelement.c +122 -0
  104. data/ext/mathematical/lsmmathmltablecellelement.h +62 -0
  105. data/ext/mathematical/lsmmathmltableelement.c +545 -0
  106. data/ext/mathematical/lsmmathmltableelement.h +78 -0
  107. data/ext/mathematical/lsmmathmltablerowelement.c +120 -0
  108. data/ext/mathematical/lsmmathmltablerowelement.h +64 -0
  109. data/ext/mathematical/lsmmathmltraits.c +819 -0
  110. data/ext/mathematical/lsmmathmltraits.h +119 -0
  111. data/ext/mathematical/lsmmathmltypes.h +66 -0
  112. data/ext/mathematical/lsmmathmlunderoverelement.c +485 -0
  113. data/ext/mathematical/lsmmathmlunderoverelement.h +82 -0
  114. data/ext/mathematical/lsmmathmlutils.c +170 -0
  115. data/ext/mathematical/lsmmathmlutils.h +50 -0
  116. data/ext/mathematical/lsmmathmlview.c +1048 -0
  117. data/ext/mathematical/lsmmathmlview.h +164 -0
  118. data/ext/mathematical/lsmproperties.c +418 -0
  119. data/ext/mathematical/lsmproperties.h +85 -0
  120. data/ext/mathematical/lsmstr.c +231 -0
  121. data/ext/mathematical/lsmstr.h +114 -0
  122. data/ext/mathematical/lsmsvg.h +67 -0
  123. data/ext/mathematical/lsmsvgaelement.c +73 -0
  124. data/ext/mathematical/lsmsvgaelement.h +55 -0
  125. data/ext/mathematical/lsmsvgattributes.h +118 -0
  126. data/ext/mathematical/lsmsvgcircleelement.c +153 -0
  127. data/ext/mathematical/lsmsvgcircleelement.h +59 -0
  128. data/ext/mathematical/lsmsvgclippathelement.c +134 -0
  129. data/ext/mathematical/lsmsvgclippathelement.h +59 -0
  130. data/ext/mathematical/lsmsvgcolors.c +212 -0
  131. data/ext/mathematical/lsmsvgcolors.h +39 -0
  132. data/ext/mathematical/lsmsvgdefselement.c +74 -0
  133. data/ext/mathematical/lsmsvgdefselement.h +55 -0
  134. data/ext/mathematical/lsmsvgdocument.c +288 -0
  135. data/ext/mathematical/lsmsvgdocument.h +64 -0
  136. data/ext/mathematical/lsmsvgelement.c +373 -0
  137. data/ext/mathematical/lsmsvgelement.h +81 -0
  138. data/ext/mathematical/lsmsvgellipseelement.c +158 -0
  139. data/ext/mathematical/lsmsvgellipseelement.h +60 -0
  140. data/ext/mathematical/lsmsvgenums.c +544 -0
  141. data/ext/mathematical/lsmsvgenums.h +357 -0
  142. data/ext/mathematical/lsmsvgenumtypes.c +1083 -0
  143. data/ext/mathematical/lsmsvgenumtypes.h +111 -0
  144. data/ext/mathematical/lsmsvgfilterblend.c +105 -0
  145. data/ext/mathematical/lsmsvgfilterblend.h +58 -0
  146. data/ext/mathematical/lsmsvgfiltercomposite.c +109 -0
  147. data/ext/mathematical/lsmsvgfiltercomposite.h +58 -0
  148. data/ext/mathematical/lsmsvgfilterelement.c +266 -0
  149. data/ext/mathematical/lsmsvgfilterelement.h +66 -0
  150. data/ext/mathematical/lsmsvgfilterflood.c +86 -0
  151. data/ext/mathematical/lsmsvgfilterflood.h +55 -0
  152. data/ext/mathematical/lsmsvgfiltergaussianblur.c +114 -0
  153. data/ext/mathematical/lsmsvgfiltergaussianblur.h +57 -0
  154. data/ext/mathematical/lsmsvgfiltermerge.c +98 -0
  155. data/ext/mathematical/lsmsvgfiltermerge.h +55 -0
  156. data/ext/mathematical/lsmsvgfiltermergenode.c +87 -0
  157. data/ext/mathematical/lsmsvgfiltermergenode.h +57 -0
  158. data/ext/mathematical/lsmsvgfilteroffset.c +112 -0
  159. data/ext/mathematical/lsmsvgfilteroffset.h +58 -0
  160. data/ext/mathematical/lsmsvgfilterprimitive.c +168 -0
  161. data/ext/mathematical/lsmsvgfilterprimitive.h +66 -0
  162. data/ext/mathematical/lsmsvgfilterspecularlighting.c +127 -0
  163. data/ext/mathematical/lsmsvgfilterspecularlighting.h +60 -0
  164. data/ext/mathematical/lsmsvgfiltersurface.c +455 -0
  165. data/ext/mathematical/lsmsvgfiltersurface.h +66 -0
  166. data/ext/mathematical/lsmsvgfiltertile.c +102 -0
  167. data/ext/mathematical/lsmsvgfiltertile.h +57 -0
  168. data/ext/mathematical/lsmsvggelement.c +73 -0
  169. data/ext/mathematical/lsmsvggelement.h +55 -0
  170. data/ext/mathematical/lsmsvggradientelement.c +151 -0
  171. data/ext/mathematical/lsmsvggradientelement.h +68 -0
  172. data/ext/mathematical/lsmsvgimageelement.c +261 -0
  173. data/ext/mathematical/lsmsvgimageelement.h +67 -0
  174. data/ext/mathematical/lsmsvglength.c +152 -0
  175. data/ext/mathematical/lsmsvglength.h +65 -0
  176. data/ext/mathematical/lsmsvglineargradientelement.c +271 -0
  177. data/ext/mathematical/lsmsvglineargradientelement.h +60 -0
  178. data/ext/mathematical/lsmsvglineelement.c +153 -0
  179. data/ext/mathematical/lsmsvglineelement.h +60 -0
  180. data/ext/mathematical/lsmsvgmarkerelement.c +266 -0
  181. data/ext/mathematical/lsmsvgmarkerelement.h +74 -0
  182. data/ext/mathematical/lsmsvgmaskelement.c +232 -0
  183. data/ext/mathematical/lsmsvgmaskelement.h +64 -0
  184. data/ext/mathematical/lsmsvgmatrix.c +205 -0
  185. data/ext/mathematical/lsmsvgmatrix.h +59 -0
  186. data/ext/mathematical/lsmsvgpathelement.c +115 -0
  187. data/ext/mathematical/lsmsvgpathelement.h +59 -0
  188. data/ext/mathematical/lsmsvgpatternelement.c +398 -0
  189. data/ext/mathematical/lsmsvgpatternelement.h +69 -0
  190. data/ext/mathematical/lsmsvgpolygonelement.c +106 -0
  191. data/ext/mathematical/lsmsvgpolygonelement.h +57 -0
  192. data/ext/mathematical/lsmsvgpolylineelement.c +106 -0
  193. data/ext/mathematical/lsmsvgpolylineelement.h +57 -0
  194. data/ext/mathematical/lsmsvgradialgradientelement.c +323 -0
  195. data/ext/mathematical/lsmsvgradialgradientelement.h +61 -0
  196. data/ext/mathematical/lsmsvgrectelement.c +184 -0
  197. data/ext/mathematical/lsmsvgrectelement.h +62 -0
  198. data/ext/mathematical/lsmsvgstopelement.c +106 -0
  199. data/ext/mathematical/lsmsvgstopelement.h +57 -0
  200. data/ext/mathematical/lsmsvgstyle.c +560 -0
  201. data/ext/mathematical/lsmsvgstyle.h +217 -0
  202. data/ext/mathematical/lsmsvgsvgelement.c +260 -0
  203. data/ext/mathematical/lsmsvgsvgelement.h +71 -0
  204. data/ext/mathematical/lsmsvgswitchelement.c +103 -0
  205. data/ext/mathematical/lsmsvgswitchelement.h +55 -0
  206. data/ext/mathematical/lsmsvgsymbolelement.c +74 -0
  207. data/ext/mathematical/lsmsvgsymbolelement.h +55 -0
  208. data/ext/mathematical/lsmsvgtextelement.c +203 -0
  209. data/ext/mathematical/lsmsvgtextelement.h +60 -0
  210. data/ext/mathematical/lsmsvgtraits.c +1232 -0
  211. data/ext/mathematical/lsmsvgtraits.h +104 -0
  212. data/ext/mathematical/lsmsvgtransformable.c +106 -0
  213. data/ext/mathematical/lsmsvgtransformable.h +54 -0
  214. data/ext/mathematical/lsmsvgtspanelement.c +174 -0
  215. data/ext/mathematical/lsmsvgtspanelement.h +60 -0
  216. data/ext/mathematical/lsmsvgtypes.h +77 -0
  217. data/ext/mathematical/lsmsvguseelement.c +237 -0
  218. data/ext/mathematical/lsmsvguseelement.h +69 -0
  219. data/ext/mathematical/lsmsvgview.c +2583 -0
  220. data/ext/mathematical/lsmsvgview.h +179 -0
  221. data/ext/mathematical/lsmtraits.c +119 -0
  222. data/ext/mathematical/lsmtraits.h +49 -0
  223. data/ext/mathematical/lsmtypes.h +36 -0
  224. data/ext/mathematical/lsmutils.c +54 -0
  225. data/ext/mathematical/lsmutils.h +56 -0
  226. data/ext/mathematical/mathematical.c +145 -0
  227. data/ext/mathematical/y.tab.c +6179 -0
  228. data/ext/mathematical/y.tab.h +389 -0
  229. data/lib/mathematical/version.rb +1 -1
  230. data/mathematical.gemspec +8 -6
  231. data/test/mathematical/basic_test.rb +9 -0
  232. data/test/mathematical/fixtures/after/brackets_display.html +1 -0
  233. data/test/mathematical/fixtures/after/compliance_accents.html +17 -0
  234. data/test/mathematical/fixtures/after/compliance_arrows.html +71 -0
  235. data/test/mathematical/fixtures/after/compliance_colors.html +4 -0
  236. data/test/mathematical/fixtures/after/compliance_greek_letters.html +42 -0
  237. data/test/mathematical/fixtures/after/compliance_large_math.html +19 -0
  238. data/test/mathematical/fixtures/after/compliance_log_symbols.html +34 -0
  239. data/test/mathematical/fixtures/after/compliance_operators.html +262 -0
  240. data/test/mathematical/fixtures/after/dollar_sign_inline.html +1 -0
  241. data/test/mathematical/fixtures/after/equation_display.html +1 -0
  242. data/test/mathematical/fixtures/after/multiple_dollar_inline.html +1 -0
  243. data/test/mathematical/fixtures/after/parens_inline.html +1 -0
  244. data/test/mathematical/fixtures/before/brackets_display.text +1 -0
  245. data/test/mathematical/fixtures/before/compliance_accents.text +17 -0
  246. data/test/mathematical/fixtures/before/compliance_arrows.text +71 -0
  247. data/test/mathematical/fixtures/before/compliance_colors.text +4 -0
  248. data/test/mathematical/fixtures/before/compliance_greek_letters.text +42 -0
  249. data/test/mathematical/fixtures/before/compliance_large_math.text +19 -0
  250. data/test/mathematical/fixtures/before/compliance_log_symbols.text +34 -0
  251. data/test/mathematical/fixtures/before/compliance_operators.text +262 -0
  252. data/test/mathematical/fixtures/before/dollar_sign_inline.text +1 -0
  253. data/test/mathematical/fixtures/before/equation_display.text +1 -0
  254. data/test/mathematical/fixtures/before/multiple_dollar_inline.text +1 -0
  255. data/test/mathematical/fixtures/before/parens_inline.text +1 -0
  256. data/test/mathematical/fixtures/performance/big_file.text +1767 -0
  257. data/test/mathematical/fixtures_test.rb +45 -0
  258. data/test/mathematical/maliciousness_test.rb +45 -0
  259. data/test/mathematical/performance_test.rb +15 -0
  260. data/test/test_helper.rb +5 -0
  261. metadata +301 -14
  262. data/lib/mathematical.bundle +0 -0
  263. data/lib/mathematical/mathematical.bundle +0 -0
@@ -0,0 +1,77 @@
1
+ /* Lasem - SVG and Mathml library
2
+ *
3
+ * Copyright © 2010 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
+ #ifndef LSM_SVG_TYPES_H
25
+ #define LSM_SVG_TYPES_H
26
+
27
+ #include <lsmsvgenums.h>
28
+
29
+ G_BEGIN_DECLS
30
+
31
+ typedef struct _LsmSvgDocument LsmSvgDocument;
32
+ typedef struct _LsmSvgElement LsmSvgElement;
33
+ typedef struct _LsmSvgTransformable LsmSvgTransformable;
34
+ typedef struct _LsmSvgGraphic LsmSvgGraphic;
35
+ typedef struct _LsmSvgClipPathElement LsmSvgClipPathElement;
36
+ typedef struct _LsmSvgSvgElement LsmSvgSvgElement;
37
+ typedef struct _LsmSvgAElement LsmSvgAElement;
38
+ typedef struct _LsmSvgGElement LsmSvgGElement;
39
+ typedef struct _LsmSvgDefsElement LsmSvgDefsElement;
40
+ typedef struct _LsmSvgUseElement LsmSvgUseElement;
41
+ typedef struct _LsmSvgImageElement LsmSvgImageElement;
42
+ typedef struct _LsmSvgSymbolElement LsmSvgSymbolElement;
43
+ typedef struct _LsmSvgMarkerElement LsmSvgMarkerElement;
44
+ typedef struct _LsmSvgRectElement LsmSvgRectElement;
45
+ typedef struct _LsmSvgCircleElement LsmSvgCircleElement;
46
+ typedef struct _LsmSvgEllipseElement LsmSvgEllipseElement;
47
+ typedef struct _LsmSvgFilterElement LsmSvgFilterElement;
48
+ typedef struct _LsmSvgFilterPrimitive LsmSvgFilterPrimitive;
49
+ typedef struct _LsmSvgFilterBlend LsmSvgFilterBlend;
50
+ typedef struct _LsmSvgFilterComposite LsmSvgFilterComposite;
51
+ typedef struct _LsmSvgFilterFlood LsmSvgFilterFlood;
52
+ typedef struct _LsmSvgFilterGaussianBlur LsmSvgFilterGaussianBlur;
53
+ typedef struct _LsmSvgFilterMerge LsmSvgFilterMerge;
54
+ typedef struct _LsmSvgFilterMergeNode LsmSvgFilterMergeNode;
55
+ typedef struct _LsmSvgFilterOffset LsmSvgFilterOffset;
56
+ typedef struct _LsmSvgFilterSpecularLighting LsmSvgFilterSpecularLighting;
57
+ typedef struct _LsmSvgFilterTile LsmSvgFilterTile;
58
+ typedef struct _LsmSvgLineElement LsmSvgLineElement;
59
+ typedef struct _LsmSvgPolylineElement LsmSvgPolylineElement;
60
+ typedef struct _LsmSvgPolygonElement LsmSvgPolygonElement;
61
+ typedef struct _LsmSvgPathElement LsmSvgPathElement;
62
+ typedef struct _LsmSvgTextElement LsmSvgTextElement;
63
+ typedef struct _LsmSvgTspanElement LsmSvgTspanElement;
64
+ typedef struct _LsmSvgGradientElement LsmSvgGradientElement;
65
+ typedef struct _LsmSvgLinearGradientElement LsmSvgLinearGradientElement;
66
+ typedef struct _LsmSvgRadialGradientElement LsmSvgRadialGradientElement;
67
+ typedef struct _LsmSvgStopElement LsmSvgStopElement;
68
+ typedef struct _LsmSvgSwitchElement LsmSvgSwitchElement;
69
+ typedef struct _LsmSvgPatternElement LsmSvgPatternElement;
70
+ typedef struct _LsmSvgMaskElement LsmSvgMaskElement;
71
+
72
+ typedef struct _LsmSvgView LsmSvgView;
73
+ typedef struct _LsmSvgStyle LsmSvgStyle;
74
+
75
+ G_END_DECLS
76
+
77
+ #endif
@@ -0,0 +1,237 @@
1
+ /* Lasem
2
+ *
3
+ * Copyright © 2009 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
+ #include <lsmsvguseelement.h>
25
+ #include <lsmsvgview.h>
26
+ #include <lsmdebug.h>
27
+ #include <lsmsvgdocument.h>
28
+ #include <stdio.h>
29
+
30
+ static GObjectClass *parent_class;
31
+
32
+ /* GdomNode implementation */
33
+
34
+ static const char *
35
+ lsm_svg_use_element_get_node_name (LsmDomNode *node)
36
+ {
37
+ return "use";
38
+ }
39
+
40
+ static gboolean
41
+ lsm_svg_use_can_append_child (LsmDomNode *node, LsmDomNode *child)
42
+ {
43
+ return FALSE;
44
+ }
45
+
46
+ /* LsmSvgElement implementation */
47
+
48
+ /* LsmSvgGraphic implementation */
49
+
50
+ static LsmDomElement *
51
+ _get_used_element (LsmSvgUseElement *use_element)
52
+ {
53
+ LsmDomDocument *document;
54
+ LsmDomElement *element;
55
+ const char *id;
56
+
57
+ document = lsm_dom_node_get_owner_document (LSM_DOM_NODE (use_element));
58
+ if (document == NULL) {
59
+ lsm_debug_dom ("[LsmSvgUseElement::_get_used_element] Owner document not found");
60
+ return NULL;
61
+ }
62
+
63
+ id = use_element->href.value;
64
+ if (id == NULL)
65
+ return NULL;
66
+
67
+ if (*id == '#')
68
+ id++;
69
+
70
+ element = LSM_DOM_ELEMENT (lsm_svg_document_get_element_by_id (LSM_SVG_DOCUMENT (document), id));
71
+ if (!LSM_IS_SVG_ELEMENT (element)) {
72
+ lsm_debug_dom ("[LsmSvgUseElement::_get_used_element] Target '%s' not found", id);
73
+ return NULL;
74
+ }
75
+
76
+ return element;
77
+ }
78
+
79
+ static void
80
+ lsm_svg_use_element_render (LsmSvgElement *self, LsmSvgView *view)
81
+ {
82
+ LsmSvgUseElement *use_element = LSM_SVG_USE_ELEMENT (self);
83
+ LsmDomElement *element;
84
+ LsmSvgMatrix matrix;
85
+ double x, y;
86
+
87
+ if (use_element->flags & LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_RENDER) {
88
+ lsm_debug_render ("[LsmSvgUseElement::render] Circular reference");
89
+ return;
90
+ }
91
+
92
+ element = _get_used_element (use_element);
93
+ if (element == NULL)
94
+ return;
95
+
96
+ use_element->flags |= LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_RENDER;
97
+
98
+ x = lsm_svg_view_normalize_length (view, &use_element->x.length,
99
+ LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
100
+ y = lsm_svg_view_normalize_length (view, &use_element->y.length,
101
+ LSM_SVG_LENGTH_DIRECTION_VERTICAL);
102
+
103
+ lsm_svg_matrix_init_translate (&matrix, x, y);
104
+
105
+ if (lsm_svg_view_push_matrix (view, &matrix))
106
+ lsm_svg_element_render (LSM_SVG_ELEMENT (element), view);
107
+
108
+ lsm_svg_view_pop_matrix (view);
109
+
110
+ use_element->flags &= ~LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_RENDER;
111
+ }
112
+
113
+ static void
114
+ lsm_svg_use_element_get_extents (LsmSvgElement *self, LsmSvgView *view, LsmExtents *extents)
115
+ {
116
+ LsmSvgUseElement *use_element = LSM_SVG_USE_ELEMENT (self);
117
+ LsmDomElement *element;
118
+ LsmSvgMatrix matrix;
119
+ double x, y;
120
+
121
+ if (use_element->flags & LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_GET_EXTENTS) {
122
+ lsm_debug_render ("[LsmSvgUseElement::get_extents] Circular reference");
123
+ extents->x1 = 0;
124
+ extents->y1 = 0;
125
+ extents->x2 = 0;
126
+ extents->y2 = 0;
127
+ return;
128
+ }
129
+
130
+ element = _get_used_element (use_element);
131
+ if (element == NULL) {
132
+ extents->x1 = 0;
133
+ extents->y1 = 0;
134
+ extents->x2 = 0;
135
+ extents->y2 = 0;
136
+ return;
137
+ }
138
+
139
+ use_element->flags |= LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_GET_EXTENTS;
140
+
141
+ x = lsm_svg_view_normalize_length (view, &use_element->x.length,
142
+ LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
143
+ y = lsm_svg_view_normalize_length (view, &use_element->y.length,
144
+ LSM_SVG_LENGTH_DIRECTION_VERTICAL);
145
+
146
+ lsm_svg_element_transformed_get_extents (LSM_SVG_ELEMENT (element), view, extents);
147
+
148
+ lsm_svg_matrix_init_translate (&matrix, x, y);
149
+
150
+ if (lsm_svg_view_push_matrix (view, &matrix))
151
+ lsm_svg_matrix_transform_bounding_box (&matrix,
152
+ &extents->x1, &extents->y1,
153
+ &extents->x2, &extents->y2);
154
+ lsm_svg_view_pop_matrix (view);
155
+
156
+ use_element->flags &= ~LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_GET_EXTENTS;
157
+ }
158
+
159
+ /* LsmSvgUseElement implementation */
160
+
161
+ LsmDomNode *
162
+ lsm_svg_use_element_new (void)
163
+ {
164
+ return g_object_new (LSM_TYPE_SVG_USE_ELEMENT, NULL);
165
+ }
166
+
167
+ static const LsmSvgLength length_default = { .value_unit = 0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
168
+
169
+ static void
170
+ lsm_svg_use_element_init (LsmSvgUseElement *self)
171
+ {
172
+ self->x.length = length_default;
173
+ self->y.length = length_default;
174
+ self->width.length = length_default;
175
+ self->height.length = length_default;
176
+ }
177
+
178
+ /* LsmSvgUseElement class */
179
+
180
+ static const LsmAttributeInfos lsm_svg_use_element_attribute_infos[] = {
181
+ {
182
+ .name = "x",
183
+ .attribute_offset = offsetof (LsmSvgUseElement, x),
184
+ .trait_class = &lsm_svg_length_trait_class,
185
+ .trait_default = &length_default
186
+ },
187
+ {
188
+ .name = "y",
189
+ .attribute_offset = offsetof (LsmSvgUseElement, y),
190
+ .trait_class = &lsm_svg_length_trait_class,
191
+ .trait_default = &length_default
192
+ },
193
+ {
194
+ .name = "width",
195
+ .attribute_offset = offsetof (LsmSvgUseElement, width),
196
+ .trait_class = &lsm_svg_length_trait_class,
197
+ .trait_default = &length_default
198
+ },
199
+ {
200
+ .name = "height",
201
+ .attribute_offset = offsetof (LsmSvgUseElement, height),
202
+ .trait_class = &lsm_svg_length_trait_class,
203
+ .trait_default = &length_default
204
+ },
205
+ {
206
+ .name = "xlink:href",
207
+ .attribute_offset = offsetof (LsmSvgUseElement, href),
208
+ .trait_class = &lsm_null_trait_class
209
+ }
210
+ };
211
+
212
+ static void
213
+ lsm_svg_use_element_class_init (LsmSvgUseElementClass *klass)
214
+ {
215
+ LsmDomNodeClass *d_node_class = LSM_DOM_NODE_CLASS (klass);
216
+ LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_CLASS (klass);
217
+
218
+ parent_class = g_type_class_peek_parent (klass);
219
+
220
+ d_node_class->get_node_name = lsm_svg_use_element_get_node_name;
221
+ d_node_class->can_append_child = lsm_svg_use_can_append_child;
222
+
223
+ s_element_class->category =
224
+ LSM_SVG_ELEMENT_CATEGORY_GRAPHICS |
225
+ LSM_SVG_ELEMENT_CATEGORY_GRAPHICS_REFERENCING |
226
+ LSM_SVG_ELEMENT_CATEGORY_STRUCTURAL;
227
+
228
+ s_element_class->render = lsm_svg_use_element_render;
229
+ s_element_class->get_extents = lsm_svg_use_element_get_extents;
230
+ s_element_class->attribute_manager = lsm_attribute_manager_duplicate (s_element_class->attribute_manager);
231
+
232
+ lsm_attribute_manager_add_attributes (s_element_class->attribute_manager,
233
+ G_N_ELEMENTS (lsm_svg_use_element_attribute_infos),
234
+ lsm_svg_use_element_attribute_infos);
235
+ }
236
+
237
+ G_DEFINE_TYPE (LsmSvgUseElement, lsm_svg_use_element, LSM_TYPE_SVG_TRANSFORMABLE)
@@ -0,0 +1,69 @@
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
+ #ifndef LSM_SVG_USE_ELEMENT_H
25
+ #define LSM_SVG_USE_ELEMENT_H
26
+
27
+ #include <lsmsvgtypes.h>
28
+ #include <lsmsvgtransformable.h>
29
+
30
+ G_BEGIN_DECLS
31
+
32
+ typedef enum {
33
+ LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_RENDER = 1 << 0,
34
+ LSM_SVG_USE_ELEMENT_FLAGS_IN_USE_FOR_GET_EXTENTS = 1 << 1
35
+ } LsmSvgUseElementFlags;
36
+
37
+ #define LSM_TYPE_SVG_USE_ELEMENT (lsm_svg_use_element_get_type ())
38
+ #define LSM_SVG_USE_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LSM_TYPE_SVG_USE_ELEMENT, LsmSvgUseElement))
39
+ #define LSM_SVG_USE_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LSM_TYPE_SVG_USE_ELEMENT, LsmSvgUseElementClass))
40
+ #define LSM_IS_SVG_USE_ELEMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LSM_TYPE_SVG_USE_ELEMENT))
41
+ #define LSM_IS_SVG_USE_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LSM_TYPE_SVG_USE_ELEMENT))
42
+ #define LSM_SVG_USE_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), LSM_TYPE_SVG_USE_ELEMENT, LsmSvgUseElementClass))
43
+
44
+ typedef struct _LsmSvgUseElementClass LsmSvgUseElementClass;
45
+
46
+ struct _LsmSvgUseElement {
47
+ LsmSvgTransformable base;
48
+
49
+ LsmSvgLengthAttribute x;
50
+ LsmSvgLengthAttribute y;
51
+ LsmSvgLengthAttribute width;
52
+ LsmSvgLengthAttribute height;
53
+
54
+ LsmAttribute href;
55
+
56
+ LsmSvgUseElementFlags flags;
57
+ };
58
+
59
+ struct _LsmSvgUseElementClass {
60
+ LsmSvgTransformableClass base_class;
61
+ };
62
+
63
+ GType lsm_svg_use_element_get_type (void);
64
+
65
+ LsmDomNode * lsm_svg_use_element_new (void);
66
+
67
+ G_END_DECLS
68
+
69
+ #endif
@@ -0,0 +1,2583 @@
1
+ /* Lasem
2
+ *
3
+ * Copyright © 2009 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
+ #include <lsmdebug.h>
25
+ #include <lsmsvgview.h>
26
+ #include <lsmsvgdocument.h>
27
+ #include <lsmsvgelement.h>
28
+ #include <lsmsvgsvgelement.h>
29
+ #include <lsmsvgradialgradientelement.h>
30
+ #include <lsmsvgfilterelement.h>
31
+ #include <lsmsvglineargradientelement.h>
32
+ #include <lsmsvgpatternelement.h>
33
+ #include <lsmsvgmarkerelement.h>
34
+ #include <lsmsvgclippathelement.h>
35
+ #include <lsmsvgmaskelement.h>
36
+ #include <lsmsvgfiltersurface.h>
37
+ #include <lsmcairo.h>
38
+ #include <lsmstr.h>
39
+ #include <gdk-pixbuf/gdk-pixbuf.h>
40
+ #include <glib/gprintf.h>
41
+
42
+ #include <math.h>
43
+ #include <string.h>
44
+
45
+ static gboolean lsm_svg_view_circular_reference_check (LsmSvgView *view, LsmSvgElement *element);
46
+
47
+ static GObjectClass *parent_class;
48
+
49
+ typedef struct {
50
+ gboolean is_text_path;
51
+ gboolean is_extents_defined;
52
+ LsmExtents extents;
53
+ PangoLayout *pango_layout;
54
+ } LsmSvgViewPathInfos;
55
+
56
+ static LsmSvgViewPathInfos default_path_infos = {
57
+ .is_text_path = FALSE,
58
+ .is_extents_defined = FALSE,
59
+ .extents = {0.0, 0.0, 0.0, 0.0},
60
+ .pango_layout = NULL
61
+ };
62
+
63
+ struct _LsmSvgViewPatternData {
64
+ cairo_t *old_cairo;
65
+
66
+ cairo_pattern_t *pattern;
67
+
68
+ LsmBox extents;
69
+ LsmBox object_extents;
70
+
71
+ double opacity;
72
+ };
73
+
74
+ typedef struct {
75
+ cairo_surface_t *surface;
76
+ double group_opacity;
77
+ gboolean enable_background;
78
+ } LsmSvgViewBackground;
79
+
80
+ cairo_operator_t cairo_operators[] = {
81
+ CAIRO_OPERATOR_CLEAR,
82
+ CAIRO_OPERATOR_SOURCE,
83
+ CAIRO_OPERATOR_DEST,
84
+ CAIRO_OPERATOR_OVER,
85
+ CAIRO_OPERATOR_DEST_OVER,
86
+ CAIRO_OPERATOR_IN,
87
+ CAIRO_OPERATOR_DEST_IN,
88
+ CAIRO_OPERATOR_OUT,
89
+ CAIRO_OPERATOR_DEST_OUT,
90
+ CAIRO_OPERATOR_ATOP,
91
+ CAIRO_OPERATOR_DEST_ATOP,
92
+ CAIRO_OPERATOR_XOR,
93
+ CAIRO_OPERATOR_ADD,
94
+ CAIRO_OPERATOR_MULTIPLY,
95
+ CAIRO_OPERATOR_SCREEN,
96
+ CAIRO_OPERATOR_OVERLAY,
97
+ CAIRO_OPERATOR_DARKEN,
98
+ CAIRO_OPERATOR_LIGHTEN,
99
+ CAIRO_OPERATOR_COLOR_DODGE,
100
+ CAIRO_OPERATOR_COLOR_BURN,
101
+ CAIRO_OPERATOR_HARD_LIGHT,
102
+ CAIRO_OPERATOR_SOFT_LIGHT,
103
+ CAIRO_OPERATOR_DIFFERENCE,
104
+ CAIRO_OPERATOR_EXCLUSION
105
+ };
106
+
107
+ static void
108
+ lsm_cairo_set_comp_op (cairo_t *cairo, LsmSvgCompOp comp_op)
109
+ {
110
+ if (G_LIKELY (cairo != NULL && comp_op >= LSM_SVG_COMP_OP_CLEAR && comp_op <= LSM_SVG_COMP_OP_EXCLUSION)) {
111
+ lsm_log_render ("[lsmSvgView::set_comp_op] Set comp-op to %s", lsm_svg_comp_op_to_string (comp_op));
112
+ cairo_set_operator (cairo, cairo_operators[comp_op]);
113
+ }
114
+ }
115
+
116
+ double
117
+ lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, LsmSvgLengthDirection direction)
118
+ {
119
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), 0.0);
120
+
121
+ return lsm_svg_length_normalize (length, view->viewbox_stack->data, view->style->font_size_px, direction);
122
+ }
123
+
124
+ double *
125
+ lsm_svg_view_normalize_length_list (LsmSvgView *view, const LsmSvgLengthList *list, LsmSvgLengthDirection direction, unsigned int *n_data)
126
+ {
127
+ double *data;
128
+ unsigned int i;
129
+
130
+ g_return_val_if_fail (n_data != NULL, NULL);
131
+ *n_data = 0;
132
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
133
+
134
+ if (list->n_lengths == 0)
135
+ return NULL;
136
+
137
+ *n_data = list->n_lengths;
138
+ data = g_new (double, list->n_lengths);
139
+ for (i = 0; i < list->n_lengths; i++)
140
+ data[i] = lsm_svg_view_normalize_length (view, &list->lengths[i], direction);
141
+
142
+ return data;
143
+ }
144
+
145
+ static void
146
+ _start_pattern (LsmSvgView *view, const LsmBox *extents, const LsmBox *object_extents, double opacity)
147
+ {
148
+ lsm_debug_render ("[LsmSvgView::start_pattern]");
149
+
150
+ view->pattern_stack = g_slist_prepend (view->pattern_stack, view->pattern_data);
151
+
152
+ view->pattern_data = g_new (LsmSvgViewPatternData, 1);
153
+ view->pattern_data->old_cairo = view->dom_view.cairo;
154
+ view->pattern_data->pattern = NULL;
155
+ view->pattern_data->extents = *extents;
156
+ view->pattern_data->opacity = opacity;
157
+ view->pattern_data->object_extents = *object_extents;
158
+
159
+ view->dom_view.cairo = NULL;
160
+ }
161
+
162
+ static void
163
+ _end_pattern (LsmSvgView *view)
164
+ {
165
+ g_return_if_fail (view->pattern_data != NULL);
166
+
167
+ if (view->pattern_data->pattern != NULL)
168
+ cairo_pattern_destroy (view->pattern_data->pattern);
169
+ if (view->dom_view.cairo != NULL)
170
+ cairo_destroy (view->dom_view.cairo);
171
+
172
+ view->dom_view.cairo = view->pattern_data->old_cairo;
173
+
174
+ g_free (view->pattern_data);
175
+
176
+ if (view->pattern_stack != NULL) {
177
+ view->pattern_data = view->pattern_stack->data;
178
+ view->pattern_stack = g_slist_delete_link (view->pattern_stack, view->pattern_stack);
179
+ } else
180
+ view->pattern_data = NULL;
181
+
182
+ lsm_debug_render ("[LsmSvgView::end_pattern]");
183
+ }
184
+
185
+ static void
186
+ _set_pattern (LsmSvgView *view, cairo_pattern_t *pattern)
187
+ {
188
+ g_return_if_fail (view->pattern_data != NULL);
189
+ g_return_if_fail (view->pattern_data->pattern == NULL);
190
+
191
+ view->pattern_data->pattern = pattern;
192
+ view->last_stop_offset = 0.0;
193
+ }
194
+
195
+ void
196
+ lsm_svg_view_create_radial_gradient (LsmSvgView *view,
197
+ double cx, double cy,
198
+ double r,
199
+ double fx, double fy)
200
+ {
201
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
202
+
203
+ _set_pattern (view, cairo_pattern_create_radial (fx, fy, 0, cx, cy, r));
204
+ }
205
+
206
+ void
207
+ lsm_svg_view_create_linear_gradient (LsmSvgView *view,
208
+ double x1, double y1,
209
+ double x2, double y2)
210
+ {
211
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
212
+
213
+ _set_pattern (view, cairo_pattern_create_linear (x1, y1, x2, y2));
214
+ }
215
+
216
+ void
217
+ lsm_svg_view_add_gradient_color_stop (LsmSvgView *view, double offset)
218
+ {
219
+ const LsmSvgStyle *style;
220
+ const LsmSvgColor *color;
221
+
222
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
223
+ g_return_if_fail (view->pattern_data != NULL);
224
+ g_return_if_fail (view->pattern_data->pattern != NULL);
225
+
226
+ if (offset > 1.0)
227
+ offset = 1.0;
228
+
229
+ if (offset < view->last_stop_offset)
230
+ offset = view->last_stop_offset;
231
+ else
232
+ view->last_stop_offset = offset;
233
+
234
+ style = view->style;
235
+
236
+ lsm_debug_render ("[LsmSvgView::add_gradient_color_stop] opacity = %g", style->stop_opacity->value);
237
+
238
+ color = &style->stop_color->value;
239
+
240
+ if (color->red < 0.0 || color->blue < 0.0 || color->green < 0.0)
241
+ color = &style->color->value;
242
+
243
+ lsm_debug_render ("[LsmSvgView::add_gradient_color_stop] color = %2x%2x%2x",
244
+ (int) (255.0 * color->red),
245
+ (int) (255.0 * color->green),
246
+ (int) (255.0 * color->blue));
247
+
248
+ cairo_pattern_add_color_stop_rgba (view->pattern_data->pattern, offset,
249
+ color->red,
250
+ color->green,
251
+ color->blue,
252
+ style->stop_opacity->value * view->pattern_data->opacity);
253
+ }
254
+
255
+ gboolean
256
+ lsm_svg_view_set_gradient_properties (LsmSvgView *view,
257
+ LsmSvgSpreadMethod method,
258
+ LsmSvgPatternUnits units,
259
+ const LsmSvgMatrix *gradient_matrix)
260
+ {
261
+ cairo_matrix_t matrix;
262
+ cairo_matrix_t inv_matrix;
263
+ cairo_status_t status;
264
+
265
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), FALSE);
266
+ g_return_val_if_fail (view->pattern_data != NULL, FALSE);
267
+ g_return_val_if_fail (view->pattern_data->pattern != NULL, FALSE);
268
+
269
+ switch (method) {
270
+ case LSM_SVG_SPREAD_METHOD_REFLECT:
271
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_REFLECT);
272
+ break;
273
+ case LSM_SVG_SPREAD_METHOD_REPEAT:
274
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_REPEAT);
275
+ break;
276
+ default:
277
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_PAD);
278
+ }
279
+
280
+ if (gradient_matrix != NULL) {
281
+ cairo_matrix_init (&matrix,
282
+ gradient_matrix->a, gradient_matrix->b,
283
+ gradient_matrix->c, gradient_matrix->d,
284
+ gradient_matrix->e, gradient_matrix->f);
285
+ cairo_matrix_invert (&matrix);
286
+ } else
287
+ cairo_matrix_init_identity (&matrix);
288
+
289
+ if (units == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX &&
290
+ view->pattern_data->extents.width > 0.0 &&
291
+ view->pattern_data->extents.height > 0.0) {
292
+ cairo_matrix_scale (&matrix,
293
+ 1.0 / view->pattern_data->extents.width,
294
+ 1.0 / view->pattern_data->extents.height);
295
+ cairo_matrix_translate (&matrix,
296
+ -view->pattern_data->extents.x,
297
+ -view->pattern_data->extents.y);
298
+
299
+ }
300
+
301
+ inv_matrix = matrix;
302
+ status = cairo_matrix_invert (&inv_matrix);
303
+
304
+ if (status != CAIRO_STATUS_SUCCESS) {
305
+ lsm_debug_render ("[LsmSvgView::set_gradient_properties] Not invertible matrix");
306
+ return FALSE;
307
+ }
308
+
309
+ cairo_pattern_set_matrix (view->pattern_data->pattern, &matrix);
310
+
311
+ return TRUE;
312
+ }
313
+
314
+ gboolean
315
+ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
316
+ const LsmBox *viewport,
317
+ const LsmSvgMatrix *pattern_matrix,
318
+ LsmSvgViewSurfaceType surface_type)
319
+ {
320
+ cairo_surface_t *surface;
321
+ cairo_pattern_t *pattern;
322
+ cairo_matrix_t matrix;
323
+ cairo_matrix_t inv_matrix;
324
+ cairo_status_t status;
325
+ double x1, y1, x2, y2;
326
+ double device_width, device_height;
327
+ double x_scale, y_scale;
328
+
329
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), FALSE);
330
+ g_return_val_if_fail (viewport != NULL, FALSE);
331
+ g_return_val_if_fail (view->pattern_data != NULL, FALSE);
332
+ g_return_val_if_fail (view->dom_view.cairo == NULL, FALSE);
333
+
334
+ x1 = viewport->x;
335
+ y1 = viewport->y;
336
+ x2 = viewport->x + viewport->width;
337
+ y2 = viewport->y;
338
+
339
+ cairo_user_to_device (view->pattern_data->old_cairo, &x1, &y1);
340
+ cairo_user_to_device (view->pattern_data->old_cairo, &x2, &y2);
341
+
342
+ device_width = sqrt ((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
343
+
344
+ x2 = viewport->x;
345
+ y2 = viewport->y + viewport->height;
346
+
347
+ cairo_user_to_device (view->pattern_data->old_cairo, &x2, &y2);
348
+
349
+ device_height = sqrt ((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
350
+
351
+ if (surface_type == LSM_SVG_VIEW_SURFACE_TYPE_IMAGE) {
352
+ device_height = ceil (device_height);
353
+ device_width = ceil (device_width);
354
+ }
355
+
356
+ x_scale = device_width / viewport->width;
357
+ y_scale = device_height / viewport->height;
358
+
359
+ lsm_debug_render ("[LsmSvgView::create_surface_pattern] pattern size = %g ,%g at %g, %g (scale %g x %g)",
360
+ device_width, device_height, viewport->x, viewport->y, x_scale, y_scale);
361
+
362
+ switch (surface_type) {
363
+ case LSM_SVG_VIEW_SURFACE_TYPE_AUTO:
364
+ surface = cairo_surface_create_similar (cairo_get_target (view->pattern_data->old_cairo),
365
+ CAIRO_CONTENT_COLOR_ALPHA,
366
+ device_width, device_height);
367
+ break;
368
+ default:
369
+ case LSM_SVG_VIEW_SURFACE_TYPE_IMAGE:
370
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, device_width, device_height);
371
+ break;
372
+ }
373
+
374
+ pattern = cairo_pattern_create_for_surface (surface);
375
+ view->dom_view.cairo = cairo_create (surface);
376
+ cairo_surface_destroy (surface);
377
+
378
+ cairo_scale (view->dom_view.cairo, x_scale, y_scale);
379
+ cairo_translate (view->dom_view.cairo, -viewport->x, -viewport->y);
380
+
381
+ _set_pattern (view, pattern);
382
+
383
+ if (pattern_matrix != NULL) {
384
+ cairo_matrix_init (&matrix,
385
+ pattern_matrix->a, pattern_matrix->b,
386
+ pattern_matrix->c, pattern_matrix->d,
387
+ pattern_matrix->e + viewport->x, pattern_matrix->f + viewport->y);
388
+ cairo_matrix_scale (&matrix, 1.0 / x_scale, 1.0 / y_scale);
389
+ cairo_matrix_invert (&matrix);
390
+ } else {
391
+ cairo_matrix_init_scale (&matrix, x_scale, y_scale);
392
+ cairo_matrix_translate (&matrix, -viewport->x, -viewport->y);
393
+ }
394
+
395
+ inv_matrix = matrix;
396
+ status = cairo_matrix_invert (&inv_matrix);
397
+
398
+ if (status != CAIRO_STATUS_SUCCESS) {
399
+ lsm_debug_render ("[LsmSvgView::create_surface_pattern] Not invertible matrix");
400
+ return FALSE;
401
+ }
402
+
403
+ cairo_pattern_set_matrix (view->pattern_data->pattern, &matrix);
404
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_REPEAT);
405
+
406
+ lsm_debug_render ("[LsmSvgView::create_surface_pattern] Pattern matrix %g, %g, %g, %g, %g, %g",
407
+ matrix.xx, matrix.xy, matrix.yx, matrix.yy,
408
+ matrix.x0, matrix.y0);
409
+
410
+ return TRUE;
411
+ }
412
+
413
+ typedef enum {
414
+ LSM_SVG_VIEW_PAINT_OPERATION_FILL,
415
+ LSM_SVG_VIEW_PAINT_OPERATION_STROKE
416
+ } LsmSvgViewPaintOperation;
417
+
418
+ static void
419
+ _paint_url (LsmSvgView *view,
420
+ LsmSvgViewPathInfos *path_infos,
421
+ LsmSvgViewPaintOperation operation,
422
+ const char *url, double opacity)
423
+ {
424
+ cairo_t *cairo;
425
+ LsmSvgElement *element;
426
+ LsmBox extents;
427
+
428
+ element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document), url);
429
+ if ((!LSM_IS_SVG_RADIAL_GRADIENT_ELEMENT (element) &&
430
+ !LSM_IS_SVG_LINEAR_GRADIENT_ELEMENT (element) &&
431
+ !LSM_IS_SVG_PATTERN_ELEMENT (element)) ||
432
+ lsm_svg_view_circular_reference_check (view, element)) {
433
+
434
+ cairo_set_source_rgba (view->dom_view.cairo, 0, 0, 0, 0);
435
+
436
+ lsm_warning_render ("[LsmSvgView::_paint_url] Paint url not found: %s", url);
437
+
438
+ return;
439
+ }
440
+
441
+ lsm_debug_render ("[LsmSvgView::_paint_url] Paint using '%s'", url);
442
+
443
+ if (!path_infos->is_extents_defined) {
444
+ cairo_path_extents (view->dom_view.cairo,
445
+ &path_infos->extents.x1,
446
+ &path_infos->extents.y1,
447
+ &path_infos->extents.x2,
448
+ &path_infos->extents.y2);
449
+ path_infos->is_extents_defined = TRUE;
450
+ }
451
+
452
+ extents.x = path_infos->extents.x1;
453
+ extents.y = path_infos->extents.y1;
454
+ extents.width = path_infos->extents.x2 - extents.x;
455
+ extents.height = path_infos->extents.y2 - extents.y;
456
+
457
+ lsm_debug_render ("[LsmSvgView::_paint_url] Pattern extents x = %g, y = %g, w = %g, h = %g",
458
+ extents.x, extents.y, extents.width, extents.height);
459
+
460
+ _start_pattern (view, &extents, &extents, opacity);
461
+
462
+ lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
463
+
464
+ cairo = view->pattern_data->old_cairo;
465
+
466
+ if (view->pattern_data->pattern) {
467
+ if (view->debug_pattern && view->dom_view.cairo) {
468
+ char *filename;
469
+
470
+ filename = g_strdup_printf ("pattern-%s).png", url);
471
+ cairo_surface_write_to_png (cairo_get_target (view->dom_view.cairo), filename);
472
+ g_free (filename);
473
+ }
474
+
475
+ cairo_set_source (cairo, view->pattern_data->pattern);
476
+ } else
477
+ cairo_set_source_rgba (cairo, 0.0, 0.0, 0.0, 0.0);
478
+
479
+ _end_pattern (view);
480
+ }
481
+
482
+ static gboolean
483
+ _set_color (LsmSvgView *view,
484
+ LsmSvgViewPathInfos *path_infos,
485
+ LsmSvgViewPaintOperation operation,
486
+ const LsmSvgPaint *paint, double opacity)
487
+ {
488
+ cairo_t *cairo = view->dom_view.cairo;
489
+
490
+ switch (paint->type) {
491
+ case LSM_SVG_PAINT_TYPE_NONE:
492
+ return FALSE;
493
+ case LSM_SVG_PAINT_TYPE_RGB_COLOR:
494
+ cairo_set_source_rgba (cairo,
495
+ paint->color.red,
496
+ paint->color.green,
497
+ paint->color.blue,
498
+ opacity);
499
+ break;
500
+ case LSM_SVG_PAINT_TYPE_CURRENT_COLOR:
501
+ cairo_set_source_rgba (cairo,
502
+ view->style->color->value.red,
503
+ view->style->color->value.green,
504
+ view->style->color->value.blue,
505
+ opacity);
506
+ break;
507
+ case LSM_SVG_PAINT_TYPE_URI:
508
+ case LSM_SVG_PAINT_TYPE_URI_RGB_COLOR:
509
+ case LSM_SVG_PAINT_TYPE_URI_CURRENT_COLOR:
510
+ case LSM_SVG_PAINT_TYPE_URI_NONE:
511
+ _paint_url (view, path_infos, operation, paint->url, opacity);
512
+ break;
513
+ default:
514
+ return FALSE;
515
+ }
516
+
517
+ return TRUE;
518
+ }
519
+
520
+ static void
521
+ paint_markers (LsmSvgView *view)
522
+ {
523
+ const LsmSvgStyle *style;
524
+ LsmSvgElement *marker;
525
+ LsmSvgElement *marker_start;
526
+ LsmSvgElement *marker_mid;
527
+ LsmSvgElement *marker_end;
528
+ cairo_t *cairo;
529
+ cairo_path_t *path;
530
+ cairo_path_data_t *data;
531
+ cairo_path_data_t *next_data;
532
+ double stroke_width;
533
+ double prev_x, prev_y;
534
+ double x = 0;
535
+ double y = 0;
536
+ double next_x, next_y;
537
+ cairo_path_data_type_t type;
538
+ cairo_path_data_type_t next_type;
539
+ double angle;
540
+ int i;
541
+
542
+ style = view->style;
543
+
544
+ if ((style->marker->value == NULL || strcmp (style->marker->value, "none") == 0) &&
545
+ (style->marker_mid->value == NULL || strcmp (style->marker_mid->value, "none") == 0) &&
546
+ (style->marker_end->value == NULL || strcmp (style->marker_end->value, "none") == 0) &&
547
+ (style->marker_start->value == NULL || strcmp (style->marker_start->value, "none") == 0))
548
+ return;
549
+
550
+ cairo = view->dom_view.cairo;
551
+
552
+ marker = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
553
+ style->marker->value);
554
+ marker_start = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
555
+ style->marker_start->value);
556
+ marker_mid = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
557
+ style->marker_mid->value);
558
+ marker_end = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
559
+ style->marker_end->value);
560
+ stroke_width = lsm_svg_view_normalize_length (view, &view->style->stroke_width->length,
561
+ LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
562
+
563
+ if (marker != NULL && lsm_svg_view_circular_reference_check (view, marker))
564
+ return;
565
+ if (marker_start != NULL && lsm_svg_view_circular_reference_check (view, marker_start))
566
+ return;
567
+ if (marker_mid != NULL && lsm_svg_view_circular_reference_check (view, marker_mid))
568
+ return;
569
+ if (marker_end != NULL && lsm_svg_view_circular_reference_check (view, marker_end))
570
+ return;
571
+
572
+ if (marker_start == NULL)
573
+ marker_start = marker;
574
+ if (marker_mid == NULL)
575
+ marker_mid = marker;
576
+ if (marker_end == NULL)
577
+ marker_end = marker;
578
+
579
+ path = cairo_copy_path (cairo);
580
+ cairo_new_path (cairo);
581
+
582
+ if (path->num_data > 0) {
583
+ next_data = &path->data[0];
584
+ next_type = next_data->header.type;
585
+
586
+ if (next_type == CAIRO_PATH_CURVE_TO) {
587
+ next_x = next_data[3].point.x;
588
+ next_y = next_data[3].point.y;
589
+ } else {
590
+ next_x = next_data[1].point.x;
591
+ next_y = next_data[1].point.y;
592
+ }
593
+
594
+ for (i = 0; i < path->num_data; i += path->data[i].header.length) {
595
+ data = next_data;
596
+
597
+ prev_x = x;
598
+ prev_y = y;
599
+ x = next_x;
600
+ y = next_y;
601
+ type = next_type;
602
+
603
+ if (i + path->data[i].header.length < path->num_data) {
604
+ next_data = &path->data[i + path->data[i].header.length];
605
+ next_type = next_data->header.type;
606
+
607
+ if (next_type == CAIRO_PATH_CURVE_TO) {
608
+ next_x = next_data[3].point.x;
609
+ next_y = next_data[3].point.y;
610
+ } else {
611
+ next_x = next_data[1].point.x;
612
+ next_y = next_data[1].point.y;
613
+ }
614
+ } else {
615
+ next_data = NULL;
616
+ next_type = CAIRO_PATH_MOVE_TO;
617
+ next_x = 0.0;
618
+ next_y = 0.0;
619
+ }
620
+
621
+ if (data->header.type == CAIRO_PATH_CLOSE_PATH) {
622
+ marker = NULL;
623
+ } else if (next_data == NULL ||
624
+ next_data->header.type == CAIRO_PATH_MOVE_TO) {
625
+ marker = marker_end;
626
+ if (type == CAIRO_PATH_CURVE_TO) {
627
+ if (y != data[2].point.y ||
628
+ x != data[2].point.x)
629
+ angle = atan2 (y - data[2].point.y,
630
+ x - data[2].point.x);
631
+ else
632
+ angle = atan2 (y - data[1].point.y,
633
+ x - data[1].point.x);
634
+ } else
635
+ angle = atan2 (y - prev_y, x - prev_x);
636
+ } else if (data->header.type == CAIRO_PATH_MOVE_TO) {
637
+ marker = marker_start;
638
+ if (next_type == CAIRO_PATH_CURVE_TO) {
639
+ if (next_data[1].point.y != y ||
640
+ next_data[1].point.x != x)
641
+ angle = atan2 (next_data[1].point.y - y,
642
+ next_data[1].point.x - x);
643
+ else
644
+ angle = atan2 (next_data[2].point.y - y,
645
+ next_data[2].point.x - x);
646
+ } else
647
+ angle = atan2 (next_y - y, next_x - x);
648
+ } else {
649
+ double xdifin, ydifin, xdifout, ydifout, intot, outtot;
650
+
651
+ marker = marker_mid;
652
+
653
+ if (type == CAIRO_PATH_CURVE_TO) {
654
+ if (x != data[2].point.x ||
655
+ y != data[2].point.y) {
656
+ xdifin = x - data[2].point.x;
657
+ ydifin = y - data[2].point.y;
658
+ } else {
659
+ xdifin = x - data[1].point.x;
660
+ ydifin = y - data[1].point.y;
661
+ }
662
+ } else {
663
+ xdifin = x - prev_x;
664
+ ydifin = y - prev_y;
665
+ }
666
+ if (next_type == CAIRO_PATH_CURVE_TO) {
667
+ if (next_data[1].point.x != x ||
668
+ next_data[1].point.y != y) {
669
+ xdifout = next_data[1].point.x - x;
670
+ ydifout = next_data[1].point.y - y;
671
+ } else {
672
+ xdifout = next_data[2].point.x - x;
673
+ ydifout = next_data[2].point.y - y;
674
+ }
675
+ } else {
676
+ xdifout = next_x - x;
677
+ ydifout = next_y - y;
678
+ }
679
+
680
+ intot = sqrt (xdifin * xdifin + ydifin * ydifin);
681
+ outtot = sqrt (xdifout * xdifout + ydifout * ydifout);
682
+
683
+ xdifin /= intot;
684
+ ydifin /= intot;
685
+ xdifout /= outtot;
686
+ ydifout /= outtot;
687
+
688
+ angle = atan2 ((ydifin + ydifout) / 2, (xdifin + xdifout) / 2);
689
+ }
690
+
691
+ if (marker != NULL) {
692
+ cairo_save (cairo);
693
+ cairo_translate (cairo, x, y);
694
+ lsm_svg_marker_element_render (LSM_SVG_MARKER_ELEMENT (marker), view,
695
+ stroke_width, angle);
696
+ cairo_restore (cairo);
697
+ }
698
+ }
699
+
700
+ cairo_path_destroy (path);
701
+ }
702
+ }
703
+
704
+ static void
705
+ paint (LsmSvgView *view, LsmSvgViewPathInfos *path_infos)
706
+ {
707
+ const LsmSvgStyle *style;
708
+ LsmSvgElement *element;
709
+ cairo_t *cairo;
710
+ gboolean use_group;
711
+ double group_opacity;
712
+
713
+ element = view->element_stack->data;
714
+
715
+ g_return_if_fail (LSM_IS_SVG_ELEMENT (element));
716
+
717
+ cairo = view->dom_view.cairo;
718
+ style = view->style;
719
+
720
+ if ((style->opacity != NULL ||
721
+ style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER ) &&
722
+ style->ignore_group_opacity &&
723
+ g_strcmp0 (style->filter->value, "none") == 0) {
724
+ group_opacity = style->opacity->value;
725
+
726
+ use_group = ((style->fill->paint.type != LSM_SVG_PAINT_TYPE_NONE &&
727
+ style->stroke->paint.type != LSM_SVG_PAINT_TYPE_NONE) ||
728
+ style->stroke->paint.type == LSM_SVG_PAINT_TYPE_URI ||
729
+ style->stroke->paint.type == LSM_SVG_PAINT_TYPE_URI_RGB_COLOR ||
730
+ style->fill->paint.type == LSM_SVG_PAINT_TYPE_URI_RGB_COLOR ||
731
+ style->fill->paint.type == LSM_SVG_PAINT_TYPE_URI) &&
732
+ (group_opacity < 1.0 || style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER );
733
+ } else {
734
+ use_group = FALSE;
735
+ group_opacity = 1.0;
736
+ }
737
+
738
+ /* Instead of push_group, we should restrict to the current path bounding box */
739
+ if (use_group) {
740
+ cairo_push_group (cairo);
741
+ } else if (style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER)
742
+ lsm_cairo_set_comp_op (cairo, style->comp_op->value);
743
+
744
+ if (_set_color (view,
745
+ path_infos,
746
+ LSM_SVG_VIEW_PAINT_OPERATION_FILL,
747
+ &style->fill->paint,
748
+ style->fill_opacity->value * (use_group ? 1.0 : group_opacity))) {
749
+
750
+ if (path_infos->is_text_path) {
751
+ pango_cairo_show_layout (cairo, path_infos->pango_layout);
752
+ } else {
753
+ cairo_set_fill_rule (cairo, style->fill_rule->value == LSM_SVG_FILL_RULE_EVEN_ODD ?
754
+ CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
755
+ cairo_fill_preserve (cairo);
756
+ }
757
+ }
758
+
759
+ if (_set_color (view,
760
+ path_infos,
761
+ LSM_SVG_VIEW_PAINT_OPERATION_STROKE,
762
+ &style->stroke->paint,
763
+ style->stroke_opacity->value * (use_group ? 1.0 : group_opacity))) {
764
+ double line_width;
765
+
766
+ if (path_infos->is_text_path) {
767
+ pango_cairo_layout_path (cairo, path_infos->pango_layout);
768
+ }
769
+
770
+ switch (style->stroke_line_join->value) {
771
+ case LSM_SVG_LINE_JOIN_MITER:
772
+ cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
773
+ break;
774
+ case LSM_SVG_LINE_JOIN_ROUND:
775
+ cairo_set_line_join (cairo,CAIRO_LINE_JOIN_ROUND);
776
+ break;
777
+ default:
778
+ cairo_set_line_join (cairo,CAIRO_LINE_JOIN_BEVEL);
779
+ }
780
+
781
+ switch (style->stroke_line_cap->value) {
782
+ case LSM_SVG_LINE_CAP_BUTT:
783
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
784
+ break;
785
+ case LSM_SVG_LINE_CAP_ROUND:
786
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND);
787
+ break;
788
+ default:
789
+ cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
790
+ }
791
+
792
+ line_width = lsm_svg_view_normalize_length (view, &style->stroke_width->length,
793
+ LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
794
+
795
+ cairo_set_miter_limit (cairo, style->stroke_miter_limit->value);
796
+ cairo_set_line_width (cairo, line_width);
797
+
798
+ if (style->stroke_dash_array->value.n_dashes > 0) {
799
+ double dash_offset;
800
+ double *dashes;
801
+ unsigned int i;
802
+
803
+ dash_offset = lsm_svg_view_normalize_length (view, &style->stroke_dash_offset->length,
804
+ LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
805
+ dashes = g_new (double, style->stroke_dash_array->value.n_dashes);
806
+ for (i = 0; i < style->stroke_dash_array->value.n_dashes; i++)
807
+ dashes[i] = lsm_svg_view_normalize_length (view,
808
+ &style->stroke_dash_array->value.dashes[i],
809
+ LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
810
+
811
+ cairo_set_dash (cairo, dashes, style->stroke_dash_array->value.n_dashes, dash_offset);
812
+ g_free (dashes);
813
+ } else
814
+ cairo_set_dash (cairo, NULL, 0, 0.0);
815
+
816
+ cairo_stroke_preserve (cairo);
817
+ }
818
+
819
+ paint_markers (view);
820
+
821
+ cairo_new_path (cairo);
822
+
823
+ if (use_group) {
824
+ cairo_pop_group_to_source (cairo);
825
+ if (G_UNLIKELY (style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
826
+ lsm_cairo_set_comp_op (cairo, style->comp_op->value);
827
+ cairo_paint_with_alpha (cairo, group_opacity);
828
+ }
829
+
830
+ if (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER)
831
+ lsm_cairo_set_comp_op (cairo, LSM_SVG_COMP_OP_SRC_OVER);
832
+ }
833
+
834
+ static void
835
+ process_path (LsmSvgView *view, LsmSvgViewPathInfos *path_infos)
836
+ {
837
+ g_return_if_fail (view->style != NULL);
838
+
839
+ if (view->is_clipping) {
840
+ if (path_infos->is_text_path)
841
+ pango_cairo_layout_path (view->dom_view.cairo, path_infos->pango_layout);
842
+ cairo_set_fill_rule (view->dom_view.cairo, view->style->clip_rule->value);
843
+ } else
844
+ paint (view, path_infos);
845
+ }
846
+
847
+ void
848
+ lsm_svg_view_show_viewport (LsmSvgView*view, const LsmBox *viewport)
849
+ {
850
+ LsmSvgPaint *paint;
851
+
852
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
853
+ g_return_if_fail (viewport != NULL);
854
+
855
+ paint = &view->style->viewport_fill->paint;
856
+
857
+ switch (paint->type) {
858
+ case LSM_SVG_PAINT_TYPE_RGB_COLOR:
859
+ cairo_set_source_rgba (view->dom_view.cairo,
860
+ paint->color.red,
861
+ paint->color.green,
862
+ paint->color.blue,
863
+ view->style->viewport_fill_opacity->value);
864
+ break;
865
+ case LSM_SVG_PAINT_TYPE_CURRENT_COLOR:
866
+ cairo_set_source_rgba (view->dom_view.cairo,
867
+ view->style->color->value.red,
868
+ view->style->color->value.green,
869
+ view->style->color->value.blue,
870
+ view->style->viewport_fill_opacity->value);
871
+ default:
872
+ return;
873
+ }
874
+
875
+ cairo_rectangle (view->dom_view.cairo, viewport->x, viewport->y, 0, 0);
876
+ cairo_paint (view->dom_view.cairo);
877
+ }
878
+
879
+ /*
880
+ * Code for show_rectangle and show ellipse is inspired from
881
+ * the librsvg library (rsvg-shapes.c)
882
+ *
883
+ * Copyright (C) 2000 Eazel, Inc.
884
+ * Copyright (C) 2002 Dom Lachowicz <cinamod@hotmail.com>
885
+ *
886
+ * Authors: Raph Levien <raph@artofcode.com>,
887
+ * Dom Lachowicz <cinamod@hotmail.com>,
888
+ * Caleb Moore <c.moore@student.unsw.edu.au>
889
+ */
890
+
891
+ void
892
+ lsm_svg_view_show_rectangle (LsmSvgView *view,
893
+ double x, double y,
894
+ double w, double h,
895
+ double rx, double ry)
896
+ {
897
+ LsmSvgViewPathInfos path_infos = default_path_infos;
898
+ cairo_t *cairo;
899
+
900
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
901
+
902
+ cairo = view->dom_view.cairo;
903
+
904
+ if (rx <= 0.0 || ry <= 0.0)
905
+ cairo_rectangle (cairo, x, y, w, h);
906
+ else {
907
+
908
+ if (rx > fabs (w / 2.))
909
+ rx = fabs (w / 2.);
910
+ if (ry > fabs (h / 2.))
911
+ ry = fabs (h / 2.);
912
+
913
+ cairo_move_to (cairo, x + rx, y);
914
+ cairo_line_to (cairo, x + w - rx, y);
915
+ lsm_cairo_elliptical_arc (cairo, rx, ry, 0.0, FALSE, TRUE, x + w, y + ry);
916
+ cairo_line_to (cairo, x + w, y + h -ry);
917
+ lsm_cairo_elliptical_arc (cairo, rx, ry, 0.0, FALSE, TRUE, x + w - rx, y + h);
918
+ cairo_line_to (cairo, x + rx, y + h);
919
+ lsm_cairo_elliptical_arc (cairo, rx, ry, 0.0, FALSE, TRUE, x, y + h - ry);
920
+ cairo_line_to (cairo, x, y + ry);
921
+ lsm_cairo_elliptical_arc (cairo, rx, ry, 0.0, FALSE, TRUE, x + rx, y);
922
+ cairo_close_path (cairo);
923
+ }
924
+
925
+ process_path (view, &path_infos);
926
+ }
927
+
928
+ void
929
+ lsm_svg_view_show_circle (LsmSvgView *view, double cx, double cy, double r)
930
+ {
931
+ LsmSvgViewPathInfos path_infos = default_path_infos;
932
+
933
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
934
+
935
+ cairo_arc (view->dom_view.cairo, cx, cy, r, 0, 2 * M_PI);
936
+
937
+ process_path (view, &path_infos);
938
+ }
939
+
940
+ #define LSM_SVG_ARC_MAGIC ((double) 0.5522847498) /* 4/3 * (1-cos 45)/sin 45 = 4/3 * sqrt(2) - 1 */
941
+
942
+ void
943
+ lsm_svg_view_show_ellipse (LsmSvgView *view, double cx, double cy, double rx, double ry)
944
+ {
945
+ LsmSvgViewPathInfos path_infos = default_path_infos;
946
+ cairo_t *cairo;
947
+
948
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
949
+
950
+ if (rx <= 0 || ry <= 0)
951
+ return;
952
+
953
+ cairo = view->dom_view.cairo;
954
+
955
+ cairo_move_to (cairo, cx + rx, cy);
956
+ cairo_curve_to (cairo, cx + rx, cy + LSM_SVG_ARC_MAGIC * ry, cx + LSM_SVG_ARC_MAGIC * rx, cy + ry, cx, cy + ry);
957
+ cairo_curve_to (cairo, cx - LSM_SVG_ARC_MAGIC * rx, cy + ry, cx - rx, cy + LSM_SVG_ARC_MAGIC * ry, cx - rx, cy);
958
+ cairo_curve_to (cairo, cx - rx, cy - LSM_SVG_ARC_MAGIC * ry, cx - LSM_SVG_ARC_MAGIC * rx, cy - ry, cx, cy - ry);
959
+ cairo_curve_to (cairo, cx + LSM_SVG_ARC_MAGIC * rx, cy - ry, cx + rx, cy - LSM_SVG_ARC_MAGIC * ry, cx + rx, cy);
960
+ cairo_close_path (cairo);
961
+
962
+ process_path (view, &path_infos);
963
+ }
964
+
965
+ void
966
+ lsm_svg_view_show_path (LsmSvgView *view,
967
+ const char *d)
968
+ {
969
+ LsmSvgViewPathInfos path_infos = default_path_infos;
970
+
971
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
972
+
973
+ lsm_cairo_emit_svg_path (view->dom_view.cairo, d);
974
+
975
+ process_path (view, &path_infos);
976
+ }
977
+
978
+ void
979
+ lsm_svg_view_path_extents (LsmSvgView *view,
980
+ const char *path,
981
+ LsmExtents *extents)
982
+ {
983
+ double x1, y1, x2, y2;
984
+
985
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
986
+ g_return_if_fail (extents != NULL);
987
+
988
+ cairo_new_path (view->dom_view.cairo);
989
+ lsm_cairo_emit_svg_path (view->dom_view.cairo, path);
990
+ cairo_path_extents (view->dom_view.cairo, &x1, &y1, &x2, &y2);
991
+ cairo_new_path (view->dom_view.cairo);
992
+
993
+ extents->x1 = x1;
994
+ extents->x2 = x2;
995
+ extents->y1 = y1;
996
+ extents->y2 = y2;
997
+ }
998
+
999
+ void
1000
+ lsm_svg_view_show_line (LsmSvgView *view, double x1, double y1, double x2, double y2)
1001
+ {
1002
+ LsmSvgViewPathInfos path_infos = default_path_infos;
1003
+
1004
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1005
+
1006
+ cairo_move_to (view->dom_view.cairo, x1, y1);
1007
+ cairo_line_to (view->dom_view.cairo, x2, y2);
1008
+
1009
+ process_path (view, &path_infos);
1010
+ }
1011
+
1012
+ static void
1013
+ _show_points (LsmSvgView *view, const char *points, gboolean close_path)
1014
+ {
1015
+ LsmSvgViewPathInfos path_infos = default_path_infos;
1016
+ char *str;
1017
+ double values[2];
1018
+ unsigned int n_values;
1019
+ unsigned int count = 0;
1020
+
1021
+ if (points == NULL)
1022
+ return;
1023
+
1024
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1025
+
1026
+ str = (char *) points;
1027
+
1028
+ do {
1029
+ n_values = lsm_str_parse_double_list (&str, 2, values);
1030
+ if (n_values == 2) {
1031
+ if (count == 0)
1032
+ cairo_move_to (view->dom_view.cairo, values[0], values[1]);
1033
+ else
1034
+ cairo_line_to (view->dom_view.cairo, values[0], values[1]);
1035
+ } else if (n_values != 0) {
1036
+ cairo_new_path (view->dom_view.cairo);
1037
+ return;
1038
+ }
1039
+ count++;
1040
+ } while (n_values == 2);
1041
+
1042
+ if (close_path)
1043
+ cairo_close_path (view->dom_view.cairo);
1044
+
1045
+ process_path (view, &path_infos);
1046
+ }
1047
+
1048
+ void
1049
+ lsm_svg_view_show_polyline (LsmSvgView *view, const char *points)
1050
+ {
1051
+ _show_points (view, points, FALSE);
1052
+ }
1053
+
1054
+ void
1055
+ lsm_svg_view_show_polygon (LsmSvgView *view, const char *points)
1056
+ {
1057
+ _show_points (view, points, TRUE);
1058
+ }
1059
+
1060
+ static void
1061
+ _update_pango_layout (LsmSvgView *view, unsigned int n, char const *string, double x, double y,
1062
+ unsigned int n_dx, const double *dx,
1063
+ unsigned int n_dy, const double *dy,
1064
+ LsmSvgViewPathInfos *path_infos)
1065
+ {
1066
+ const LsmSvgStyle *style;
1067
+ PangoLayout *pango_layout;
1068
+ PangoFontDescription *font_description;
1069
+ PangoStretch font_stretch;
1070
+ PangoStyle font_style;
1071
+ PangoLayoutIter *iter;
1072
+ PangoRectangle rectangle;
1073
+ PangoAttrList *attrs;
1074
+ PangoAttribute *attr;
1075
+ int baseline;
1076
+ int i;
1077
+ double x1, y1;
1078
+
1079
+ style = view->style;
1080
+
1081
+ pango_layout = view->pango_layout;
1082
+ font_description = view->dom_view.font_description;
1083
+
1084
+ pango_font_description_set_family (font_description, style->font_family->value);
1085
+ pango_font_description_set_size (font_description, PANGO_SCALE * style->font_size_px);
1086
+ pango_font_description_set_weight (font_description, style->font_weight->value);
1087
+
1088
+ switch (style->font_stretch->value) {
1089
+ case LSM_SVG_FONT_STRETCH_ULTRA_CONDENSED:
1090
+ font_stretch = PANGO_STRETCH_ULTRA_CONDENSED;
1091
+ break;
1092
+ case LSM_SVG_FONT_STRETCH_EXTRA_CONDENSED:
1093
+ font_stretch = PANGO_STRETCH_EXTRA_CONDENSED;
1094
+ break;
1095
+ case LSM_SVG_FONT_STRETCH_CONDENSED:
1096
+ font_stretch = PANGO_STRETCH_CONDENSED;
1097
+ break;
1098
+ case LSM_SVG_FONT_STRETCH_SEMI_CONDENSED:
1099
+ font_stretch = PANGO_STRETCH_SEMI_CONDENSED;
1100
+ break;
1101
+ case LSM_SVG_FONT_STRETCH_SEMI_EXPANDED:
1102
+ font_stretch = PANGO_STRETCH_SEMI_EXPANDED;
1103
+ break;
1104
+ case LSM_SVG_FONT_STRETCH_EXPANDED:
1105
+ font_stretch = PANGO_STRETCH_EXPANDED;
1106
+ break;
1107
+ case LSM_SVG_FONT_STRETCH_EXTRA_EXPANDED:
1108
+ font_stretch = PANGO_STRETCH_EXTRA_EXPANDED;
1109
+ break;
1110
+ case LSM_SVG_FONT_STRETCH_ULTRA_EXPANDED:
1111
+ font_stretch = PANGO_STRETCH_ULTRA_EXPANDED;
1112
+ break;
1113
+ case LSM_SVG_FONT_STRETCH_NORMAL:
1114
+ default:
1115
+ font_stretch = PANGO_STRETCH_NORMAL;
1116
+ break;
1117
+ }
1118
+ pango_font_description_set_stretch (font_description, font_stretch);
1119
+
1120
+ switch (style->font_style->value) {
1121
+ case LSM_SVG_FONT_STYLE_OBLIQUE:
1122
+ font_style = PANGO_STYLE_OBLIQUE;
1123
+ break;
1124
+ case LSM_SVG_FONT_STYLE_ITALIC:
1125
+ font_style = PANGO_STYLE_ITALIC;
1126
+ break;
1127
+ case LSM_SVG_FONT_STYLE_NORMAL:
1128
+ default:
1129
+ font_style = PANGO_STYLE_NORMAL;
1130
+ break;
1131
+ }
1132
+ pango_font_description_set_style (font_description, font_style);
1133
+
1134
+ pango_layout_set_text (pango_layout, string, n);
1135
+
1136
+ attrs = pango_attr_list_new ();
1137
+ #if 0
1138
+ for (i = 0; i < n_dx; i++) {
1139
+
1140
+ attr = pango_attr_letter_spacing_new (pango_units_from_double (dx[i]));
1141
+ attr->start_index = i;
1142
+ if (i < n_dx - 1)
1143
+ attr->end_index = i + 1;
1144
+ else
1145
+ attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
1146
+
1147
+ pango_attr_list_insert (attrs, attr);
1148
+ }
1149
+ #endif
1150
+ for (i = 0; i < n_dy; i++) {
1151
+
1152
+ attr = pango_attr_rise_new (-pango_units_from_double (dy[i]));
1153
+ attr->start_index = i;
1154
+ if (i < n_dy - 1)
1155
+ attr->end_index = i + 1;
1156
+ else
1157
+ attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
1158
+
1159
+ pango_attr_list_insert (attrs, attr);
1160
+ }
1161
+ pango_layout_set_attributes (pango_layout, attrs);
1162
+ pango_attr_list_unref (attrs);
1163
+
1164
+ pango_layout_set_font_description (pango_layout, font_description);
1165
+ pango_layout_get_extents (pango_layout, &rectangle, NULL);
1166
+
1167
+ iter = pango_layout_get_iter (pango_layout);
1168
+ baseline = pango_layout_iter_get_baseline (iter);
1169
+ pango_layout_iter_free (iter);
1170
+
1171
+ x1 = x - pango_units_to_double (rectangle.x);
1172
+ y1 = y - pango_units_to_double (baseline);
1173
+
1174
+ switch (style->text_anchor->value) {
1175
+ case LSM_SVG_TEXT_ANCHOR_END:
1176
+ x1 -= pango_units_to_double (rectangle.width);
1177
+ break;
1178
+ case LSM_SVG_TEXT_ANCHOR_MIDDLE:
1179
+ x1 -= pango_units_to_double (rectangle.width) / 2.0;
1180
+ break;
1181
+ case LSM_SVG_TEXT_ANCHOR_START:
1182
+ default:
1183
+ break;
1184
+ }
1185
+
1186
+ path_infos->is_text_path = TRUE;
1187
+ path_infos->is_extents_defined = TRUE;
1188
+ path_infos->extents.x1 = x1;
1189
+ path_infos->extents.y1 = y1;
1190
+ path_infos->extents.x2 = x1 + pango_units_to_double (rectangle.width);
1191
+ path_infos->extents.y2 = y1 + pango_units_to_double (rectangle.height);
1192
+ path_infos->pango_layout = pango_layout;
1193
+ }
1194
+
1195
+ static gboolean
1196
+ _lock_pango_layout (LsmSvgView *view)
1197
+ {
1198
+ /* A text may be painted with a text based pattern. In this case,
1199
+ * we take care to create a new pango layout if the current one is in use. */
1200
+ if (view->is_pango_layout_in_use) {
1201
+ PangoContext *pango_context;
1202
+
1203
+ pango_context = pango_layout_get_context (view->pango_layout);
1204
+ view->pango_layout_stack = g_slist_prepend (view->pango_layout_stack, view->pango_layout);
1205
+ view->pango_layout = pango_layout_new (pango_context);
1206
+
1207
+ lsm_debug_render ("[LsmSvgView::_lock_pango_layout] Create a new pango layout");
1208
+
1209
+ return TRUE;
1210
+ }
1211
+
1212
+ view->is_pango_layout_in_use = TRUE;
1213
+
1214
+ return FALSE;
1215
+ }
1216
+
1217
+ static void
1218
+ _unlock_pango_layout (LsmSvgView *view, gboolean need_pop)
1219
+ {
1220
+
1221
+ if (need_pop) {
1222
+ lsm_debug_render ("[LsmSvgView::_unlock_pango_layout] Free the child pango layout");
1223
+
1224
+ if (view->pango_layout != NULL) {
1225
+ g_object_unref (view->pango_layout);
1226
+
1227
+ view->pango_layout = view->pango_layout_stack->data;
1228
+ view->pango_layout_stack = g_slist_delete_link (view->pango_layout_stack,
1229
+ view->pango_layout_stack);
1230
+ } else
1231
+ g_warning ("[LsmSvgView::_unlock_pango_layout] Pango layout stack empty");
1232
+ }
1233
+
1234
+ view->is_pango_layout_in_use = FALSE;
1235
+ }
1236
+
1237
+ static void
1238
+ _show_text (LsmSvgView *view,
1239
+ unsigned int n, char const *string,
1240
+ unsigned int n_x, double *x, unsigned int n_y, double *y,
1241
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
1242
+ {
1243
+ LsmSvgViewPathInfos path_infos = default_path_infos;
1244
+ PangoRectangle extents;
1245
+ PangoLayoutIter *layout_iter;
1246
+ const LsmSvgStyle *style;
1247
+ gboolean need_pop;
1248
+ double x_text;
1249
+ double y_text;
1250
+ double x_end, y_end;
1251
+ double baseline;
1252
+ cairo_t *cairo;
1253
+
1254
+
1255
+ cairo = view->dom_view.cairo;
1256
+
1257
+ style = view->style;
1258
+
1259
+ lsm_debug_render ("[LsmSvgView::show_text] Show '%s' at %g,%g (%g px)", string, x, y, style->font_size_px);
1260
+
1261
+ need_pop = _lock_pango_layout (view);
1262
+
1263
+ cairo_get_current_point (cairo, &x_text, &y_text);
1264
+ if (x != NULL)
1265
+ x_text = x[0];
1266
+ if (y != NULL)
1267
+ y_text = y[0];
1268
+
1269
+
1270
+ _update_pango_layout (view, n, string, x_text, y_text, n_dx, dx, n_dy, dy, &path_infos);
1271
+
1272
+ if (style->writing_mode->value == LSM_SVG_WRITING_MODE_TB ||
1273
+ style->writing_mode->value == LSM_SVG_WRITING_MODE_TB_RL) {
1274
+
1275
+ cairo_save (cairo);
1276
+ cairo_rotate (cairo, M_PI / 2.0);
1277
+ cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
1278
+
1279
+ process_path (view, &path_infos);
1280
+
1281
+ cairo_restore (cairo);
1282
+ } else {
1283
+ cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
1284
+ process_path (view, &path_infos);
1285
+ }
1286
+
1287
+ layout_iter = pango_layout_get_iter (view->pango_layout);
1288
+ pango_layout_iter_get_line_extents (layout_iter, NULL, &extents);
1289
+ baseline = pango_units_to_double (pango_layout_iter_get_baseline (layout_iter));
1290
+ pango_layout_iter_free (layout_iter);
1291
+
1292
+ x_end = pango_units_to_double (extents.x + extents.width) + path_infos.extents.x1;
1293
+ y_end = pango_units_to_double (extents.y) + baseline + path_infos.extents.y1;
1294
+
1295
+ if (view->debug_text) {
1296
+ double x1, y1;
1297
+
1298
+ lsm_debug_render ("[LsmSvgView::_show_text] Logical extents %gx%g at %g,%g\n",
1299
+ pango_units_to_double (extents.width),
1300
+ pango_units_to_double (extents.height),
1301
+ pango_units_to_double (extents.x),
1302
+ pango_units_to_double (extents.y));
1303
+
1304
+ lsm_debug_render ("[LsmSvgView::_show_text] End point is %g, %g\n", x_end, y_end);
1305
+ lsm_debug_render ("[LsmSvgView::_show_text] Baseline = %g\n", baseline);
1306
+
1307
+ x1 = 1;
1308
+ y1 = 1;
1309
+ cairo_device_to_user_distance (cairo, &x1, &y1);
1310
+
1311
+ cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
1312
+ cairo_set_line_width (cairo, x1);
1313
+ cairo_rectangle (cairo, path_infos.extents.x1, path_infos.extents.y1,
1314
+ pango_units_to_double (extents.x + extents.width),
1315
+ pango_units_to_double (extents.y + extents.height));
1316
+ cairo_stroke (cairo);
1317
+ cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
1318
+ cairo_arc (cairo, x_end, y_end, 4.0 * x1, 0.0, 2.0 * M_PI);
1319
+ cairo_arc (cairo, path_infos.extents.x1, path_infos.extents.y1, 4.0 * x1, 0.0, 2.0 * M_PI);
1320
+ cairo_fill (cairo);
1321
+ }
1322
+
1323
+ cairo_move_to (cairo, x_end, y_end);
1324
+
1325
+ _unlock_pango_layout (view, need_pop);
1326
+ }
1327
+
1328
+ void
1329
+ lsm_svg_view_start_text (LsmSvgView *view)
1330
+ {
1331
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1332
+
1333
+ cairo_move_to (view->dom_view.cairo, 0, 0);
1334
+ }
1335
+
1336
+ void
1337
+ lsm_svg_view_end_text (LsmSvgView *view)
1338
+ {
1339
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1340
+
1341
+ cairo_new_path (view->dom_view.cairo);
1342
+ }
1343
+
1344
+ void
1345
+ lsm_svg_view_show_text (LsmSvgView *view, char const *string,
1346
+ unsigned int n_x, double *x, unsigned int n_y, double *y,
1347
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
1348
+ {
1349
+ unsigned int n, i;
1350
+ char *iter = (char *) string;
1351
+
1352
+ if (string == NULL || string[0] == '\0')
1353
+ return;
1354
+
1355
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1356
+ g_return_if_fail (n_x > 0 || x == NULL);
1357
+ g_return_if_fail (n_y > 0 || y == NULL);
1358
+ g_return_if_fail (n_dx > 0 || dx == NULL);
1359
+ g_return_if_fail (n_dy > 0 || dy == NULL);
1360
+
1361
+ n = MAX (n_x, n_y);
1362
+ if (n <= 1) {
1363
+ _show_text (view, strlen (string), string, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
1364
+ return;
1365
+ }
1366
+
1367
+ for (i = 0; (i < n - 1) && iter[0] != '\0'; i++) {
1368
+ char *next_char;
1369
+
1370
+ next_char = g_utf8_next_char (iter);
1371
+ _show_text (view, next_char - iter, iter,
1372
+ i < n_x ? n_x - i : 0,
1373
+ i < n_x ? &x[i] : NULL,
1374
+ i < n_y ? n_y - i : 0,
1375
+ i < n_y ? &y[i] : NULL,
1376
+ i < n_dx ? n_dx - i : 0,
1377
+ i < n_dx ? &dx[i] : NULL,
1378
+ i < n_dy ? n_dy - i : 0,
1379
+ i < n_dy ? &dy[i] : NULL);
1380
+ iter = next_char;
1381
+ }
1382
+
1383
+ if (iter[0] != '\0')
1384
+ _show_text (view, strlen (iter), iter,
1385
+ i < n_x ? n_x - i : 0,
1386
+ i < n_x ? &x[i] : NULL,
1387
+ i < n_y ? n_y - i : 0,
1388
+ i < n_y ? &y[i] : NULL,
1389
+ i < n_dx ? n_dx - i : 0,
1390
+ i < n_dx ? &dx[i] : NULL,
1391
+ i < n_dy ? n_dy - i : 0,
1392
+ i < n_dy ? &dy[i] : NULL);
1393
+ }
1394
+
1395
+ void
1396
+ lsm_svg_view_text_extents (LsmSvgView *view, char const *string,
1397
+ double x, double y,
1398
+ unsigned int n_dx, double *dx, unsigned int n_dy, double *dy,
1399
+ LsmExtents *extents)
1400
+ {
1401
+ LsmSvgViewPathInfos path_infos = default_path_infos;
1402
+ gboolean need_pop;
1403
+
1404
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1405
+ g_return_if_fail (extents != NULL);
1406
+
1407
+ if (string == NULL ||
1408
+ string[0] == '\0') {
1409
+ extents->x1 = 0;
1410
+ extents->y1 = 0;
1411
+ extents->y1 = 0;
1412
+ extents->y2 = 0;
1413
+ }
1414
+
1415
+ need_pop = _lock_pango_layout (view);
1416
+
1417
+ _update_pango_layout (view, strlen (string), string, x, y, n_dx, dx, n_dy, dy, &path_infos);
1418
+
1419
+ _unlock_pango_layout (view, need_pop);
1420
+
1421
+ *extents = path_infos.extents;
1422
+ }
1423
+
1424
+ void
1425
+ lsm_svg_view_show_pixbuf (LsmSvgView *view, GdkPixbuf *pixbuf)
1426
+ {
1427
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1428
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1429
+
1430
+ lsm_cairo_set_source_pixbuf (view->dom_view.cairo, pixbuf, 0, 0);
1431
+ cairo_paint (view->dom_view.cairo);
1432
+ }
1433
+
1434
+ void
1435
+ lsm_svg_view_push_viewbox (LsmSvgView *view, const LsmBox *viewbox)
1436
+ {
1437
+ LsmSvgViewbox *svg_viewbox;
1438
+
1439
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1440
+
1441
+ lsm_debug_render ("[LsmSvgView::push_viewbox] viewbox = %g, %g, %g, %g",
1442
+ viewbox->x, viewbox->y, viewbox->width, viewbox->height);
1443
+
1444
+ svg_viewbox = lsm_svg_viewbox_new (view->resolution_ppi, viewbox);
1445
+
1446
+ view->viewbox_stack = g_slist_prepend (view->viewbox_stack, svg_viewbox);
1447
+ }
1448
+
1449
+ void
1450
+ lsm_svg_view_pop_viewbox (LsmSvgView *view)
1451
+ {
1452
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1453
+ g_return_if_fail (view->viewbox_stack != NULL);
1454
+
1455
+ lsm_debug_render ("[LsmSvgView::pop_viewbox]");
1456
+
1457
+ lsm_svg_viewbox_free (view->viewbox_stack->data);
1458
+ view->viewbox_stack = g_slist_delete_link (view->viewbox_stack, view->viewbox_stack);
1459
+ }
1460
+
1461
+ static const LsmBox *
1462
+ _compute_viewbox_scale (const LsmBox *viewport, const LsmBox *viewbox,
1463
+ const LsmSvgPreserveAspectRatio *aspect_ratio,
1464
+ double *x_offset, double *y_offset,
1465
+ double *x_scale, double *y_scale)
1466
+ {
1467
+ if (viewbox != NULL) {
1468
+ double x, y;
1469
+ double x_ratio;
1470
+ double y_ratio;
1471
+
1472
+ x_ratio = viewbox->width > 0.0 ? viewport->width / viewbox->width : 0.0;
1473
+ y_ratio = viewbox->height > 0.0 ? viewport->height / viewbox->height : 0.0;
1474
+
1475
+ if (aspect_ratio != NULL && aspect_ratio->align > LSM_SVG_ALIGN_NONE) {
1476
+ if (aspect_ratio->meet_or_slice == LSM_SVG_MEET_OR_SLICE_MEET) {
1477
+ *x_scale = MIN (x_ratio, y_ratio);
1478
+ *y_scale = *x_scale;
1479
+ } else {
1480
+ *x_scale = MAX (x_ratio, y_ratio);
1481
+ *y_scale = *x_scale;
1482
+ }
1483
+
1484
+ x = -viewbox->x * *x_scale;
1485
+ y = -viewbox->y * *y_scale;
1486
+
1487
+ switch (aspect_ratio->align) {
1488
+ case LSM_SVG_ALIGN_X_MIN_Y_MIN:
1489
+ break;
1490
+ case LSM_SVG_ALIGN_X_MIN_Y_MID:
1491
+ y += (viewport->height- viewbox->height * *y_scale) * 0.5;
1492
+ break;
1493
+ case LSM_SVG_ALIGN_X_MIN_Y_MAX:
1494
+ y += (viewport->height - viewbox->height * *y_scale);
1495
+ break;
1496
+ case LSM_SVG_ALIGN_X_MID_Y_MIN:
1497
+ x += (viewport->width - viewbox->width * *x_scale) * 0.5;
1498
+ break;
1499
+ case LSM_SVG_ALIGN_X_MID_Y_MID:
1500
+ x += (viewport->width - viewbox->width * *x_scale) * 0.5;
1501
+ y += (viewport->height- viewbox->height * *y_scale) * 0.5;
1502
+ break;
1503
+ case LSM_SVG_ALIGN_X_MID_Y_MAX:
1504
+ x += (viewport->width - viewbox->width * *x_scale) * 0.5;
1505
+ y += (viewport->height - viewbox->height * *y_scale);
1506
+ break;
1507
+ case LSM_SVG_ALIGN_X_MAX_Y_MIN:
1508
+ x += (viewport->width - viewbox->width * *x_scale);
1509
+ break;
1510
+ case LSM_SVG_ALIGN_X_MAX_Y_MID:
1511
+ x += (viewport->width - viewbox->width * *x_scale);
1512
+ y += (viewport->height- viewbox->height * *y_scale) * 0.5;
1513
+ break;
1514
+ case LSM_SVG_ALIGN_X_MAX_Y_MAX:
1515
+ x += (viewport->width - viewbox->width * *x_scale);
1516
+ y += (viewport->height - viewbox->height * *y_scale);
1517
+ break;
1518
+ default:
1519
+ break;
1520
+ }
1521
+
1522
+ *x_offset = x;
1523
+ *y_offset = y;
1524
+
1525
+ } else {
1526
+ *x_scale = x_ratio;
1527
+ *y_scale = y_ratio;
1528
+
1529
+ *x_offset = -viewbox->x * *x_scale;
1530
+ *y_offset = -viewbox->y * *y_scale;
1531
+ }
1532
+
1533
+ lsm_debug_render ("[LsmSvgView::_compute_viewbox_scale] scale = %g, %g", *x_scale, *y_scale);
1534
+
1535
+ return viewbox;
1536
+ }
1537
+
1538
+ *x_scale = *y_scale = 1.0;
1539
+ *x_offset = 0.0;
1540
+ *y_offset = 0.0;
1541
+
1542
+ return viewport;
1543
+ }
1544
+
1545
+ void
1546
+ lsm_svg_view_push_viewport (LsmSvgView *view, const LsmBox *viewport, const LsmBox *viewbox,
1547
+ const LsmSvgPreserveAspectRatio *aspect_ratio,
1548
+ LsmSvgOverflow overflow)
1549
+ {
1550
+ cairo_t *cairo;
1551
+ const LsmBox *actual_viewbox;
1552
+ double x_offset, y_offset;
1553
+ double x_scale, y_scale;
1554
+
1555
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1556
+ g_return_if_fail (viewport != NULL);
1557
+
1558
+ actual_viewbox = _compute_viewbox_scale (viewport, viewbox, aspect_ratio,
1559
+ &x_offset, &y_offset, &x_scale, &y_scale);
1560
+ lsm_svg_view_push_viewbox (view, actual_viewbox);
1561
+
1562
+ cairo = view->dom_view.cairo;
1563
+
1564
+ cairo_save (cairo);
1565
+
1566
+ if (lsm_debug_check (&lsm_debug_category_viewport, LSM_DEBUG_LEVEL_LOG)) {
1567
+ cairo_save (cairo);
1568
+ cairo_set_line_width (cairo, 1.0);
1569
+ cairo_set_source_rgb (cairo, 0.0, 0.0, 0.0);
1570
+ cairo_rectangle (cairo, viewport->x, viewport->y, viewport->width, viewport->height);
1571
+ cairo_stroke (cairo);
1572
+ cairo_restore (cairo);
1573
+ }
1574
+
1575
+ if (overflow == LSM_SVG_OVERFLOW_HIDDEN) {
1576
+ cairo_rectangle (cairo, viewport->x, viewport->y, viewport->width, viewport->height);
1577
+ cairo_clip (cairo);
1578
+ }
1579
+
1580
+ cairo_translate (cairo, viewport->x + x_offset, viewport->y + y_offset);
1581
+ cairo_scale (cairo, x_scale, y_scale);
1582
+ }
1583
+
1584
+ void
1585
+ lsm_svg_view_pop_viewport (LsmSvgView *view)
1586
+ {
1587
+ cairo_restore (view->dom_view.cairo);
1588
+
1589
+ lsm_svg_view_pop_viewbox (view);
1590
+ }
1591
+
1592
+ void
1593
+ lsm_svg_view_viewbox_to_viewport (LsmSvgView *view, const LsmBox *viewport, const LsmBox *viewbox,
1594
+ const LsmSvgPreserveAspectRatio *aspect_ratio,
1595
+ double *x, double *y)
1596
+ {
1597
+ double x_offset, y_offset;
1598
+ double x_scale, y_scale;
1599
+
1600
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1601
+ g_return_if_fail (viewport != NULL);
1602
+
1603
+ _compute_viewbox_scale (viewport, viewbox, aspect_ratio,
1604
+ &x_offset, &y_offset, &x_scale, &y_scale);
1605
+
1606
+ if (x != NULL)
1607
+ *x = *x * x_scale + x_offset;
1608
+
1609
+ if (y != NULL)
1610
+ *y = *y * y_scale + y_offset;
1611
+ }
1612
+
1613
+ gboolean
1614
+ lsm_svg_view_push_matrix (LsmSvgView *view, const LsmSvgMatrix *matrix)
1615
+ {
1616
+ cairo_matrix_t cr_matrix;
1617
+ cairo_matrix_t cr_inv_matrix;
1618
+ cairo_matrix_t *ctm;
1619
+ cairo_status_t status;
1620
+
1621
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), FALSE);
1622
+
1623
+ ctm = g_new (cairo_matrix_t, 1);
1624
+ cairo_get_matrix (view->dom_view.cairo, ctm);
1625
+
1626
+ view->matrix_stack = g_slist_prepend (view->matrix_stack, ctm);
1627
+
1628
+ lsm_debug_render ("[LsmSvgView::push_matrix] New transform %g, %g, %g, %g, %g, %g",
1629
+ matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
1630
+
1631
+ cairo_matrix_init (&cr_matrix, matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
1632
+ cr_inv_matrix = cr_matrix;
1633
+ status = cairo_matrix_invert (&cr_inv_matrix) == CAIRO_STATUS_SUCCESS;
1634
+
1635
+ if (status == CAIRO_STATUS_SUCCESS) {
1636
+ lsm_debug_render ("[LsmSvgView::push_matrix] Not invertible matrix");
1637
+ return FALSE;
1638
+ }
1639
+
1640
+ cairo_transform (view->dom_view.cairo, &cr_matrix);
1641
+
1642
+ {
1643
+ cairo_matrix_t current_ctm;
1644
+ cairo_get_matrix (view->dom_view.cairo, &current_ctm);
1645
+
1646
+ lsm_debug_render ("[LsmSvgView::push_matrix] Current ctm %g, %g, %g, %g, %g, %g",
1647
+ current_ctm.xx, current_ctm.xy, current_ctm.yx, current_ctm.yy,
1648
+ current_ctm.x0, current_ctm.y0);
1649
+ }
1650
+
1651
+ return TRUE;
1652
+ }
1653
+
1654
+ void
1655
+ lsm_svg_view_pop_matrix (LsmSvgView *view)
1656
+ {
1657
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1658
+
1659
+ if (view->matrix_stack != NULL) {
1660
+ cairo_matrix_t *ctm;
1661
+
1662
+ ctm = view->matrix_stack->data;
1663
+
1664
+ cairo_set_matrix (view->dom_view.cairo, ctm);
1665
+
1666
+ lsm_debug_render ("[LsmSvgView::pop_matrix] Restore ctm %g, %g, %g, %g, %g, %g",
1667
+ ctm->xx, ctm->xy, ctm->yx, ctm->yy,
1668
+ ctm->x0, ctm->y0);
1669
+
1670
+ g_free (ctm);
1671
+ view->matrix_stack = g_slist_delete_link (view->matrix_stack, view->matrix_stack);
1672
+ }
1673
+ }
1674
+
1675
+ static void
1676
+ lsm_svg_view_push_clip (LsmSvgView *view)
1677
+ {
1678
+ LsmSvgElement *element;
1679
+ LsmExtents extents;
1680
+ char *url;
1681
+
1682
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1683
+ g_return_if_fail (!view->is_clipping);
1684
+
1685
+ lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
1686
+
1687
+ url = view->style->clip_path->value;
1688
+
1689
+ lsm_debug_render ("[LsmSvgView::push_clip] Using '%s'", url);
1690
+
1691
+ cairo_save (view->dom_view.cairo);
1692
+
1693
+ view->clip_extents.x = extents.x1;
1694
+ view->clip_extents.y = extents.y1;
1695
+ view->clip_extents.width = extents.x2 - extents.x1;
1696
+ view->clip_extents.height = extents.y2 - extents.y1;
1697
+
1698
+ lsm_debug_render ("[LsmSvgView::push_clip] x=%g y=%g w=%g h=%g",
1699
+ view->clip_extents.x,
1700
+ view->clip_extents.y,
1701
+ view->clip_extents.width,
1702
+ view->clip_extents.height);
1703
+
1704
+ element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document), url);
1705
+ if (LSM_IS_SVG_CLIP_PATH_ELEMENT (element) &&
1706
+ !lsm_svg_view_circular_reference_check (view, element)) {
1707
+ view->is_clipping = TRUE;
1708
+ lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
1709
+ cairo_clip (view->dom_view.cairo);
1710
+ view->is_clipping = FALSE;
1711
+ } else
1712
+ lsm_warning_render ("[LsmSvgView::push_clip] Clip path not found: %s", view->style->clip_path->value);
1713
+ }
1714
+
1715
+ static void
1716
+ lsm_svg_view_pop_clip (LsmSvgView *view)
1717
+ {
1718
+ lsm_debug_render ("[LsmSvgView::pop_clip");
1719
+
1720
+ cairo_restore (view->dom_view.cairo);
1721
+ }
1722
+
1723
+ static void
1724
+ lsm_svg_view_push_mask (LsmSvgView *view)
1725
+ {
1726
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1727
+
1728
+ cairo_push_group (view->dom_view.cairo);
1729
+ }
1730
+
1731
+ static void
1732
+ lsm_svg_view_pop_mask (LsmSvgView *view)
1733
+ {
1734
+ LsmSvgElement *mask_element;
1735
+
1736
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1737
+
1738
+ mask_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
1739
+ view->style->mask->value);
1740
+
1741
+ if (LSM_IS_SVG_MASK_ELEMENT (mask_element) &&
1742
+ !lsm_svg_view_circular_reference_check (view, mask_element)) {
1743
+ LsmExtents extents;
1744
+ LsmBox mask_extents;
1745
+ cairo_t *cairo;
1746
+
1747
+ lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
1748
+
1749
+ mask_extents.x = extents.x1;
1750
+ mask_extents.y = extents.y1;
1751
+ mask_extents.width = extents.x2 - extents.x1;
1752
+ mask_extents.height = extents.y2 - extents.y1;
1753
+
1754
+ cairo = view->dom_view.cairo;
1755
+
1756
+ _start_pattern (view, &mask_extents, &mask_extents, 1.0);
1757
+
1758
+ lsm_svg_element_force_render (LSM_SVG_ELEMENT (mask_element), view);
1759
+
1760
+ cairo_pop_group_to_source (cairo);
1761
+ if (view->pattern_data->pattern != NULL) {
1762
+ cairo_surface_t *surface;
1763
+ int width, height, row, i, stride;
1764
+ unsigned char *pixels;
1765
+
1766
+ cairo_pattern_get_surface (view->pattern_data->pattern, &surface);
1767
+ pixels = cairo_image_surface_get_data (surface);
1768
+ height = cairo_image_surface_get_height (surface);
1769
+ width = cairo_image_surface_get_width (surface);
1770
+ stride = cairo_image_surface_get_stride (surface);
1771
+
1772
+ for (row = 0; row < height; row++) {
1773
+ guint8 *row_data = (pixels + (row * stride));
1774
+ for (i = 0; i < width; i++) {
1775
+ guint32 *pixel = (guint32 *) row_data + i;
1776
+ *pixel = ((((*pixel & 0x00ff0000) >> 16) * 13817 +
1777
+ ((*pixel & 0x0000ff00) >> 8) * 46518 +
1778
+ ((*pixel & 0x000000ff)) * 4688) * 0xff
1779
+ /* * opacity */);
1780
+ }
1781
+ }
1782
+
1783
+ cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_NONE);
1784
+
1785
+ if (view->debug_mask && view->dom_view.cairo != NULL) {
1786
+ char *filename;
1787
+
1788
+ filename = g_strdup_printf ("mask-%s.png", view->style->mask->value);
1789
+ cairo_surface_write_to_png (cairo_get_target (view->dom_view.cairo), filename);
1790
+ g_free (filename);
1791
+ }
1792
+
1793
+ cairo_mask (cairo, view->pattern_data->pattern);
1794
+ } else {
1795
+ cairo_paint (cairo);
1796
+ }
1797
+
1798
+ _end_pattern (view);
1799
+ } else {
1800
+ lsm_warning_render ("[LsmSvgView::pop_mask] Mask url nout found: %s", view->style->mask->value);
1801
+
1802
+ cairo_pop_group_to_source (view->dom_view.cairo);
1803
+ cairo_paint (view->dom_view.cairo);
1804
+ }
1805
+ }
1806
+
1807
+ static void
1808
+ lsm_svg_view_push_filter (LsmSvgView *view)
1809
+ {
1810
+ LsmExtents extents;
1811
+ LsmBox object_extents;
1812
+ LsmBox effect_viewport;
1813
+ LsmSvgElement *filter_element;
1814
+ gboolean success;
1815
+
1816
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1817
+ g_return_if_fail (view->element_stack != NULL);
1818
+
1819
+ lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
1820
+
1821
+ object_extents.x = extents.x1;
1822
+ object_extents.y = extents.y1;
1823
+ object_extents.width = extents.x2 - extents.x1;
1824
+ object_extents.height = extents.y2 - extents.y1;
1825
+
1826
+ filter_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
1827
+ view->style->filter->value);
1828
+
1829
+ if (LSM_IS_SVG_FILTER_ELEMENT (filter_element)) {
1830
+ effect_viewport = lsm_svg_filter_element_get_effect_viewport (LSM_SVG_FILTER_ELEMENT (filter_element),
1831
+ &object_extents, view);
1832
+
1833
+ _start_pattern (view, &effect_viewport, &object_extents,
1834
+ view->style->opacity != NULL ? view->style->opacity->value : 1.0);
1835
+
1836
+ success = lsm_svg_view_create_surface_pattern (view,
1837
+ &effect_viewport,
1838
+ NULL,
1839
+ LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
1840
+ } else {
1841
+ lsm_warning_render ("LsmSvgView::push_filter] Filter not found: %s", view->style->filter->value);
1842
+
1843
+ _start_pattern (view, &object_extents, &object_extents, 0.0);
1844
+
1845
+ success = lsm_svg_view_create_surface_pattern (view,
1846
+ &object_extents,
1847
+ NULL,
1848
+ LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
1849
+ }
1850
+
1851
+ if (!success)
1852
+ lsm_warning_render ("LsmSvgView::push_filter] Failed to create subsurface");
1853
+ }
1854
+
1855
+ static void
1856
+ lsm_svg_view_pop_filter (LsmSvgView *view)
1857
+ {
1858
+ LsmSvgElement *filter_element;
1859
+ LsmSvgFilterSurface *filter_surface;
1860
+ cairo_surface_t *surface;
1861
+ GSList *iter;
1862
+
1863
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
1864
+
1865
+ filter_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
1866
+ view->style->filter->value);
1867
+
1868
+ if (LSM_IS_SVG_FILTER_ELEMENT (filter_element) &&
1869
+ view->pattern_data->pattern != NULL) {
1870
+ cairo_matrix_t matrix;
1871
+ LsmBox subregion;
1872
+
1873
+ view->filter_surfaces = NULL;
1874
+
1875
+ cairo_pattern_get_surface (view->pattern_data->pattern, &surface);
1876
+
1877
+ subregion.x = 0;
1878
+ subregion.y = 0;
1879
+ subregion.width = cairo_image_surface_get_width (surface);
1880
+ subregion.height = cairo_image_surface_get_height (surface);
1881
+
1882
+ filter_surface = lsm_svg_filter_surface_new_with_content ("SourceGraphic", surface, &subregion);
1883
+ cairo_pattern_get_matrix (view->pattern_data->pattern, &matrix);
1884
+
1885
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, filter_surface);
1886
+
1887
+ lsm_svg_element_force_render (filter_element, view);
1888
+
1889
+ if (view->debug_filter) {
1890
+ GSList *iter;
1891
+ char *filename;
1892
+ static int count = 0;
1893
+
1894
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next) {
1895
+ LsmSvgFilterSurface *surface = iter->data;
1896
+
1897
+ filename = g_strdup_printf ("filter-%04d-%s-%s.png", count++,
1898
+ view->style->filter->value,
1899
+ lsm_svg_filter_surface_get_name (surface));
1900
+ cairo_surface_write_to_png (lsm_svg_filter_surface_get_cairo_surface (surface), filename);
1901
+ g_free (filename);
1902
+ }
1903
+ }
1904
+
1905
+ if (view->filter_surfaces->next != NULL) {
1906
+ cairo_pattern_t *pattern;
1907
+ cairo_surface_t *surface;
1908
+
1909
+ surface = lsm_svg_filter_surface_get_cairo_surface (view->filter_surfaces->data);
1910
+ pattern = cairo_pattern_create_for_surface (surface);
1911
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
1912
+ cairo_pattern_set_matrix (pattern, &matrix);
1913
+ cairo_set_source (view->pattern_data->old_cairo, pattern);
1914
+ cairo_pattern_destroy (pattern);
1915
+ cairo_paint_with_alpha (view->pattern_data->old_cairo, view->style->opacity->value);
1916
+ }
1917
+
1918
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next)
1919
+ lsm_svg_filter_surface_unref (iter->data);
1920
+ g_slist_free (view->filter_surfaces);
1921
+ view->filter_surfaces = NULL;
1922
+ }
1923
+
1924
+ _end_pattern (view);
1925
+ }
1926
+
1927
+ static LsmSvgFilterSurface *
1928
+ _get_filter_surface (LsmSvgView *view, const char *input)
1929
+ {
1930
+ GSList *iter;
1931
+ LsmSvgFilterSurface *source_surface = NULL;
1932
+
1933
+ if (input == NULL)
1934
+ return view->filter_surfaces->data;
1935
+
1936
+ for (iter = view->filter_surfaces; iter != NULL; iter = iter->next) {
1937
+ LsmSvgFilterSurface *surface = iter->data;
1938
+
1939
+ if (g_strcmp0 (input, lsm_svg_filter_surface_get_name (surface)) == 0)
1940
+ return surface;
1941
+
1942
+ source_surface = surface;
1943
+ }
1944
+
1945
+ if (g_strcmp0 (input, "SourceAlpha") == 0 && source_surface != NULL) {
1946
+ LsmSvgFilterSurface *surface;
1947
+
1948
+ surface = lsm_svg_filter_surface_new_similar ("SourceAlpha", source_surface, NULL);
1949
+ lsm_svg_filter_surface_alpha (source_surface, surface);
1950
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, surface);
1951
+
1952
+ return surface;
1953
+ } else if (g_strcmp0 (input, "BackgroundImage") == 0) {
1954
+ LsmSvgFilterSurface *surface;
1955
+ LsmSvgViewBackground *background;
1956
+ gboolean background_processing = FALSE;
1957
+ cairo_matrix_t matrix;
1958
+ cairo_matrix_t pattern_matrix;
1959
+ cairo_t *cairo;
1960
+ GList *iter;
1961
+
1962
+ for (iter = view->background_stack; iter != NULL; iter = iter->next) {
1963
+ background = iter->data;
1964
+
1965
+ if (background->enable_background) {
1966
+ background_processing = TRUE;
1967
+ break;
1968
+ }
1969
+ }
1970
+
1971
+ if (!background_processing) {
1972
+ lsm_debug_render ("[LsmSvgView::_get_filter_surface] Background processing not enabled");
1973
+ return NULL;
1974
+ }
1975
+
1976
+ surface = lsm_svg_filter_surface_new_similar ("BackgroundImage", source_surface, NULL);
1977
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, surface);
1978
+
1979
+ cairo_get_matrix (view->pattern_data->old_cairo, &matrix);
1980
+ cairo_pattern_get_matrix (view->pattern_data->pattern, &pattern_matrix);
1981
+
1982
+ cairo_matrix_invert (&matrix);
1983
+ cairo_matrix_multiply (&matrix, &matrix, &pattern_matrix);
1984
+
1985
+ lsm_debug_render ("[LsmSvgView::_get_filter_surface] Background image matrix %g, %g, %g, %g, %g, %g",
1986
+ matrix.xx, matrix.xy, matrix.yx, matrix.yy,
1987
+ matrix.x0, matrix.y0);
1988
+
1989
+ cairo = cairo_create (lsm_svg_filter_surface_get_cairo_surface (surface));
1990
+ cairo_set_matrix (cairo, &matrix);
1991
+
1992
+ for (; iter != NULL; iter = iter->prev) {
1993
+ background = iter->data;
1994
+
1995
+ cairo_set_source_surface (cairo, background->surface, 0, 0);
1996
+ cairo_paint_with_alpha (cairo, background->group_opacity);
1997
+ }
1998
+
1999
+ cairo_destroy (cairo);
2000
+
2001
+ return surface;
2002
+ } else if (g_strcmp0 (input, "BackgroundAlpha") == 0) {
2003
+ LsmSvgFilterSurface *surface;
2004
+ LsmSvgFilterSurface *background_surface;
2005
+
2006
+ if (view->background_stack == NULL)
2007
+ return NULL;
2008
+
2009
+ background_surface = _get_filter_surface (view, "BackgroundImage");
2010
+
2011
+ surface = lsm_svg_filter_surface_new_similar ("BackgroundAlpha", background_surface, NULL);
2012
+ lsm_svg_filter_surface_alpha (background_surface, surface);
2013
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, surface);
2014
+
2015
+ return surface;
2016
+ }
2017
+
2018
+ return NULL;
2019
+ }
2020
+
2021
+ static LsmSvgFilterSurface *
2022
+ _create_filter_surface (LsmSvgView *view, const char *output, LsmSvgFilterSurface *input_surface, const LsmBox *subregion)
2023
+ {
2024
+ LsmSvgFilterSurface *surface;
2025
+
2026
+ surface = lsm_svg_filter_surface_new_similar (output, input_surface, subregion);
2027
+
2028
+ view->filter_surfaces = g_slist_prepend (view->filter_surfaces, surface);
2029
+
2030
+ return surface;
2031
+ }
2032
+
2033
+ LsmBox
2034
+ lsm_svg_view_get_filter_surface_extents (LsmSvgView *view, const char *name)
2035
+ {
2036
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
2037
+ LsmSvgFilterSurface *surface;
2038
+ LsmBox extents;
2039
+
2040
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), null_extents);
2041
+
2042
+ surface = _get_filter_surface (view, name);
2043
+ if (surface == NULL)
2044
+ return null_extents;
2045
+
2046
+ lsm_cairo_box_device_to_user (view->dom_view.cairo, &extents, lsm_svg_filter_surface_get_subregion (surface));
2047
+
2048
+ return extents;
2049
+ }
2050
+
2051
+ void
2052
+ lsm_svg_view_apply_blend (LsmSvgView *view, const char *input_1, const char*input_2, const char *output,
2053
+ const LsmBox *subregion, LsmSvgBlendingMode mode)
2054
+ {
2055
+ LsmSvgFilterSurface *output_surface;
2056
+ LsmSvgFilterSurface *input_1_surface;
2057
+ LsmSvgFilterSurface *input_2_surface;
2058
+ LsmBox subregion_px;
2059
+
2060
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2061
+
2062
+ input_1_surface = _get_filter_surface (view, input_1);
2063
+ input_2_surface = _get_filter_surface (view, input_2);
2064
+
2065
+ if (input_1_surface == NULL || input_2_surface == NULL) {
2066
+ lsm_warning_render ("[SvgView::apply_blend] Inputs '%s' or '%s' not found", input_1, input_2);
2067
+ return;
2068
+ }
2069
+
2070
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2071
+ output_surface = _create_filter_surface (view, output, input_1_surface, &subregion_px);
2072
+
2073
+ lsm_log_render ("[SvgView::blend] mode = %s", lsm_svg_blending_mode_to_string (mode));
2074
+
2075
+ lsm_svg_filter_surface_blend (input_1_surface, input_2_surface, output_surface, mode);
2076
+ }
2077
+
2078
+ void
2079
+ lsm_svg_view_apply_flood (LsmSvgView *view, const char *output, const LsmBox *subregion)
2080
+ {
2081
+ LsmSvgFilterSurface *output_surface;
2082
+ LsmSvgFilterSurface *input_surface;
2083
+ LsmBox subregion_px;
2084
+
2085
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2086
+
2087
+ input_surface = _get_filter_surface (view, NULL);
2088
+
2089
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2090
+ output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
2091
+
2092
+ lsm_log_render ("[SvgView::apply_flood] subregion %gx%g px at %g,%g px",
2093
+ subregion_px.width, subregion_px.height,
2094
+ subregion_px.x, subregion_px.y);
2095
+
2096
+ lsm_svg_filter_surface_flood (output_surface,
2097
+ view->style->flood_color->value.red,
2098
+ view->style->flood_color->value.green,
2099
+ view->style->flood_color->value.blue,
2100
+ view->style->flood_opacity->value);
2101
+ }
2102
+
2103
+ void
2104
+ lsm_svg_view_apply_gaussian_blur (LsmSvgView *view, const char *input, const char *output,
2105
+ const LsmBox *subregion, double std_x, double std_y)
2106
+ {
2107
+ LsmSvgFilterSurface *input_surface;
2108
+ LsmSvgFilterSurface *output_surface;
2109
+ LsmBox subregion_px;
2110
+
2111
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2112
+
2113
+ input_surface = _get_filter_surface (view, input);
2114
+
2115
+ if (input_surface == NULL) {
2116
+ lsm_debug_render ("[SvgView::apply_gaussian_blur] Input '%s' not found", input);
2117
+ return;
2118
+ }
2119
+
2120
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2121
+ output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
2122
+
2123
+ lsm_log_render ("[SvgView::apply_gaussian_blur] %s -> %s (%g,%g)",
2124
+ input != NULL ? input : "previous",
2125
+ output != NULL ? output : "next",
2126
+ std_x, std_y);
2127
+
2128
+ cairo_user_to_device_distance (view->dom_view.cairo, &std_x, &std_y);
2129
+
2130
+ lsm_log_render ("[SvgView::apply_gaussian_blur] %g px,%g px",
2131
+ std_x, std_y);
2132
+
2133
+ lsm_svg_filter_surface_fast_blur (input_surface, output_surface, std_x, std_y);
2134
+ }
2135
+
2136
+ void
2137
+ lsm_svg_view_apply_offset (LsmSvgView *view, const char *input, const char *output,
2138
+ const LsmBox *subregion, double dx, double dy)
2139
+ {
2140
+ LsmSvgFilterSurface *input_surface;
2141
+ LsmSvgFilterSurface *output_surface;
2142
+ LsmBox subregion_px;
2143
+
2144
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2145
+
2146
+ input_surface = _get_filter_surface (view, input);
2147
+
2148
+ if (input_surface == NULL) {
2149
+ lsm_debug_render ("[SvgView::apply_offset] Input '%s' not found", input);
2150
+ return;
2151
+ }
2152
+
2153
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2154
+ output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
2155
+
2156
+ lsm_log_render ("[SvgView::apply_offset] %s -> %s (dx:%g,dy:%g)", input, output, dx, dy);
2157
+
2158
+ cairo_user_to_device_distance (view->dom_view.cairo, &dx, &dy);
2159
+
2160
+ lsm_log_render ("[SvgView::apply_offset] %g px,%g px", dx, dy);
2161
+
2162
+ lsm_svg_filter_surface_offset (input_surface, output_surface, dx, dy);
2163
+ }
2164
+
2165
+ void
2166
+ lsm_svg_view_apply_merge (LsmSvgView *view, const char *input, const char *output, const LsmBox *subregion)
2167
+ {
2168
+ LsmSvgFilterSurface *input_surface;
2169
+ LsmSvgFilterSurface *output_surface;
2170
+ LsmBox subregion_px;
2171
+
2172
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2173
+
2174
+ input_surface = _get_filter_surface (view, input);
2175
+
2176
+ if (input_surface == NULL) {
2177
+ lsm_debug_render ("[SvgView::apply_offset] Input '%s' not found", input);
2178
+ return;
2179
+ }
2180
+
2181
+ output_surface = _get_filter_surface (view, output);
2182
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2183
+ if (output_surface == NULL)
2184
+ output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
2185
+
2186
+ if (output_surface != NULL)
2187
+ lsm_svg_filter_surface_merge (input_surface, output_surface);
2188
+ }
2189
+
2190
+ void
2191
+ lsm_svg_view_apply_tile (LsmSvgView *view, const char *input, const char *output, const LsmBox *subregion)
2192
+ {
2193
+ LsmSvgFilterSurface *input_surface;
2194
+ LsmSvgFilterSurface *output_surface;
2195
+ LsmBox subregion_px;
2196
+
2197
+ input_surface = _get_filter_surface (view, input);
2198
+
2199
+ if (input_surface == NULL) {
2200
+ lsm_debug_render ("[SvgView::apply_offset] Input '%s' not found", input);
2201
+ return;
2202
+ }
2203
+
2204
+ lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
2205
+ output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
2206
+
2207
+ lsm_svg_filter_surface_tile (input_surface, output_surface);
2208
+ }
2209
+
2210
+ void
2211
+ lsm_svg_view_push_element (LsmSvgView *view, const LsmSvgElement *element)
2212
+ {
2213
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2214
+ g_return_if_fail (LSM_IS_SVG_ELEMENT (element));
2215
+
2216
+ view->element_stack = g_slist_prepend (view->element_stack, (void *) element);
2217
+ }
2218
+
2219
+ void
2220
+ lsm_svg_view_pop_element (LsmSvgView *view)
2221
+ {
2222
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2223
+ g_return_if_fail (view->element_stack != NULL);
2224
+
2225
+ view->element_stack = g_slist_delete_link (view->element_stack, view->element_stack);
2226
+ }
2227
+
2228
+ static gboolean
2229
+ lsm_svg_view_circular_reference_check (LsmSvgView *view, LsmSvgElement *element)
2230
+ {
2231
+ GSList *iter;
2232
+
2233
+ for (iter = view->element_stack; iter != NULL; iter = iter->next)
2234
+ if (iter->data == element) {
2235
+ lsm_debug_render ("[LsmSvgView::circular_reference_check] "
2236
+ "Circular reference to %s (id = %s)",
2237
+ lsm_dom_element_get_tag_name (LSM_DOM_ELEMENT (element)),
2238
+ lsm_dom_element_get_attribute (LSM_DOM_ELEMENT (element), "id"));
2239
+ return TRUE;
2240
+ }
2241
+
2242
+ return FALSE;
2243
+ }
2244
+
2245
+ void
2246
+ lsm_svg_view_push_style (LsmSvgView *view, LsmSvgStyle *style)
2247
+ {
2248
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2249
+ g_return_if_fail (style != NULL);
2250
+
2251
+ lsm_log_render ("[SvgView::push_style]");
2252
+
2253
+ if (view->style == NULL || (style->font_size != view->style->font_size)) {
2254
+ LsmSvgViewbox font_viewbox;
2255
+ LsmSvgViewbox *viewbox;
2256
+ double current_font_size_px;
2257
+
2258
+ if (view->style != NULL)
2259
+ current_font_size_px = view->style->font_size_px;
2260
+ else
2261
+ current_font_size_px = 0.0;
2262
+
2263
+ viewbox = view->viewbox_stack->data;
2264
+ font_viewbox.resolution_ppi = viewbox->resolution_ppi;
2265
+ font_viewbox.viewbox.x = 0;
2266
+ font_viewbox.viewbox.y = 0;
2267
+ font_viewbox.viewbox.width = current_font_size_px;
2268
+ font_viewbox.viewbox.height = current_font_size_px;
2269
+
2270
+ style->font_size_px = lsm_svg_length_normalize (&style->font_size->length, &font_viewbox,
2271
+ current_font_size_px, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
2272
+
2273
+ if (style->font_size_px < 0.0)
2274
+ style->font_size_px = 0.0;
2275
+ lsm_log_render ("[SvgView::push_style] Font size = %g pixels", style->font_size_px);
2276
+ } else
2277
+ style->font_size_px = view->style->font_size_px;
2278
+
2279
+ view->style_stack = g_slist_prepend (view->style_stack, (void *) style);
2280
+ view->style = style;
2281
+
2282
+ }
2283
+
2284
+ void
2285
+ lsm_svg_view_push_composition (LsmSvgView *view, LsmSvgStyle *style)
2286
+ {
2287
+ gboolean do_filter;
2288
+ gboolean do_mask;
2289
+ gboolean do_clip;
2290
+
2291
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2292
+ g_return_if_fail (style != NULL);
2293
+
2294
+ lsm_svg_view_push_style (view, style);
2295
+
2296
+ lsm_log_render ("[SvgView::push_composition]");
2297
+
2298
+ do_clip = (g_strcmp0 (style->clip_path->value, "none") != 0);
2299
+ do_mask = (g_strcmp0 (style->mask->value, "none") != 0);
2300
+ do_filter = (g_strcmp0 (style->filter->value, "none") != 0);
2301
+
2302
+ if (G_UNLIKELY((view->style->opacity->value < 1.0 ||
2303
+ view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW ||
2304
+ view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER) &&
2305
+ !do_filter &&
2306
+ !view->is_clipping &&
2307
+ !view->style->ignore_group_opacity &&
2308
+ view->dom_view.cairo != NULL)) {
2309
+ LsmSvgViewBackground *background;
2310
+
2311
+ lsm_debug_render ("[LsmSvgView::push_composition] Push group");
2312
+ cairo_push_group (view->dom_view.cairo);
2313
+
2314
+ background = g_slice_new (LsmSvgViewBackground);
2315
+ background->surface = cairo_get_group_target (view->dom_view.cairo);
2316
+ background->group_opacity = view->style->opacity->value;
2317
+ background->enable_background = view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW;
2318
+
2319
+ view->background_stack = g_list_prepend (view->background_stack, background);
2320
+ }
2321
+
2322
+ if (G_UNLIKELY (do_clip)) {
2323
+ lsm_debug_render ("[LsmSvgView::push_style] Start clip '%s'", style->clip_path->value);
2324
+ lsm_svg_view_push_clip (view);
2325
+ }
2326
+
2327
+ if (G_UNLIKELY (do_mask)) {
2328
+ lsm_debug_render ("[LsmSvgView::push_style] Start mask '%s'", style->mask->value);
2329
+ lsm_svg_view_push_mask (view);
2330
+ }
2331
+
2332
+ /* Don't do filtering during a clipping operation, as filter will
2333
+ * create a new subsurface, where clipping should occur with the path
2334
+ * of the clip-path element. */
2335
+ if (G_UNLIKELY (do_filter && !view->is_clipping)) {
2336
+ lsm_debug_render ("[LsmSvgView::push_style] Start filter '%s'", style->filter->value);
2337
+ lsm_svg_view_push_filter (view);
2338
+ }
2339
+ }
2340
+
2341
+ void lsm_svg_view_pop_style (LsmSvgView *view)
2342
+ {
2343
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2344
+ g_return_if_fail (view->style_stack != NULL);
2345
+
2346
+ view->style_stack = g_slist_delete_link (view->style_stack, view->style_stack);
2347
+ view->style = view->style_stack != NULL ? view->style_stack->data : NULL;
2348
+
2349
+ lsm_log_render ("[SvgView::pop_style]");
2350
+ }
2351
+
2352
+ void lsm_svg_view_pop_composition (LsmSvgView *view)
2353
+ {
2354
+ gboolean do_filter;
2355
+ gboolean do_mask;
2356
+ gboolean do_clip;
2357
+ cairo_t *cairo;
2358
+
2359
+ g_return_if_fail (LSM_IS_SVG_VIEW (view));
2360
+ g_return_if_fail (view->style != NULL);
2361
+
2362
+ lsm_log_render ("[SvgView::pop_composition]");
2363
+
2364
+ do_clip = (g_strcmp0 (view->style->clip_path->value, "none") != 0);
2365
+ do_mask = (g_strcmp0 (view->style->mask->value, "none") != 0);
2366
+ do_filter = (g_strcmp0 (view->style->filter->value, "none") != 0);
2367
+
2368
+ /* Don't do filtering during a clipping operation, as filter will
2369
+ * create a new subsurface, where clipping should occur with the path
2370
+ * of the clip-path element. */
2371
+ if (G_UNLIKELY (do_filter && !view->is_clipping))
2372
+ lsm_svg_view_pop_filter (view);
2373
+
2374
+ if (G_UNLIKELY (do_mask))
2375
+ lsm_svg_view_pop_mask (view);
2376
+
2377
+ if (G_UNLIKELY (do_clip))
2378
+ lsm_svg_view_pop_clip (view);
2379
+
2380
+ cairo = view->dom_view.cairo;
2381
+
2382
+ if (G_UNLIKELY ((view->style->opacity->value < 1.0 ||
2383
+ view->style->enable_background->value == LSM_SVG_ENABLE_BACKGROUND_NEW ||
2384
+ view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER) &&
2385
+ !do_filter &&
2386
+ !view->is_clipping &&
2387
+ !view->style->ignore_group_opacity &&
2388
+ cairo != NULL)) {
2389
+ g_slice_free (LsmSvgViewBackground, view->background_stack->data);
2390
+ view->background_stack = g_list_delete_link (view->background_stack, view->background_stack);
2391
+
2392
+ cairo_pop_group_to_source (view->dom_view.cairo);
2393
+ if (G_UNLIKELY (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
2394
+ lsm_cairo_set_comp_op (cairo, view->style->comp_op->value);
2395
+ cairo_paint_with_alpha (cairo, view->style->opacity->value);
2396
+ if (G_UNLIKELY (view->style->comp_op->value != LSM_SVG_COMP_OP_SRC_OVER))
2397
+ lsm_cairo_set_comp_op (cairo, LSM_SVG_COMP_OP_SRC_OVER);
2398
+ lsm_debug_render ("[LsmSvgView::pop_composition] Pop group");
2399
+ }
2400
+
2401
+ lsm_svg_view_pop_style (view);
2402
+ }
2403
+
2404
+ LsmSvgStyle *
2405
+ lsm_svg_view_get_current_style (LsmSvgView *view)
2406
+ {
2407
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
2408
+
2409
+ return (LsmSvgStyle *) view->style;
2410
+ }
2411
+
2412
+ const LsmBox *
2413
+ lsm_svg_view_get_pattern_extents (LsmSvgView *view)
2414
+ {
2415
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
2416
+
2417
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
2418
+ g_return_val_if_fail (view->pattern_data != NULL, &null_extents);
2419
+
2420
+ return &view->pattern_data->extents;
2421
+ }
2422
+
2423
+ const LsmBox *
2424
+ lsm_svg_view_get_object_extents (LsmSvgView *view)
2425
+ {
2426
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
2427
+
2428
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
2429
+ g_return_val_if_fail (view->pattern_data != NULL, &null_extents);
2430
+
2431
+ return &view->pattern_data->object_extents;
2432
+ }
2433
+
2434
+ const LsmBox *
2435
+ lsm_svg_view_get_clip_extents (LsmSvgView *view)
2436
+ {
2437
+ static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
2438
+
2439
+ g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
2440
+ g_return_val_if_fail (view->is_clipping, &null_extents);
2441
+
2442
+ return &view->clip_extents;
2443
+ }
2444
+
2445
+ static void
2446
+ lsm_svg_view_measure (LsmDomView *view, double *width, double *height, double *baseline)
2447
+ {
2448
+ LsmSvgSvgElement *svg_element;
2449
+
2450
+ svg_element = lsm_svg_document_get_root_element (LSM_SVG_DOCUMENT (view->document));
2451
+ if (svg_element == NULL)
2452
+ return;
2453
+
2454
+ lsm_svg_svg_element_measure (svg_element, LSM_SVG_VIEW (view), width, height);
2455
+ if (baseline)
2456
+ *baseline = *height;
2457
+ }
2458
+
2459
+ static void
2460
+ lsm_svg_view_render (LsmDomView *view)
2461
+ {
2462
+ LsmSvgView *svg_view;
2463
+ LsmSvgSvgElement *svg_element;
2464
+
2465
+ svg_view = LSM_SVG_VIEW (view);
2466
+
2467
+ svg_element = lsm_svg_document_get_root_element (LSM_SVG_DOCUMENT (view->document));
2468
+ if (svg_element == NULL)
2469
+ return;
2470
+
2471
+ svg_view->style_stack = NULL;
2472
+ svg_view->element_stack = NULL;
2473
+ svg_view->viewbox_stack = NULL;
2474
+ svg_view->matrix_stack = NULL;
2475
+ svg_view->pango_layout_stack = NULL;
2476
+ svg_view->background_stack = NULL;
2477
+
2478
+ svg_view->is_clipping = FALSE;
2479
+ svg_view->is_pango_layout_in_use = FALSE;
2480
+ svg_view->pango_layout = view->pango_layout;
2481
+
2482
+ svg_view->resolution_ppi = lsm_dom_view_get_resolution (view);
2483
+
2484
+ lsm_svg_svg_element_render (svg_element, svg_view);
2485
+
2486
+ if (svg_view->is_pango_layout_in_use)
2487
+ g_warning ("[LsmSvgView::render] Unfinished text redenring");
2488
+
2489
+ if (svg_view->is_clipping)
2490
+ g_warning ("[LsmSvgView::render] Unfinished clipping");
2491
+
2492
+ if (svg_view->pango_layout_stack != NULL) {
2493
+ g_warning ("[LsmSvgView::render] Dangling pango_layout in stack");
2494
+ g_slist_free (svg_view->pango_layout_stack);
2495
+ svg_view->pango_layout_stack = NULL;
2496
+ }
2497
+
2498
+ if (svg_view->matrix_stack != NULL) {
2499
+ g_warning ("[LsmSvgView::render] Dangling matrix in stack");
2500
+ g_slist_free (svg_view->matrix_stack);
2501
+ svg_view->matrix_stack = NULL;
2502
+ }
2503
+ if (svg_view->viewbox_stack != NULL) {
2504
+ g_warning ("[LsmSvgView::render] Dangling viewport in stack");
2505
+ g_slist_free (svg_view->viewbox_stack);
2506
+ svg_view->viewbox_stack = NULL;
2507
+ }
2508
+ if (svg_view->element_stack != NULL) {
2509
+ g_warning ("[LsmSvgView::render] Dangling element in stack");
2510
+ g_slist_free (svg_view->element_stack);
2511
+ svg_view->element_stack = NULL;
2512
+ }
2513
+ if (svg_view->style_stack != NULL) {
2514
+ g_warning ("[LsmSvgView::render] Dangling style in stack");
2515
+ g_slist_free (svg_view->style_stack);
2516
+ svg_view->style_stack = NULL;
2517
+ }
2518
+ if (svg_view->background_stack != NULL) {
2519
+ g_warning ("[LsmSvgView::render] Dangling background in stack");
2520
+ g_list_free (svg_view->background_stack);
2521
+ svg_view->background_stack = NULL;
2522
+ }
2523
+ }
2524
+
2525
+ static void
2526
+ lsm_svg_view_set_debug (LsmDomView *view, const char *feature, gboolean enable)
2527
+ {
2528
+ LsmSvgView *svg_view = LSM_SVG_VIEW (view);
2529
+
2530
+ if (g_strcmp0 (feature, "filter") == 0)
2531
+ svg_view->debug_filter = enable;
2532
+ else if (g_strcmp0 (feature, "mask") == 0)
2533
+ svg_view->debug_mask = enable;
2534
+ else if (g_strcmp0 (feature, "pattern") == 0)
2535
+ svg_view->debug_pattern = enable;
2536
+ else if (g_strcmp0 (feature, "group") == 0)
2537
+ svg_view->debug_group = enable;
2538
+ else if (g_strcmp0 (feature, "text") == 0)
2539
+ svg_view->debug_text = enable;
2540
+ }
2541
+
2542
+ LsmSvgView *
2543
+ lsm_svg_view_new (LsmSvgDocument *document)
2544
+ {
2545
+ LsmSvgView *view;
2546
+
2547
+ view = g_object_new (LSM_TYPE_SVG_VIEW, NULL);
2548
+
2549
+ lsm_dom_view_set_document (LSM_DOM_VIEW (view), LSM_DOM_DOCUMENT (document));
2550
+
2551
+ return view;
2552
+ }
2553
+
2554
+ static void
2555
+ lsm_svg_view_init (LsmSvgView *view)
2556
+ {
2557
+ view->debug_mask = FALSE;
2558
+ view->debug_filter = FALSE;
2559
+ view->debug_pattern = FALSE;
2560
+ }
2561
+
2562
+ static void
2563
+ lsm_svg_view_finalize (GObject *object)
2564
+ {
2565
+ parent_class->finalize (object);
2566
+ }
2567
+
2568
+ static void
2569
+ lsm_svg_view_class_init (LsmSvgViewClass *view_class)
2570
+ {
2571
+ GObjectClass *object_class = G_OBJECT_CLASS (view_class);
2572
+ LsmDomViewClass *d_view_class = LSM_DOM_VIEW_CLASS (view_class);
2573
+
2574
+ parent_class = g_type_class_peek_parent (view_class);
2575
+
2576
+ object_class->finalize = lsm_svg_view_finalize;
2577
+
2578
+ d_view_class->measure = lsm_svg_view_measure;
2579
+ d_view_class->render = lsm_svg_view_render;
2580
+ d_view_class->set_debug = lsm_svg_view_set_debug;
2581
+ }
2582
+
2583
+ G_DEFINE_TYPE (LsmSvgView, lsm_svg_view, LSM_TYPE_DOM_VIEW)