Merge lp:~inkscape.dev/inkscape/writing_modes into lp:~inkscape.dev/inkscape/trunk
- writing_modes
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 14487 |
Proposed branch: | lp:~inkscape.dev/inkscape/writing_modes |
Merge into: | lp:~inkscape.dev/inkscape/trunk |
Diff against target: |
2674 lines (+1247/-352) 22 files modified
share/icons/icons.svg (+347/-4) src/desktop-style.cpp (+57/-5) src/desktop-style.h (+1/-0) src/display/nr-style.cpp (+0/-2) src/display/nr-style.h (+0/-1) src/libnrtype/FontInstance.cpp (+209/-29) src/libnrtype/Layout-TNG-Compute.cpp (+200/-149) src/libnrtype/Layout-TNG-Input.cpp (+10/-46) src/libnrtype/Layout-TNG-OutIter.cpp (+9/-6) src/libnrtype/Layout-TNG-Output.cpp (+46/-14) src/libnrtype/Layout-TNG-Scanline-Maker.h (+7/-7) src/libnrtype/Layout-TNG-Scanline-Makers.cpp (+14/-18) src/libnrtype/Layout-TNG.h (+88/-15) src/libnrtype/TextWrapper.cpp (+2/-2) src/libnrtype/font-instance.h (+28/-5) src/libnrtype/one-box.h (+1/-1) src/style-enums.h (+31/-10) src/style-internal.h (+0/-1) src/style.cpp (+7/-4) src/style.h (+2/-0) src/widgets/text-toolbar.cpp (+186/-33) src/widgets/toolbox.cpp (+2/-0) |
To merge this branch: | bzr merge lp:~inkscape.dev/inkscape/writing_modes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Inkscape Developers | Pending | ||
Review via email: mp+276053@code.launchpad.net |
Commit message
Description of the change
* Latin characters in vertical text will be drawn by default sideways.
This is the default direction in both SVG 1.1 and in CSS 3 Writing
Modes. Currently Inkscape draws the glyphs upright.
* Punctuation characters in CJK vertical text will be orientated
correctly.
* The Text Toolbar can be used to set 'text-orientation' which controls
how characters are orientated in vertical text (it has no effect on
horizontal text). The three choices are 'mixed' where the glyphs are
drawn in their Unicode defined natural orientation, 'upright' where all
glyphs are drawn upright, and 'sideways' where all glyphs are drawn
sideways.
* The new CSS 3 values for 'writing-mode' will be recognized. The
values written out are still the SVG 1.1 values except for the new
'vertical-lr' value which has no equivalent SVG 1.1 value (and is
required for Mongolian). A new button appears on the Text Toolbar to
select this value. (The SVG 1.1 values are deprecated but must still be
recognized by SVG renderers.)
* Fonts without vertical metrics will have a vertical advance of 1em.
The CSS specification explicitly does not define what advance to use
but the SVG 1.1 spec suggests 1em and the W3C Japanese text document
specified an advance of 1em.
* In laying out multi-line text, any 'leading' value from the font is
ignored. CSS dictates that the font-size corresponds to the em height
of a font which is defined as 'ascent' + 'descent'. The change to
ignore the "internal" font 'leading' may make small visual changes in
how multi-line text appears.
* In flowed text, Inkscape has been using a "scaled" value of 'ascent'
to position the first line. This has been changed to follow the correct
CSS prescription of using the value of 'half-leading' + normal 'ascent'
for horizontal text (to find the alphabetic baseline) and 'half
-leading' + half em width for vertical text (to find the center
baseline). (The 'leading' in this case is the extra space needed
between lines as dictated by the 'line-height' property. It is not the
'internal' font 'leading'.)
- 14432. By Tavmjong Bah
-
Vertical baseline depends on block 'text-orientation' value.
- 14433. By Tavmjong Bah
-
Rearrange code to make handling of baseline clearer.
- 14434. By Tavmjong Bah
-
'direction' is an inherited property, remove 'set' requirement.
- 14435. By Tavmjong Bah
-
Replace leading by more useful x-height. Use OS/2 font metrics when available.
Use otmMacAscent/otmMacDescent rather than otmAscent/ otmDescent.
Actually both should be available as they have different purposes... - 14436. By Tavmjong Bah
-
Read/write 'dominant-baseline' property.
- 14437. By Tavmjong Bah
-
Find font metrics when font is initialized. Fill baseline table.
Separately track typographic ascent/descent and maximum ascent/descent. - 14438. By Tavmjong Bah
-
Turn FontMetrics into a class. Add maximum ascent/descent variables.
- 14439. By Tavmjong Bah
-
Code cleanup. Remove/simplify some functions.
- 14440. By Tavmjong Bah
-
Use maximum ascent and descent for glyphs to ensure that glyphs that extend
outside the em-box are fully drawn. - 14441. By Tavmjong Bah
-
Implement rendering of 'dominant-baseline' property.
- 14442. By Tavmjong Bah
-
Swap text-before-edge and text-after-edge baseline values.
- 14443. By Tavmjong Bah
-
Remove unintended change that added C++11 flag.
Preview Diff
1 | === modified file 'share/icons/icons.svg' |
2 | --- share/icons/icons.svg 2015-07-27 00:04:29 +0000 |
3 | +++ share/icons/icons.svg 2015-11-24 09:40:36 +0000 |
4 | @@ -869,6 +869,45 @@ |
5 | <linearGradient y2="217.2552" x2="173.0313" y1="207.7552" x1="161.2865" gradientTransform="matrix(1.102855,0,0,1.148517,-175.0966,-238.3557)" gradientUnits="userSpaceOnUse" id="linearGradient20190" xlink:href="#linearGradient3480" inkscape:collect="always" /> |
6 | <linearGradient y2="218.5416" x2="173.724" y1="209.14059" x1="163.85941" gradientTransform="matrix(1.102855,0,0,1.148517,-174.5451,-237.7814)" gradientUnits="userSpaceOnUse" id="linearGradient20197" xlink:href="#linearGradient1887" inkscape:collect="always" /> |
7 | <linearGradient y2="217.2552" x2="173.0313" y1="207.7552" x1="161.2865" gradientTransform="matrix(1.102855,0,0,1.148517,-175.0966,-238.3557)" gradientUnits="userSpaceOnUse" id="linearGradient20199" xlink:href="#linearGradient3480" inkscape:collect="always" /> |
8 | + <linearGradient |
9 | + inkscape:collect="always" |
10 | + xlink:href="#linearGradient6524" |
11 | + id="linearGradient10133" |
12 | + gradientUnits="userSpaceOnUse" |
13 | + x1="860.239" |
14 | + y1="45.30668" |
15 | + x2="843.9635" |
16 | + y2="28.96459" /> |
17 | + <linearGradient |
18 | + inkscape:collect="always" |
19 | + xlink:href="#linearGradient6524" |
20 | + id="linearGradient10161" |
21 | + gradientUnits="userSpaceOnUse" |
22 | + x1="860.239" |
23 | + y1="45.30668" |
24 | + x2="843.9635" |
25 | + y2="28.96459" |
26 | + gradientTransform="translate(-256,405)" /> |
27 | + <linearGradient |
28 | + inkscape:collect="always" |
29 | + xlink:href="#linearGradient6524" |
30 | + id="linearGradient11127" |
31 | + gradientUnits="userSpaceOnUse" |
32 | + gradientTransform="translate(-226,405)" |
33 | + x1="860.239" |
34 | + y1="45.30668" |
35 | + x2="843.9635" |
36 | + y2="28.96459" /> |
37 | + <linearGradient |
38 | + inkscape:collect="always" |
39 | + xlink:href="#linearGradient6524" |
40 | + id="linearGradient11155" |
41 | + gradientUnits="userSpaceOnUse" |
42 | + gradientTransform="translate(-196,405)" |
43 | + x1="860.239" |
44 | + y1="45.30668" |
45 | + x2="843.9635" |
46 | + y2="28.96459" /> |
47 | </defs> |
48 | <sodipodi:namedview inkscape:guide-bbox="true" inkscape:current-layer="svg1" inkscape:grid-bbox="true" inkscape:pageopacity="1.0000000" pagecolor="#e8e8e4" snaptoguides="true" showguides="true" inkscape:window-y="27" inkscape:window-x="0" inkscape:window-height="960" inkscape:window-width="1280" inkscape:cy="336.2393" inkscape:cx="537.9384" inkscape:zoom="6.033032" gridtolerance="6" snaptogrid="false" showgrid="false" id="base" inkscape:document-units="px" inkscape:grid-points="true" guidetolerance="8" fill="#8ab3de" stroke="#646464" inkscape:object-nodes="false" objecttolerance="11" inkscape:snap-bbox="false" inkscape:snap-nodes="true" inkscape:bbox-nodes="false" inkscape:bbox-paths="false" inkscape:snap-global="false" inkscape:snap-center="false" inkscape:snap-midpoints="false" inkscape:snap-intersection-paths="true" inkscape:object-paths="false" inkscape:snap-object-midpoints="true" inkscape:window-maximized="1" inkscape:snap-grids="true" inkscape:snap-smooth-nodes="false" inkscape:snap-text-baseline="false" inkscape:snap-page="true" inkscape:snap-bbox-midpoints="false" inkscape:snap-bbox-edge-midpoints="false"> |
49 | <inkscape:grid type="xygrid" id="grid9252" originx="0px" originy="0px" spacingx="0.5px" spacingy="0.5px" empspacing="2" visible="true" enabled="true" snapvisiblegridlinesonly="true" /> |
50 | @@ -1824,6 +1863,310 @@ |
51 | <path style="fill:#5a5a5a;fill-rule:evenodd" d="M 851.4754,45 849,42 851,42 851,27 852,27 852,42 854,42 851.4754,45 Z" id="path6550" sodipodi:nodetypes="cccccccc" inkscape:connector-curvature="0" /> |
52 | <use xlink:href="#path6550" height="1250" width="1250" transform="translate(-5.9754)" id="use5600" y="0" x="0" /> |
53 | </g> |
54 | +<g |
55 | + transform="translate(-196,375)" |
56 | + inkscape:label="#writing_mode_tb_lr" |
57 | + id="format-text-direction-vertical-lr"> |
58 | + <path |
59 | + inkscape:connector-curvature="0" |
60 | + style="color:#000000;fill:#000000;fill-opacity:0.06666673;fill-rule:evenodd" |
61 | + d="m 841,26 22,0 1,1 0,20 -2,2 -20,0 -1,-1 0,-22 z" |
62 | + id="path10109" |
63 | + sodipodi:nodetypes="cccccccc" /> |
64 | + <path |
65 | + inkscape:connector-curvature="0" |
66 | + id="path10111" |
67 | + d="m 840,26 1,0 0,20 -1,0 0,-20 z" |
68 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
69 | + <rect |
70 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
71 | + id="rect10113" |
72 | + width="1" |
73 | + height="20" |
74 | + x="861" |
75 | + y="26" /> |
76 | + <rect |
77 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
78 | + id="rect10115" |
79 | + width="1" |
80 | + height="20" |
81 | + x="-26" |
82 | + y="841" |
83 | + transform="matrix(0,-1,1,0,0,0)" /> |
84 | + <rect |
85 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
86 | + id="rect10117" |
87 | + width="1" |
88 | + height="20" |
89 | + x="-47" |
90 | + y="841" |
91 | + transform="matrix(0,-1,1,0,0,0)" /> |
92 | + <rect |
93 | + style="color:#000000;fill:url(#linearGradient10133);fill-rule:evenodd" |
94 | + id="rect10119" |
95 | + width="20" |
96 | + height="20" |
97 | + x="841" |
98 | + y="26" /> |
99 | + <path |
100 | + inkscape:connector-curvature="0" |
101 | + id="path10121" |
102 | + d="m 842,46 -1,0 0,-20 20,0 0,1 -19,0 0,19 z" |
103 | + style="fill:#ffffff;fill-rule:evenodd" /> |
104 | + <path |
105 | + inkscape:connector-curvature="0" |
106 | + sodipodi:nodetypes="cccc" |
107 | + id="path10123" |
108 | + d="m 843.5,34.7482 0,-4 c 0,-3 5,-3 5,0 l 0,4" |
109 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round" /> |
110 | + <path |
111 | + inkscape:connector-curvature="0" |
112 | + id="path10125" |
113 | + d="m 843.3571,31.9982 5.1429,0" |
114 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px" /> |
115 | + <path |
116 | + inkscape:connector-curvature="0" |
117 | + sodipodi:nodetypes="cccccccc" |
118 | + id="path10127" |
119 | + d="m 845.5492,45 2.4754,-3.0009 -2,0 0,-7 -1,0 0,7 -2,0 2.5246,3.0009 z" |
120 | + style="fill:#5a5a5a;fill-rule:evenodd" /> |
121 | + <path |
122 | + inkscape:connector-curvature="0" |
123 | + sodipodi:nodetypes="cccccccc" |
124 | + id="path10129" |
125 | + d="m 851.4754,45 -2.4754,-3 2,0 0,-15 1,0 0,15 2,0 -2.5246,3 z" |
126 | + style="fill:#5a5a5a;fill-rule:evenodd" /> |
127 | + <use |
128 | + x="0" |
129 | + y="0" |
130 | + id="use10131" |
131 | + transform="translate(6,0)" |
132 | + width="1250" |
133 | + height="1250" |
134 | + xlink:href="#path6550" /> |
135 | +</g> |
136 | +<g |
137 | + id="text-orientation-auto" |
138 | + inkscape:label="#text_orientation_auto"> |
139 | + <path |
140 | + inkscape:connector-curvature="0" |
141 | + style="color:#000000;fill:#000000;fill-opacity:0.06666673;fill-rule:evenodd" |
142 | + d="m 585,431 22,0 1,1 0,20 -2,2 -20,0 -1,-1 0,-22 z" |
143 | + id="path10137" |
144 | + sodipodi:nodetypes="cccccccc" /> |
145 | + <path |
146 | + inkscape:connector-curvature="0" |
147 | + id="path10139" |
148 | + d="m 584,431 1,0 0,20 -1,0 0,-20 z" |
149 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
150 | + <rect |
151 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
152 | + id="rect10141" |
153 | + width="1" |
154 | + height="20" |
155 | + x="605" |
156 | + y="431" /> |
157 | + <rect |
158 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
159 | + id="rect10143" |
160 | + width="1" |
161 | + height="20" |
162 | + x="-431" |
163 | + y="585" |
164 | + transform="matrix(0,-1,1,0,0,0)" /> |
165 | + <rect |
166 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
167 | + id="rect10145" |
168 | + width="1" |
169 | + height="20" |
170 | + x="-452" |
171 | + y="585" |
172 | + transform="matrix(0,-1,1,0,0,0)" /> |
173 | + <rect |
174 | + style="color:#000000;fill:url(#linearGradient10161);fill-rule:evenodd" |
175 | + id="rect10147" |
176 | + width="20" |
177 | + height="20" |
178 | + x="585" |
179 | + y="431" /> |
180 | + <path |
181 | + inkscape:connector-curvature="0" |
182 | + id="path10149" |
183 | + d="m 586,451 -1,0 0,-20 20,0 0,1 -19,0 0,19 z" |
184 | + style="fill:#ffffff;fill-rule:evenodd" /> |
185 | + <path |
186 | + inkscape:connector-curvature="0" |
187 | + sodipodi:nodetypes="cccc" |
188 | + id="path10151" |
189 | + d="m 595.30711,449.12856 4,0 c 3,0 3,-5 0,-5 l -4,0" |
190 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round" /> |
191 | + <path |
192 | + inkscape:connector-curvature="0" |
193 | + id="path10153" |
194 | + d="m 598.05711,449.27146 0,-5.1429" |
195 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px" /> |
196 | + <use |
197 | + x="0" |
198 | + y="0" |
199 | + id="use10159" |
200 | + transform="translate(-261,405)" |
201 | + width="1250" |
202 | + height="1250" |
203 | + xlink:href="#path6550" /> |
204 | + <path |
205 | + id="path11017" |
206 | + style="color:#000000;solid-opacity:1;fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round;stroke-linejoin:round" |
207 | + d="m 595,438.5 7.5,0.0854 m -6,-2.5854 4.20941,0 -1.70941,1.5 0.0234,3 c -0.0234,0.5 -0.52344,1 -1.02344,1 l -1,0 m 2.00004,-7.72791 -0.5,-0.77209 m -3.5,2.00274 0,-1.00274 7.5,0 -0.0207,0.98202" |
208 | + inkscape:connector-curvature="0" /> |
209 | +</g> |
210 | +<g |
211 | + id="text-orientation-upright" |
212 | + inkscape:label="#text_orientation_upright"> |
213 | + <path |
214 | + sodipodi:nodetypes="cccccccc" |
215 | + id="path11105" |
216 | + d="m 615,431 22,0 1,1 0,20 -2,2 -20,0 -1,-1 0,-22 z" |
217 | + style="color:#000000;fill:#000000;fill-opacity:0.06666673;fill-rule:evenodd" |
218 | + inkscape:connector-curvature="0" /> |
219 | + <path |
220 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
221 | + d="m 614,431 1,0 0,20 -1,0 0,-20 z" |
222 | + id="path11107" |
223 | + inkscape:connector-curvature="0" /> |
224 | + <rect |
225 | + y="431" |
226 | + x="635" |
227 | + height="20" |
228 | + width="1" |
229 | + id="rect11109" |
230 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
231 | + <rect |
232 | + transform="matrix(0,-1,1,0,0,0)" |
233 | + y="615" |
234 | + x="-431" |
235 | + height="20" |
236 | + width="1" |
237 | + id="rect11111" |
238 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
239 | + <rect |
240 | + transform="matrix(0,-1,1,0,0,0)" |
241 | + y="615" |
242 | + x="-452" |
243 | + height="20" |
244 | + width="1" |
245 | + id="rect11113" |
246 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
247 | + <rect |
248 | + y="431" |
249 | + x="615" |
250 | + height="20" |
251 | + width="20" |
252 | + id="rect11115" |
253 | + style="color:#000000;fill:url(#linearGradient11127);fill-rule:evenodd" /> |
254 | + <path |
255 | + style="fill:#ffffff;fill-rule:evenodd" |
256 | + d="m 616,451 -1,0 0,-20 20,0 0,1 -19,0 0,19 z" |
257 | + id="path11117" |
258 | + inkscape:connector-curvature="0" /> |
259 | + <path |
260 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round" |
261 | + d="m 630.92855,449.75 0,-4 c 0,-3 -5,-3 -5,0 l 0,4" |
262 | + id="path11119" |
263 | + sodipodi:nodetypes="cccc" |
264 | + inkscape:connector-curvature="0" /> |
265 | + <path |
266 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px" |
267 | + d="m 631.07145,447 -5.1429,0" |
268 | + id="path11121" |
269 | + inkscape:connector-curvature="0" /> |
270 | + <use |
271 | + xlink:href="#path6550" |
272 | + height="1250" |
273 | + width="1250" |
274 | + transform="translate(-231,405)" |
275 | + id="use11123" |
276 | + y="0" |
277 | + x="0" /> |
278 | + <path |
279 | + inkscape:connector-curvature="0" |
280 | + d="m 625,438.5 7.5,0.0854 m -6,-2.5854 4.20941,0 -1.70941,1.5 0.0234,3 c -0.0234,0.5 -0.52344,1 -1.02344,1 l -1,0 m 2.00004,-7.72791 -0.5,-0.77209 m -3.5,2.00274 0,-1.00274 7.5,0 -0.0207,0.98202" |
281 | + style="color:#000000;solid-opacity:1;fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round;stroke-linejoin:round" |
282 | + id="path11125" /> |
283 | +</g> |
284 | +<g |
285 | + id="text-orientation-sideways" |
286 | + inkscape:label="#text_orientation_sideways"> |
287 | + <path |
288 | + inkscape:connector-curvature="0" |
289 | + style="color:#000000;fill:#000000;fill-opacity:0.06666673;fill-rule:evenodd" |
290 | + d="m 645,431 22,0 1,1 0,20 -2,2 -20,0 -1,-1 0,-22 z" |
291 | + id="path11133" |
292 | + sodipodi:nodetypes="cccccccc" /> |
293 | + <path |
294 | + inkscape:connector-curvature="0" |
295 | + id="path11135" |
296 | + d="m 644,431 1,0 0,20 -1,0 0,-20 z" |
297 | + style="color:#000000;fill:#000000;fill-rule:evenodd" /> |
298 | + <rect |
299 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
300 | + id="rect11137" |
301 | + width="1" |
302 | + height="20" |
303 | + x="665" |
304 | + y="431" /> |
305 | + <rect |
306 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
307 | + id="rect11139" |
308 | + width="1" |
309 | + height="20" |
310 | + x="-431" |
311 | + y="645" |
312 | + transform="matrix(0,-1,1,0,0,0)" /> |
313 | + <rect |
314 | + style="color:#000000;fill:#000000;fill-rule:evenodd" |
315 | + id="rect11141" |
316 | + width="1" |
317 | + height="20" |
318 | + x="-452" |
319 | + y="645" |
320 | + transform="matrix(0,-1,1,0,0,0)" /> |
321 | + <rect |
322 | + style="color:#000000;fill:url(#linearGradient11155);fill-rule:evenodd" |
323 | + id="rect11143" |
324 | + width="20" |
325 | + height="20" |
326 | + x="645" |
327 | + y="431" /> |
328 | + <path |
329 | + inkscape:connector-curvature="0" |
330 | + id="path11145" |
331 | + d="m 646,451 -1,0 0,-20 20,0 0,1 -19,0 0,19 z" |
332 | + style="fill:#ffffff;fill-rule:evenodd" /> |
333 | + <path |
334 | + inkscape:connector-curvature="0" |
335 | + sodipodi:nodetypes="cccc" |
336 | + id="path11147" |
337 | + d="m 655.30711,449.12856 4,0 c 3,0 3,-5 0,-5 l -4,0" |
338 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round" /> |
339 | + <path |
340 | + inkscape:connector-curvature="0" |
341 | + id="path11149" |
342 | + d="m 658.05711,449.27146 0,-5.1429" |
343 | + style="fill:none;stroke:#383838;stroke-width:1.00000012px" /> |
344 | + <use |
345 | + x="0" |
346 | + y="0" |
347 | + id="use11151" |
348 | + transform="translate(-201,405)" |
349 | + width="1250" |
350 | + height="1250" |
351 | + xlink:href="#path6550" /> |
352 | + <path |
353 | + id="path11153" |
354 | + style="color:#000000;solid-opacity:1;fill:none;stroke:#383838;stroke-width:1.00000012px;stroke-linecap:round;stroke-linejoin:round" |
355 | + d="m 657.49703,433.49703 -0.0854,7.5 m 2.5854,-6 0,4.20941 -1.5,-1.70941 -3,0.0234 c -0.5,-0.0234 -1,-0.52344 -1,-1.02344 l 0,-1 m 7.72791,2.00004 0.77209,-0.5 m -2.00274,-3.5 1.00274,0 0,7.5 -0.98202,-0.0207" |
356 | + inkscape:connector-curvature="0" /> |
357 | +</g> |
358 | <g id="align-horizontal-right-to-anchor" transform="matrix(1,0,0,0.998006,1017.995,-110.6741)" inkscape:label="#al_left_out"> |
359 | <g id="g5060"> |
360 | <rect style="color:#000000;fill:none;stroke:url(#linearGradient5531);stroke-width:1.0009987;stroke-linejoin:round;stroke-miterlimit:0" id="rect5048" width="6.008899" height="5.011291" x="-27.50193" y="175.5202" /> |
361 | @@ -3958,11 +4301,11 @@ |
362 | <path style="fill:#ffffff;fill-rule:evenodd;stroke:url(#linearGradient5799-9);stroke-width:1px;stroke-linecap:round;stroke-linejoin:round" d="m 9.5,0.5 4,4 -4,0 0,-4 z" id="path4681-4" /> |
363 | </g> |
364 | <g transform="translate(236.3605,-335.8446)" id="flatten_simplify" inkscape:label="#flatten_simplify"> |
365 | -<rect y="536.7323" x="282.5811" height="15.721" width="15.721" id="rect13989" style="color:#000000;display:inline;fill:none;stroke:none;stroke-width:1;marker:none" /> |
366 | -<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="M 530.5332 205.6113 A 1.9925 2.080405 0 0 0 528.6133 207.1426 C 527.6704 207.4134 526.7115 207.8353 525.7988 208.5332 C 525.5735 208.7058 525.3617 208.8398 525.1465 208.9844 A 1.9925 2.080405 0 0 0 523.8516 208.4824 A 1.9925 2.080405 0 0 0 521.8672 210.3984 C 520.9451 210.5699 520.1488 210.5515 519.4629 210.5469 L 519.4512 212.0469 C 520.1403 212.0516 521.1103 212.0612 522.2676 211.8223 A 1.9925 2.080405 0 0 0 523.8516 212.6445 A 1.9925 2.080405 0 0 0 525.8438 210.5645 A 1.9925 2.080405 0 0 0 525.8281 210.3281 C 526.1184 210.1416 526.4096 209.954 526.709 209.7246 C 527.3764 209.2142 528.069 208.8737 528.7617 208.6484 A 1.9925 2.080405 0 0 0 530.5332 209.7734 A 1.9925 2.080405 0 0 0 532.4453 208.2656 C 533.1733 208.2979 533.843 208.3555 534.3984 208.3555 L 534.3984 206.8555 C 533.9353 206.8555 533.1903 206.7721 532.3047 206.7402 A 1.9925 2.080405 0 0 0 530.5332 205.6113 z M 530.5332 206.7246 A 0.9260918 0.9669491 0 0 1 531.459 207.6914 A 0.9260918 0.9669491 0 0 1 530.5332 208.6582 A 0.9260918 0.9669491 0 0 1 529.6055 207.6914 A 0.9260918 0.9669491 0 0 1 530.5332 206.7246 z M 523.8516 209.5957 A 0.9260918 0.9669491 0 0 1 524.7773 210.5645 A 0.9260918 0.9669491 0 0 1 523.8516 211.5312 A 0.9260918 0.9669491 0 0 1 522.9258 210.5645 A 0.9260918 0.9669491 0 0 1 523.8516 209.5957 z " transform="translate(-236.3605,335.8446)" id="path14280" /> |
367 | +<rect y="536.7323" x="282.5811" height="15.721" width="15.721" id="rect13989" style="color:#000000;fill:none" /> |
368 | +<path style="color:#000000;solid-opacity:1;fill:#000000;fill-rule:evenodd;stroke-width:1.5" d="M 530.5332 205.6113 A 1.9925 2.080405 0 0 0 528.6133 207.1426 C 527.6704 207.4134 526.7115 207.8353 525.7988 208.5332 C 525.5735 208.7058 525.3617 208.8398 525.1465 208.9844 A 1.9925 2.080405 0 0 0 523.8516 208.4824 A 1.9925 2.080405 0 0 0 521.8672 210.3984 C 520.9451 210.5699 520.1488 210.5515 519.4629 210.5469 L 519.4512 212.0469 C 520.1403 212.0516 521.1103 212.0612 522.2676 211.8223 A 1.9925 2.080405 0 0 0 523.8516 212.6445 A 1.9925 2.080405 0 0 0 525.8438 210.5645 A 1.9925 2.080405 0 0 0 525.8281 210.3281 C 526.1184 210.1416 526.4096 209.954 526.709 209.7246 C 527.3764 209.2142 528.069 208.8737 528.7617 208.6484 A 1.9925 2.080405 0 0 0 530.5332 209.7734 A 1.9925 2.080405 0 0 0 532.4453 208.2656 C 533.1733 208.2979 533.843 208.3555 534.3984 208.3555 L 534.3984 206.8555 C 533.9353 206.8555 533.1903 206.7721 532.3047 206.7402 A 1.9925 2.080405 0 0 0 530.5332 205.6113 z M 530.5332 206.7246 A 0.9260918 0.9669491 0 0 1 531.459 207.6914 A 0.9260918 0.9669491 0 0 1 530.5332 208.6582 A 0.9260918 0.9669491 0 0 1 529.6055 207.6914 A 0.9260918 0.9669491 0 0 1 530.5332 206.7246 z M 523.8516 209.5957 A 0.9260918 0.9669491 0 0 1 524.7773 210.5645 A 0.9260918 0.9669491 0 0 1 523.8516 211.5312 A 0.9260918 0.9669491 0 0 1 522.9258 210.5645 A 0.9260918 0.9669491 0 0 1 523.8516 209.5957 z " transform="translate(-236.3605,335.8446)" id="path14280" /> |
369 | </g> |
370 | <g inkscape:label="#interactive_simplify" id="interactive_simplify" transform="translate(215.9205,-334.4098)"> |
371 | -<rect style="color:#000000;display:inline;fill:none;stroke:none;stroke-width:1;marker:none" id="rect17937-7" width="15.721" height="15.721" x="284.9688" y="535.6099" /> |
372 | -<path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" d="m 290.1793,536.2979 c -0.7351,-0.02 -1.3963,0.2336 -1.8416,0.7418 -0.4453,0.5079 -0.6453,1.1819 -0.7277,1.8733 -0.165,1.3827 0.089,2.9888 0.3519,4.5721 0.2625,1.5832 0.5439,3.1441 0.5465,4.1601 0,0.5079 -0.082,0.854 -0.1453,0.9691 -0.064,0.115 -0.041,0.1361 -0.3174,0.1282 -0.6247,-0.018 -0.8383,-0.2559 -1.06,-0.7845 -0.2217,-0.5286 -0.3197,-1.3858 -0.2995,-2.2749 0.041,-1.7782 0.1181,-2.1383 0.1181,-2.1383 l -1.3819,-0.012 c 0,0 -0.034,0.44 -0.081,2.4977 -0.023,1.0288 -0.041,1.7085 0.3488,2.6369 0.3896,0.9284 1.2262,1.6826 2.3192,1.7143 0.6352,0.018 1.2607,-0.3347 1.5691,-0.8922 0.3084,-0.5575 0.3684,-1.1856 0.3668,-1.8493 0,-1.3269 -0.3139,-2.9046 -0.5719,-4.461 -0.258,-1.5566 -0.4523,-3.0895 -0.3384,-4.044 0.057,-0.4774 0.1784,-0.773 0.3189,-0.9332 0.1403,-0.1602 0.3293,-0.2738 0.7905,-0.2615 0.4549,0.012 0.691,0.1248 0.822,0.2393 0.131,0.1144 0.2075,0.2532 0.262,0.5316 0.109,0.5566 -0.012,1.5867 -0.2126,2.6612 -0.2001,1.0747 -0.4614,2.1843 -0.4372,3.2167 0.012,0.5163 0.098,1.0527 0.4133,1.5075 0.3153,0.4549 0.8398,0.7126 1.3954,0.7452 0.4606,0.027 0.881,-0.051 1.2367,-0.2735 0.3557,-0.2231 0.6121,-0.5902 0.7531,-0.9588 0.282,-0.7375 0.2377,-1.4817 0.2126,-2.157 -0.025,-0.6754 -0.041,-1.301 0.021,-1.5725 0.031,-0.1358 0.056,-0.155 0.057,-0.1555 6e-4,-6e-4 0.022,-0.034 0.2006,-0.029 0.218,0 0.2382,0.043 0.271,0.074 0.033,0.031 0.092,0.1224 0.1947,0.323 0.1022,0.2006 0.2482,0.5079 0.5375,0.7743 0.2893,0.2664 0.7035,0.4386 1.1723,0.4614 1.6094,-0.2758 2.284,-1.0042 3.4062,-0.084 l 0,-1.6613 c -1.4875,-0.7361 -2.2939,-0.161 -3.3448,0.1059 -0.2401,-0.012 -0.2878,-0.059 -0.3309,-0.099 -0.043,-0.04 -0.1003,-0.1294 -0.1991,-0.3231 -0.099,-0.1938 -0.2357,-0.493 -0.5181,-0.7606 -0.2825,-0.2676 -0.6959,-0.4362 -1.1528,-0.4495 -0.4137,-0.012 -0.8221,0.1078 -1.1305,0.388 -0.3084,0.2805 -0.4715,0.6683 -0.5524,1.0255 -0.162,0.7142 -0.091,1.4129 -0.067,2.0545 0.024,0.6418 -0.01,1.2067 -0.093,1.4289 -0.043,0.1112 -0.066,0.1378 -0.1273,0.176 -0.061,0.038 -0.1963,0.09 -0.4716,0.074 -0.2756,-0.016 -0.3064,-0.07 -0.3429,-0.1231 -0.037,-0.053 -0.098,-0.2166 -0.1048,-0.535 -0.015,-0.6367 0.2002,-1.72 0.4073,-2.8321 0.2071,-1.1119 0.4237,-2.265 0.2096,-3.3586 -0.1071,-0.5468 -0.3582,-1.0977 -0.792,-1.4767 -0.434,-0.379 -1.0001,-0.5617 -1.6605,-0.5794 z" id="path14318-5-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccsccccccccccccsccccccccccccccccccccc" /> |
373 | +<rect style="color:#000000;fill:none" id="rect17937-7" width="15.721" height="15.721" x="284.9688" y="535.6099" /> |
374 | +<path style="color:#000000;solid-opacity:1;fill:#000000;stroke-width:1.3" d="m 290.1793,536.2979 c -0.7351,-0.02 -1.3963,0.2336 -1.8416,0.7418 -0.4453,0.5079 -0.6453,1.1819 -0.7277,1.8733 -0.165,1.3827 0.089,2.9888 0.3519,4.5721 0.2625,1.5832 0.5439,3.1441 0.5465,4.1601 0,0.5079 -0.082,0.854 -0.1453,0.9691 -0.064,0.115 -0.041,0.1361 -0.3174,0.1282 -0.6247,-0.018 -0.8383,-0.2559 -1.06,-0.7845 -0.2217,-0.5286 -0.3197,-1.3858 -0.2995,-2.2749 0.041,-1.7782 0.1181,-2.1383 0.1181,-2.1383 l -1.3819,-0.012 c 0,0 -0.034,0.44 -0.081,2.4977 -0.023,1.0288 -0.041,1.7085 0.3488,2.6369 0.3896,0.9284 1.2262,1.6826 2.3192,1.7143 0.6352,0.018 1.2607,-0.3347 1.5691,-0.8922 0.3084,-0.5575 0.3684,-1.1856 0.3668,-1.8493 0,-1.3269 -0.3139,-2.9046 -0.5719,-4.461 -0.258,-1.5566 -0.4523,-3.0895 -0.3384,-4.044 0.057,-0.4774 0.1784,-0.773 0.3189,-0.9332 0.1403,-0.1602 0.3293,-0.2738 0.7905,-0.2615 0.4549,0.012 0.691,0.1248 0.822,0.2393 0.131,0.1144 0.2075,0.2532 0.262,0.5316 0.109,0.5566 -0.012,1.5867 -0.2126,2.6612 -0.2001,1.0747 -0.4614,2.1843 -0.4372,3.2167 0.012,0.5163 0.098,1.0527 0.4133,1.5075 0.3153,0.4549 0.8398,0.7126 1.3954,0.7452 0.4606,0.027 0.881,-0.051 1.2367,-0.2735 0.3557,-0.2231 0.6121,-0.5902 0.7531,-0.9588 0.282,-0.7375 0.2377,-1.4817 0.2126,-2.157 -0.025,-0.6754 -0.041,-1.301 0.021,-1.5725 0.031,-0.1358 0.056,-0.155 0.057,-0.1555 6e-4,-6e-4 0.022,-0.034 0.2006,-0.029 0.218,0 0.2382,0.043 0.271,0.074 0.033,0.031 0.092,0.1224 0.1947,0.323 0.1022,0.2006 0.2482,0.5079 0.5375,0.7743 0.2893,0.2664 0.7035,0.4386 1.1723,0.4614 1.6094,-0.2758 2.284,-1.0042 3.4062,-0.084 l 0,-1.6613 c -1.4875,-0.7361 -2.2939,-0.161 -3.3448,0.1059 -0.2401,-0.012 -0.2878,-0.059 -0.3309,-0.099 -0.043,-0.04 -0.1003,-0.1294 -0.1991,-0.3231 -0.099,-0.1938 -0.2357,-0.493 -0.5181,-0.7606 -0.2825,-0.2676 -0.6959,-0.4362 -1.1528,-0.4495 -0.4137,-0.012 -0.8221,0.1078 -1.1305,0.388 -0.3084,0.2805 -0.4715,0.6683 -0.5524,1.0255 -0.162,0.7142 -0.091,1.4129 -0.067,2.0545 0.024,0.6418 -0.01,1.2067 -0.093,1.4289 -0.043,0.1112 -0.066,0.1378 -0.1273,0.176 -0.061,0.038 -0.1963,0.09 -0.4716,0.074 -0.2756,-0.016 -0.3064,-0.07 -0.3429,-0.1231 -0.037,-0.053 -0.098,-0.2166 -0.1048,-0.535 -0.015,-0.6367 0.2002,-1.72 0.4073,-2.8321 0.2071,-1.1119 0.4237,-2.265 0.2096,-3.3586 -0.1071,-0.5468 -0.3582,-1.0977 -0.792,-1.4767 -0.434,-0.379 -1.0001,-0.5617 -1.6605,-0.5794 z" id="path14318-5-3" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccccccccccccccccccsccccccccccccsccccccccccccccccccccc" /> |
375 | </g> |
376 | </svg> |
377 | |
378 | === modified file 'src/desktop-style.cpp' |
379 | --- src/desktop-style.cpp 2015-10-28 20:43:30 +0000 |
380 | +++ src/desktop-style.cpp 2015-11-24 09:40:36 +0000 |
381 | @@ -500,7 +500,7 @@ |
382 | |
383 | SPIPaint *paint_res = isfill? &style_res->fill : &style_res->stroke; |
384 | bool paintImpossible = true; |
385 | - paint_res->set = TRUE; |
386 | + paint_res->set = true; |
387 | |
388 | SVGICCColor* iccColor = 0; |
389 | |
390 | @@ -1144,7 +1144,7 @@ |
391 | different = true; // different styles |
392 | } |
393 | |
394 | - set = TRUE; |
395 | + set = true; |
396 | style_res->font_weight.value = style_res->font_weight.computed = style->font_weight.computed; |
397 | style_res->font_style.value = style_res->font_style.computed = style->font_style.computed; |
398 | style_res->font_stretch.value = style_res->font_stretch.computed = style->font_stretch.computed; |
399 | @@ -1256,6 +1256,56 @@ |
400 | } |
401 | |
402 | |
403 | +/** |
404 | + * Write to style_res the average writing modes style of objects. |
405 | + */ |
406 | +int |
407 | +objects_query_writing_modes (const std::vector<SPItem*> &objects, SPStyle *style_res) |
408 | +{ |
409 | + bool different = false; |
410 | + bool set = false; |
411 | + |
412 | + int texts = 0; |
413 | + |
414 | + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { |
415 | + SPObject *obj = *i; |
416 | + |
417 | + if (!isTextualItem(obj)) { |
418 | + continue; |
419 | + } |
420 | + |
421 | + SPStyle *style = obj->style; |
422 | + if (!style) { |
423 | + continue; |
424 | + } |
425 | + |
426 | + texts ++; |
427 | + |
428 | + if (set && |
429 | + ( ( style_res->writing_mode.computed != style->writing_mode.computed ) || |
430 | + ( style_res->text_orientation.computed != style->text_orientation.computed ) ) ) { |
431 | + different = true; // different styles |
432 | + } |
433 | + |
434 | + set = true; |
435 | + style_res->writing_mode.computed = style->writing_mode.computed; |
436 | + style_res->text_orientation.computed = style->text_orientation.computed; |
437 | + } |
438 | + |
439 | + if (texts == 0 || !set) |
440 | + return QUERY_STYLE_NOTHING; |
441 | + |
442 | + if (texts > 1) { |
443 | + if (different) { |
444 | + return QUERY_STYLE_MULTIPLE_DIFFERENT; |
445 | + } else { |
446 | + return QUERY_STYLE_MULTIPLE_SAME; |
447 | + } |
448 | + } else { |
449 | + return QUERY_STYLE_SINGLE; |
450 | + } |
451 | +} |
452 | + |
453 | int |
454 | objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle *style_res) |
455 | { |
456 | @@ -1293,7 +1343,7 @@ |
457 | style_res->font_feature_settings.value = NULL; |
458 | } |
459 | |
460 | - style_res->font_feature_settings.set = TRUE; |
461 | + style_res->font_feature_settings.set = true; |
462 | style_res->font_feature_settings.value = g_strdup(style->font_feature_settings.value); |
463 | } |
464 | |
465 | @@ -1449,7 +1499,7 @@ |
466 | style_res->font_family.value = NULL; |
467 | } |
468 | |
469 | - style_res->font_family.set = TRUE; |
470 | + style_res->font_family.set = true; |
471 | style_res->font_family.value = g_strdup(style->font_family.value); |
472 | } |
473 | |
474 | @@ -1508,7 +1558,7 @@ |
475 | style_res->font_specification.value = NULL; |
476 | } |
477 | |
478 | - style_res->font_specification.set = TRUE; |
479 | + style_res->font_specification.set = true; |
480 | style_res->font_specification.value = g_strdup(style->font_specification.value); |
481 | } |
482 | } |
483 | @@ -1728,6 +1778,8 @@ |
484 | return objects_query_fontfeaturesettings (list, style); |
485 | } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) { |
486 | return objects_query_fontnumbers (list, style); |
487 | + } else if (property == QUERY_STYLE_PROPERTY_WRITINGMODES) { |
488 | + return objects_query_writing_modes (list, style); |
489 | } else if (property == QUERY_STYLE_PROPERTY_BASELINES) { |
490 | return objects_query_baselines (list, style); |
491 | |
492 | |
493 | === modified file 'src/desktop-style.h' |
494 | --- src/desktop-style.h 2015-06-22 14:13:38 +0000 |
495 | +++ src/desktop-style.h 2015-11-24 09:40:36 +0000 |
496 | @@ -51,6 +51,7 @@ |
497 | QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS, // font feature settings (OpenType features) |
498 | QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings |
499 | QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift |
500 | + QUERY_STYLE_PROPERTY_WRITINGMODES, // writing-mode, text-orientation |
501 | QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity |
502 | QUERY_STYLE_PROPERTY_BLEND, // blend |
503 | QUERY_STYLE_PROPERTY_BLUR // blur |
504 | |
505 | === modified file 'src/display/nr-style.cpp' |
506 | --- src/display/nr-style.cpp 2014-12-23 09:25:08 +0000 |
507 | +++ src/display/nr-style.cpp 2015-11-24 09:40:36 +0000 |
508 | @@ -68,7 +68,6 @@ |
509 | , tspan_width(0) |
510 | , ascender(0) |
511 | , descender(0) |
512 | - , line_gap(0) |
513 | , underline_thickness(0) |
514 | , underline_position(0) |
515 | , line_through_thickness(0) |
516 | @@ -330,7 +329,6 @@ |
517 | tspan_width = style->text_decoration_data.tspan_width; |
518 | ascender = style->text_decoration_data.ascender; |
519 | descender = style->text_decoration_data.descender; |
520 | - line_gap = style->text_decoration_data.line_gap; |
521 | underline_thickness = style->text_decoration_data.underline_thickness; |
522 | underline_position = style->text_decoration_data.underline_position; |
523 | line_through_thickness = style->text_decoration_data.line_through_thickness; |
524 | |
525 | === modified file 'src/display/nr-style.h' |
526 | --- src/display/nr-style.h 2014-12-21 14:29:02 +0000 |
527 | +++ src/display/nr-style.h 2015-11-24 09:40:36 +0000 |
528 | @@ -115,7 +115,6 @@ |
529 | float tspan_width; |
530 | float ascender; |
531 | float descender; |
532 | - float line_gap; |
533 | float underline_thickness; |
534 | float underline_position; |
535 | float line_through_thickness; |
536 | |
537 | === modified file 'src/libnrtype/FontInstance.cpp' |
538 | --- src/libnrtype/FontInstance.cpp 2014-10-06 00:18:46 +0000 |
539 | +++ src/libnrtype/FontInstance.cpp 2015-11-24 09:40:36 +0000 |
540 | @@ -21,6 +21,7 @@ |
541 | #include FT_BBOX_H |
542 | #include FT_TRUETYPE_TAGS_H |
543 | #include FT_TRUETYPE_TABLES_H |
544 | +#include FT_GLYPH_H |
545 | #include <pango/pangoft2.h> |
546 | #include <2geom/pathvector.h> |
547 | #include <2geom/path-sink.h> |
548 | @@ -183,6 +184,20 @@ |
549 | theFace(0) |
550 | { |
551 | //printf("font instance born\n"); |
552 | + _ascent = _ascent_max = 0.8; |
553 | + _descent = _descent_max = 0.2; |
554 | + _xheight = 0.5; |
555 | + |
556 | + // Default baseline values, alphabetic is reference |
557 | + _baselines[ SP_CSS_BASELINE_AUTO ] = 0.0; |
558 | + _baselines[ SP_CSS_BASELINE_ALPHABETIC ] = 0.0; |
559 | + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; |
560 | + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; |
561 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; |
562 | + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; |
563 | + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; |
564 | + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; |
565 | + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; |
566 | } |
567 | |
568 | font_instance::~font_instance(void) |
569 | @@ -259,6 +274,7 @@ |
570 | FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol); |
571 | } |
572 | #endif |
573 | + FindFontMetrics(); |
574 | } |
575 | } |
576 | |
577 | @@ -374,10 +390,10 @@ |
578 | GLYPHMETRICS metrics; |
579 | DWORD bufferSize=GetGlyphOutline (parent->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); |
580 | double scale=1.0/parent->fontSize; |
581 | - n_g.h_advance=metrics.gmCellIncX*scale; |
582 | - n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; |
583 | - n_g.h_width=metrics.gmBlackBoxX*scale; |
584 | - n_g.v_width=metrics.gmBlackBoxY*scale; |
585 | + n_g.h_advance = metrics.gmCellIncX * scale; |
586 | + n_g.v_advance = otm.otmTextMetrics.tmHeight * scale; |
587 | + n_g.h_width = metrics.gmBlackBoxX * scale; |
588 | + n_g.v_width = metrics.gmBlackBoxY * scale; |
589 | if ( bufferSize == GDI_ERROR) { |
590 | // shit happened |
591 | } else if ( bufferSize == 0) { |
592 | @@ -459,7 +475,13 @@ |
593 | n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM); |
594 | n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM); |
595 | } else { |
596 | - n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM); |
597 | + // CSS3 Writing modes dictates that if vertical font metrics are missing we must |
598 | + // synthisize them. No method is specified. The SVG 1.1 spec suggests using the em |
599 | + // height (which is not theFace->height as that includes leading). The em height |
600 | + // is ascender + descender (descender positive). Note: The "Requirements for |
601 | + // Japanese Text Layout" W3C document says that Japanese kanji should be "set |
602 | + // solid" which implies that vertical (and horizontal) advance should be 1em. |
603 | + n_g.v_width=n_g.v_advance= 1.0; |
604 | } |
605 | if ( theFace->glyph->format == ft_glyph_format_outline ) { |
606 | FT_Outline_Funcs ft2_outline_funcs = { |
607 | @@ -501,7 +523,7 @@ |
608 | } |
609 | } |
610 | |
611 | -bool font_instance::FontMetrics(double &ascent,double &descent,double &leading) |
612 | +bool font_instance::FontMetrics(double &ascent,double &descent,double &xheight) |
613 | { |
614 | if ( pFont == NULL ) { |
615 | return false; |
616 | @@ -510,32 +532,17 @@ |
617 | if ( theFace == NULL ) { |
618 | return false; |
619 | } |
620 | -#ifdef USE_PANGO_WIN32 |
621 | - OUTLINETEXTMETRIC otm; |
622 | - if ( !GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) { |
623 | - return false; |
624 | - } |
625 | - double scale=1.0/parent->fontSize; |
626 | - ascent=fabs(otm.otmAscent*scale); |
627 | - descent=fabs(otm.otmDescent*scale); |
628 | - leading=fabs(otm.otmLineGap*scale); |
629 | - //otmSubscriptSize, otmSubscriptOffset, otmSuperscriptSize, otmSuperscriptOffset, |
630 | -#else |
631 | - if ( theFace->units_per_EM == 0 ) { |
632 | - return false; // bitmap font |
633 | - } |
634 | - ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM)); |
635 | - descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM)); |
636 | - leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM)); |
637 | - leading-=ascent+descent; |
638 | -#endif |
639 | + |
640 | + ascent = _ascent; |
641 | + descent = _descent; |
642 | + xheight = _xheight; |
643 | + |
644 | return true; |
645 | } |
646 | |
647 | -bool font_instance::FontDecoration( |
648 | - double &underline_position, double &underline_thickness, |
649 | - double &linethrough_position, double &linethrough_thickness |
650 | -){ |
651 | +bool font_instance::FontDecoration( double &underline_position, double &underline_thickness, |
652 | + double &linethrough_position, double &linethrough_thickness) |
653 | +{ |
654 | if ( pFont == NULL ) { |
655 | return false; |
656 | } |
657 | @@ -662,6 +669,179 @@ |
658 | return 0; |
659 | } |
660 | |
661 | +// Internal function to find baselines |
662 | +void font_instance::FindFontMetrics() { |
663 | + |
664 | + // CSS2 recommends using the OS/2 values sTypoAscender and sTypoDescender for the Typographic |
665 | + // ascender and descender values: |
666 | + // http://www.w3.org/TR/CSS2/visudet.html#sTypoAscender |
667 | + // On Windows, the typographic ascender and descender are taken from the otmMacAscent and |
668 | + // otmMacDescent values: |
669 | + // http://microsoft.public.win32.programmer.gdi.narkive.com/LV6k4BDh/msdn-documentation-outlinetextmetrics-clarification |
670 | + // The otmAscent and otmDescent values are the maxiumum ascent and maxiumum descent of all the |
671 | + // glyphs in a font. |
672 | + if ( theFace ) { |
673 | + |
674 | +#ifdef USE_PANGO_WIN32 |
675 | + |
676 | + if ( GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) { |
677 | + double scale=1.0/parent->fontSize; |
678 | + _ascent = fabs(otm.otmMacAscent * scale); |
679 | + _descent = fabs(otm.otmMacDescent * scale); |
680 | + _xheight = fabs(otm.otmXHeight * scale); |
681 | + _ascent_max = fabs(otm.otmAscent * scale); |
682 | + _descent_max = fabs(otm.otmDescent * scale); |
683 | + |
684 | + // In CSS em size is ascent + descent... which should be 1. If not, |
685 | + // adjust so it is. |
686 | + double em = _ascent + _descent; |
687 | + if( em > 0 ) { |
688 | + _ascent /= em; |
689 | + _descent /= em; |
690 | + } |
691 | + |
692 | + // May not be necessary but if OS/2 table missing or not version 2 or higher, |
693 | + // xheight might be zero. |
694 | + if( _xheight == 0.0 ) { |
695 | + _xheight = 0.5; |
696 | + } |
697 | + |
698 | + // Baselines defined relative to alphabetic. |
699 | + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation |
700 | + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess |
701 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess |
702 | + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition |
703 | + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition |
704 | + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition |
705 | + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition |
706 | + |
707 | + |
708 | + MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; |
709 | + GLYPHMETRICS metrics; |
710 | + int retval; |
711 | + |
712 | + // Better math baseline: |
713 | + // Try center of minus sign |
714 | + retval = GetGlyphOutline (parent->hScreenDC, 0x2212, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); |
715 | + // If no minus sign, try hyphen |
716 | + if( retval <= 0 ) |
717 | + retval = GetGlyphOutline (parent->hScreenDC, '-', GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); |
718 | + |
719 | + if( retval > 0 ) { |
720 | + double math = (metrics.gmptGlyphOrigin.y + 0.5 * metrics.gmBlackBoxY) * scale; |
721 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math; |
722 | + } |
723 | + |
724 | + // Find hanging baseline... assume it is at top of 'म'. |
725 | + retval = GetGlyphOutline (parent->hScreenDC, 0x092E, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); |
726 | + if( retval > 0 ) { |
727 | + double hanging = metrics.gmptGlyphOrigin.y * scale; |
728 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = hanging; |
729 | + } |
730 | + } |
731 | + |
732 | +#else |
733 | + |
734 | + if ( theFace->units_per_EM != 0 ) { // If zero then it's a bitmap font. |
735 | + |
736 | + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table( theFace, FT_SFNT_OS2 ); |
737 | + if( os2 ) { |
738 | + _ascent = fabs(((double)os2->sTypoAscender) / ((double)theFace->units_per_EM)); |
739 | + _descent = fabs(((double)os2->sTypoDescender)/ ((double)theFace->units_per_EM)); |
740 | + } else { |
741 | + _ascent = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM)); |
742 | + _descent = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM)); |
743 | + } |
744 | + _ascent_max = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM)); |
745 | + _descent_max = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM)); |
746 | + |
747 | + // In CSS em size is ascent + descent... which should be 1. If not, |
748 | + // adjust so it is. |
749 | + double em = _ascent + _descent; |
750 | + if( em > 0 ) { |
751 | + _ascent /= em; |
752 | + _descent /= em; |
753 | + } |
754 | + |
755 | + // x-height |
756 | + if( os2 && os2->version >= 0x0002 && os2->version != 0xffffu ) { |
757 | + // Only os/2 version 2 and above have sxHeight, 0xffff marks "old Mac fonts" without table |
758 | + _xheight = fabs(((double)os2->sxHeight) / ((double)theFace->units_per_EM)); |
759 | + } else { |
760 | + // Measure 'x' height in font. Recommended option by XSL standard if no sxHeight. |
761 | + FT_UInt index = FT_Get_Char_Index( theFace, 'x' ); |
762 | + if( index != 0 ) { |
763 | + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); |
764 | + _xheight = (fabs)(((double)theFace->glyph->metrics.height/(double)theFace->units_per_EM)); |
765 | + } else { |
766 | + // No 'x' in font! |
767 | + _xheight = 0.5; |
768 | + } |
769 | + } |
770 | + |
771 | + // Baselines defined relative to alphabetic. |
772 | + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation |
773 | + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess |
774 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess |
775 | + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition |
776 | + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition |
777 | + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition |
778 | + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition |
779 | + |
780 | + // Better math baseline: |
781 | + // Try center of minus sign |
782 | + FT_UInt index = FT_Get_Char_Index( theFace, 0x2212 ); //'−' |
783 | + // If no minus sign, try hyphen |
784 | + if( index == 0 ) |
785 | + index = FT_Get_Char_Index( theFace, '-' ); |
786 | + |
787 | + if( index != 0 ) { |
788 | + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); |
789 | + FT_Glyph aglyph; |
790 | + FT_Get_Glyph( theFace->glyph, &aglyph ); |
791 | + FT_BBox acbox; |
792 | + FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox ); |
793 | + double math = (acbox.yMin + acbox.yMax)/2.0/(double)theFace->units_per_EM; |
794 | + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math; |
795 | + // std::cout << "Math baseline: - bbox: y_min: " << acbox.yMin |
796 | + // << " y_max: " << acbox.yMax |
797 | + // << " math: " << math << std::endl; |
798 | + } |
799 | + |
800 | + // Find hanging baseline... assume it is at top of 'म'. |
801 | + index = FT_Get_Char_Index( theFace, 0x092E ); // 'म' |
802 | + if( index != 0 ) { |
803 | + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); |
804 | + FT_Glyph aglyph; |
805 | + FT_Get_Glyph( theFace->glyph, &aglyph ); |
806 | + FT_BBox acbox; |
807 | + FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox ); |
808 | + double hanging = (double)acbox.yMax/(double)theFace->units_per_EM; |
809 | + _baselines[ SP_CSS_BASELINE_HANGING ] = hanging; |
810 | + // std::cout << "Hanging baseline: प: " << hanging << std::endl; |
811 | + } |
812 | + } |
813 | +#endif |
814 | + // const gchar *family = pango_font_description_get_family(descr); |
815 | + // std::cout << "Font: " << (family?family:"null") << std::endl; |
816 | + // std::cout << " ascent: " << _ascent << std::endl; |
817 | + // std::cout << " descent: " << _descent << std::endl; |
818 | + // std::cout << " x-height: " << _xheight << std::endl; |
819 | + // std::cout << " max ascent: " << _ascent_max << std::endl; |
820 | + // std::cout << " max descent: " << _descent_max << std::endl; |
821 | + // std::cout << " Baselines:" << std::endl; |
822 | + // std::cout << " alphabetic: " << _baselines[ SP_CSS_BASELINE_ALPHABETIC ] << std::endl; |
823 | + // std::cout << " ideographic: " << _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] << std::endl; |
824 | + // std::cout << " hanging: " << _baselines[ SP_CSS_BASELINE_HANGING ] << std::endl; |
825 | + // std::cout << " math: " << _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] << std::endl; |
826 | + // std::cout << " central: " << _baselines[ SP_CSS_BASELINE_CENTRAL ] << std::endl; |
827 | + // std::cout << " middle: " << _baselines[ SP_CSS_BASELINE_MIDDLE ] << std::endl; |
828 | + // std::cout << " text_before: " << _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] << std::endl; |
829 | + // std::cout << " text_after: " << _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] << std::endl; |
830 | + } |
831 | +} |
832 | + |
833 | + |
834 | /* |
835 | Local Variables: |
836 | mode:c++ |
837 | |
838 | === modified file 'src/libnrtype/Layout-TNG-Compute.cpp' |
839 | --- src/libnrtype/Layout-TNG-Compute.cpp 2015-10-12 11:48:06 +0000 |
840 | +++ src/libnrtype/Layout-TNG-Compute.cpp 2015-11-24 09:40:36 +0000 |
841 | @@ -23,33 +23,6 @@ |
842 | |
843 | #define TRACE(_args) IFTRACE(g_print _args) |
844 | |
845 | -// ******* enum conversion tables |
846 | - |
847 | -// These enums are probably from the SVG 1.0 era where one could interpret 'writing-mode' as setting direction. |
848 | -// SVG 1.1 makes it clear that 'direction' should be used. 'direction' has only two values 'ltr' and 'rtl'. |
849 | -// The first two values for the 'writing-mode' enum just happen to match the first two value of 'direction' so the |
850 | -// existing code worked when 'writing-mode' was changed to 'direction'. |
851 | -// static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_pango_direction[] = { |
852 | -// {SP_CSS_WRITING_MODE_LR_TB, PANGO_DIRECTION_LTR}, |
853 | -// {SP_CSS_WRITING_MODE_RL_TB, PANGO_DIRECTION_RTL}, |
854 | -// {SP_CSS_WRITING_MODE_TB_LR, PANGO_DIRECTION_LTR}}; // this is correct |
855 | - |
856 | -// static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_my_direction[] = { |
857 | -// {SP_CSS_WRITING_MODE_LR_TB, Layout::LEFT_TO_RIGHT}, |
858 | -// {SP_CSS_WRITING_MODE_RL_TB, Layout::RIGHT_TO_LEFT}, |
859 | -// {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}}; // this is correct |
860 | - |
861 | -// Proper 'direction' enums |
862 | -static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_pango_direction[] = { |
863 | - {SP_CSS_DIRECTION_LTR, PANGO_DIRECTION_LTR}, |
864 | - {SP_CSS_DIRECTION_RTL, PANGO_DIRECTION_RTL}}; |
865 | - |
866 | -static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_my_direction[] = { |
867 | - {SP_CSS_DIRECTION_LTR, Layout::LEFT_TO_RIGHT}, |
868 | - {SP_CSS_DIRECTION_RTL, Layout::RIGHT_TO_LEFT}}; |
869 | - |
870 | - |
871 | - |
872 | /** \brief private to Layout. Does the real work of text flowing. |
873 | |
874 | This class does a standard greedy paragraph wrapping algorithm. |
875 | @@ -140,9 +113,10 @@ |
876 | unsigned input_index; /// index into Layout::_input_stream |
877 | Glib::ustring::const_iterator input_stream_first_character; |
878 | double font_size; |
879 | - LineHeight line_height; /// This is not the CSS line-height attribute! |
880 | + FontMetrics line_height; /// This is not the CSS line-height attribute! |
881 | double line_height_multiplier; /// calculated from the font-height css property |
882 | double baseline_shift; /// calculated from the baseline-shift css property |
883 | + SPCSSTextOrientation text_orientation; |
884 | unsigned text_bytes; |
885 | unsigned char_index_in_para; /// the index of the first character in this span in the paragraph, for looking up char_attributes |
886 | SVGLength x, y, dx, dy, rotate; // these are reoriented copies of the <tspan> attributes. We change span when we encounter one. |
887 | @@ -220,9 +194,8 @@ |
888 | |
889 | void _buildPangoItemizationForPara(ParagraphInfo *para) const; |
890 | |
891 | - static void _computeFontLineHeight(font_instance *font, double font_size, |
892 | - SPStyle const *style, LineHeight *line_height, |
893 | - double *line_height_multiplier); |
894 | + // Returns line_height_multiplier |
895 | + static double _computeFontLineHeight( SPStyle const *style ); |
896 | |
897 | unsigned _buildSpansForPara(ParagraphInfo *para) const; |
898 | |
899 | @@ -270,7 +243,7 @@ |
900 | bool _goToNextWrapShape(); |
901 | |
902 | bool _findChunksForLine(ParagraphInfo const ¶, UnbrokenSpanPosition *start_span_pos, |
903 | - std::vector<ChunkInfo> *chunk_info, LineHeight *line_height); |
904 | + std::vector<ChunkInfo> *chunk_info, FontMetrics *line_height); |
905 | |
906 | static inline PangoLogAttr const &_charAttributes(ParagraphInfo const ¶, |
907 | UnbrokenSpanPosition const &span_pos) |
908 | @@ -282,7 +255,7 @@ |
909 | UnbrokenSpanPosition const &start_span_pos, |
910 | ScanlineMaker::ScanRun const &scan_run, |
911 | std::vector<ChunkInfo> *chunk_info, |
912 | - LineHeight *line_height) const; |
913 | + FontMetrics *line_height) const; |
914 | |
915 | /** computes the width of a single UnbrokenSpan (pointed to by span->start.iter_span) |
916 | and outputs its vital statistics into the other fields of \a span. |
917 | @@ -300,8 +273,11 @@ |
918 | span->setZero(); |
919 | |
920 | if (span->start.iter_span->dx._set && span->start.char_byte == 0){ |
921 | - if(para.direction == RIGHT_TO_LEFT){ span->width -= span->start.iter_span->dx.computed; } |
922 | - else { span->width += span->start.iter_span->dx.computed; } |
923 | + if(para.direction == RIGHT_TO_LEFT){ |
924 | + span->width -= span->start.iter_span->dx.computed; |
925 | + } else { |
926 | + span->width += span->start.iter_span->dx.computed; |
927 | + } |
928 | } |
929 | |
930 | if (span->start.iter_span->pango_item_index == -1) { |
931 | @@ -382,10 +358,22 @@ |
932 | double char_width = 0.0; |
933 | while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs |
934 | && span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) { |
935 | - if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) |
936 | - char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); |
937 | - else |
938 | + if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { |
939 | + // Vertical text |
940 | + |
941 | + if( text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || |
942 | + (text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED && |
943 | + para.pango_items[span->end.iter_span->pango_item_index].item->analysis.gravity == 0) ) { |
944 | + // Sideways orientation |
945 | + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, false); |
946 | + } else { |
947 | + // Upright orientation |
948 | + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); |
949 | + } |
950 | + } else { |
951 | + // Horizontal text |
952 | char_width += font_size_multiplier * span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].geometry.width; |
953 | + } |
954 | span->end_glyph_index++; |
955 | } |
956 | if (char_attributes.is_cursor_position) |
957 | @@ -474,7 +462,7 @@ |
958 | are ready to output the final result to #_flow. This method takes its |
959 | input parameters and does that. |
960 | */ |
961 | - void _outputLine(ParagraphInfo const ¶, LineHeight const &line_height, std::vector<ChunkInfo> const &chunk_info) |
962 | + void _outputLine(ParagraphInfo const ¶, FontMetrics const &line_height, std::vector<ChunkInfo> const &chunk_info) |
963 | { |
964 | TRACE(("Start _outputLine\n")); |
965 | if (chunk_info.empty()) { |
966 | @@ -486,7 +474,17 @@ |
967 | TRACE(("found line fit; creating output\n")); |
968 | Layout::Line new_line; |
969 | new_line.in_paragraph = _flow._paragraphs.size() - 1; |
970 | - new_line.baseline_y = _scanline_maker->yCoordinate() + line_height.ascent; |
971 | + new_line.baseline_y = _scanline_maker->yCoordinate(); |
972 | + if( !_flow._input_wrap_shapes.empty() ) { |
973 | + // Flowed text |
974 | + if( _block_progression == RIGHT_TO_LEFT || _block_progression == LEFT_TO_RIGHT ) { |
975 | + // Vertical text, use em box center as baseline |
976 | + new_line.baseline_y += 0.5 * line_height.emSize(); |
977 | + } else { |
978 | + new_line.baseline_y += line_height.getTypoAscent(); |
979 | + } |
980 | + } |
981 | + |
982 | new_line.in_shape = _current_shape_index; |
983 | _flow._lines.push_back(new_line); |
984 | |
985 | @@ -527,17 +525,16 @@ |
986 | // If <tspan> "y" attribute is set, use it (initial "y" attributes in |
987 | // <tspans> other than the first have already been stripped for <tspans> |
988 | // marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput). |
989 | + // NOTE: for vertical text, "y" is the user-space "x" value. |
990 | if( it_chunk->broken_spans.front().start.iter_span->y._set ) { |
991 | |
992 | // Use set "y" attribute |
993 | new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed; |
994 | - |
995 | // Save baseline |
996 | _flow._lines.back().baseline_y = new_line.baseline_y; |
997 | |
998 | - // Save new <tspan> y coordinate |
999 | - _scanline_maker->setNewYCoordinate(new_line.baseline_y - line_height.ascent); |
1000 | - |
1001 | + // Set the initial y coordinate of the next line. |
1002 | + _scanline_maker->setNewYCoordinate(new_line.baseline_y); |
1003 | } |
1004 | |
1005 | // Reset relative y_offset ("dy" attribute is relative but should be reset at |
1006 | @@ -556,21 +553,21 @@ |
1007 | } |
1008 | _flow._chunks.push_back(new_chunk); |
1009 | |
1010 | - double x; |
1011 | + double current_x; |
1012 | double direction_sign; |
1013 | Direction previous_direction = para.direction; |
1014 | double counter_directional_width_remaining = 0.0; |
1015 | float glyph_rotate = 0.0; |
1016 | if (para.direction == LEFT_TO_RIGHT) { |
1017 | direction_sign = +1.0; |
1018 | - x = 0.0; |
1019 | + current_x = 0.0; |
1020 | } else { |
1021 | direction_sign = -1.0; |
1022 | if (para.alignment == FULL && !_flow._input_wrap_shapes.empty()){ |
1023 | - x = it_chunk->scanrun_width; |
1024 | + current_x = it_chunk->scanrun_width; |
1025 | } |
1026 | else { |
1027 | - x = it_chunk->text_width; |
1028 | + current_x = it_chunk->text_width; |
1029 | } |
1030 | } |
1031 | |
1032 | @@ -583,7 +580,7 @@ |
1033 | if (it_span->start.char_byte == 0) { |
1034 | // Start of an unbroken span, we might have dx, dy or rotate still to process |
1035 | // (x and y are done per chunk) |
1036 | - if (unbroken_span.dx._set) x += unbroken_span.dx.computed; |
1037 | + if (unbroken_span.dx._set) current_x += unbroken_span.dx.computed; |
1038 | if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed; |
1039 | if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180); |
1040 | } |
1041 | @@ -601,6 +598,7 @@ |
1042 | new_span.in_input_stream_item = unbroken_span.input_index; |
1043 | new_span.baseline_shift = 0.0; |
1044 | new_span.block_progression = _block_progression; |
1045 | + new_span.text_orientation = unbroken_span.text_orientation; |
1046 | if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font)) |
1047 | { |
1048 | new_span.font->Ref(); |
1049 | @@ -609,12 +607,12 @@ |
1050 | new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte); |
1051 | } else { // a control code |
1052 | new_span.font = NULL; |
1053 | - new_span.font_size = new_span.line_height.ascent + new_span.line_height.descent; |
1054 | + new_span.font_size = new_span.line_height.emSize(); |
1055 | new_span.direction = para.direction; |
1056 | } |
1057 | |
1058 | if (new_span.direction == para.direction) { |
1059 | - x -= counter_directional_width_remaining; |
1060 | + current_x -= counter_directional_width_remaining; |
1061 | counter_directional_width_remaining = 0.0; |
1062 | } else if (new_span.direction != previous_direction) { |
1063 | // measure width of spans we need to switch round |
1064 | @@ -630,10 +628,10 @@ |
1065 | } |
1066 | counter_directional_width_remaining += direction_sign * (it_following_span->width + it_following_span->whitespace_count * add_to_each_whitespace); |
1067 | } |
1068 | - x += counter_directional_width_remaining; |
1069 | + current_x += counter_directional_width_remaining; |
1070 | counter_directional_width_remaining = 0.0; // we want to go increasingly negative |
1071 | } |
1072 | - new_span.x_start = x; |
1073 | + new_span.x_start = current_x; |
1074 | |
1075 | if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) { |
1076 | // the span is set up, push the glyphs and chars |
1077 | @@ -673,10 +671,12 @@ |
1078 | } |
1079 | |
1080 | // create the Layout::Glyph |
1081 | + PangoGlyphInfo *unbroken_span_glyph_info = &unbroken_span.glyph_string->glyphs[glyph_index]; |
1082 | Layout::Glyph new_glyph; |
1083 | - new_glyph.glyph = unbroken_span.glyph_string->glyphs[glyph_index].glyph; |
1084 | + new_glyph.glyph = unbroken_span_glyph_info->glyph; |
1085 | new_glyph.in_character = _flow._characters.size(); |
1086 | new_glyph.rotation = glyph_rotate; |
1087 | + new_glyph.orientation = ORIENTATION_UPRIGHT; // Only effects vertical text |
1088 | |
1089 | // We may have scaled font size to fit textLength; now, if |
1090 | // @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal, |
1091 | @@ -686,30 +686,68 @@ |
1092 | else |
1093 | new_glyph.vertical_scale = 1.0; |
1094 | |
1095 | - /* put something like this back in when we do glyph-rotation-horizontal/vertical |
1096 | - if (new_span.block_progression == LEFT_TO_RIGHT || new_span.block_progression == RIGHT_TO_LEFT) { |
1097 | - new_glyph.x += new_span.line_height.ascent; |
1098 | - new_glyph.y -= unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier * 0.5; |
1099 | - new_glyph.width = new_span.line_height.ascent + new_span.line_height.descent; |
1100 | - } else */ |
1101 | + // Position glyph -------------------- |
1102 | + new_glyph.x = current_x + unbroken_span_glyph_info->geometry.x_offset * font_size_multiplier; |
1103 | + new_glyph.y =_y_offset; |
1104 | + |
1105 | + // y-coordinate is flipped between vertical and horizontal text... delta_y is common offset but applied with opposite sign |
1106 | + double delta_y = unbroken_span_glyph_info->geometry.y_offset * font_size_multiplier + unbroken_span.baseline_shift; |
1107 | + SPCSSBaseline dominant_baseline = _flow._blockBaseline(); |
1108 | |
1109 | if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { |
1110 | - new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier + new_span.line_height.ascent; |
1111 | - new_glyph.y = _y_offset - |
1112 | - unbroken_span.baseline_shift + |
1113 | - (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset - |
1114 | - unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier; |
1115 | - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, true); |
1116 | + // Vertical text |
1117 | + |
1118 | + // Default dominant baseline is determined by overall block (i.e. <text>) 'text-orientation' value. |
1119 | + if( _flow._blockTextOrientation() != SP_CSS_TEXT_ORIENTATION_SIDEWAYS ) { |
1120 | + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_CENTRAL; |
1121 | + } else { |
1122 | + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; |
1123 | + } |
1124 | + |
1125 | + new_glyph.y += delta_y; |
1126 | + |
1127 | + // TODO: Should also check 'glyph_orientation_vertical' if 'text-orientation' is unset... |
1128 | + if( new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || |
1129 | + (new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_MIXED && |
1130 | + para.pango_items[unbroken_span.pango_item_index].item->analysis.gravity == 0) ) { |
1131 | + |
1132 | + // Sideways orientation (Latin characters, CJK punctuation), 90deg rotation done at output stage. zzzzzzz |
1133 | + new_glyph.orientation = ORIENTATION_SIDEWAYS; |
1134 | + |
1135 | + new_glyph.y -= new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; |
1136 | + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); |
1137 | + |
1138 | + } else { |
1139 | + // Upright orientation |
1140 | + |
1141 | + new_glyph.x += new_span.line_height.ascent; |
1142 | + |
1143 | + // Glyph reference point is center (shift: left edge to center glyph) |
1144 | + new_glyph.y -= unbroken_span_glyph_info->geometry.width * 0.5 * font_size_multiplier; |
1145 | + new_glyph.y -= new_span.font_size * (para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ] - |
1146 | + para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ SP_CSS_BASELINE_CENTRAL ] ); |
1147 | + |
1148 | + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, true); |
1149 | + if( new_glyph.width == 0 ) { |
1150 | + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; |
1151 | + } |
1152 | + |
1153 | + } |
1154 | } else { |
1155 | - new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier; |
1156 | - new_glyph.y = _y_offset - |
1157 | - unbroken_span.baseline_shift + |
1158 | - unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier; |
1159 | - new_glyph.width = unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier; |
1160 | + // Horizontal text |
1161 | + |
1162 | + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; |
1163 | + |
1164 | + new_glyph.y -= delta_y; |
1165 | + new_glyph.y += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; |
1166 | + |
1167 | + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; |
1168 | if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font)) |
1169 | - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, false); |
1170 | + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); |
1171 | // for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info |
1172 | } |
1173 | + |
1174 | + |
1175 | if (new_span.direction == RIGHT_TO_LEFT) { |
1176 | // pango wanted to give us glyphs in visual order but we refused, so we need to work |
1177 | // out where the cluster start is ourselves |
1178 | @@ -718,13 +756,15 @@ |
1179 | if (unbroken_span.glyph_string->glyphs[rtl_index].attr.is_cluster_start && rtl_index != glyph_index) |
1180 | break; |
1181 | if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) |
1182 | + // Vertical text |
1183 | cluster_width += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[rtl_index].glyph, true); |
1184 | else |
1185 | + // Horizontal text |
1186 | cluster_width += font_size_multiplier * unbroken_span.glyph_string->glyphs[rtl_index].geometry.width; |
1187 | } |
1188 | new_glyph.x -= cluster_width; |
1189 | } |
1190 | - _flow._glyphs.push_back(new_glyph); |
1191 | + _flow._glyphs.push_back(new_glyph); |
1192 | |
1193 | // create the Layout::Character(s) |
1194 | double advance_width = new_glyph.width; |
1195 | @@ -781,15 +821,15 @@ |
1196 | advance_width *= direction_sign; |
1197 | if (new_span.direction != para.direction) { |
1198 | counter_directional_width_remaining -= advance_width; |
1199 | - x -= advance_width; |
1200 | + current_x -= advance_width; |
1201 | x_in_span_last -= advance_width; |
1202 | } else { |
1203 | - x += advance_width; |
1204 | + current_x += advance_width; |
1205 | x_in_span_last += advance_width; |
1206 | } |
1207 | } |
1208 | } else if (_flow._input_stream[unbroken_span.input_index]->Type() == CONTROL_CODE) { |
1209 | - x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width; |
1210 | + current_x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width; |
1211 | } |
1212 | |
1213 | new_span.x_end = new_span.x_start + x_in_span_last; |
1214 | @@ -978,6 +1018,7 @@ |
1215 | #if PANGO_VERSION_CHECK(1,37,1) |
1216 | TRACE((" ... compiled for font features\n")); |
1217 | #endif |
1218 | + |
1219 | Glib::ustring para_text; |
1220 | PangoAttrList *attributes_list; |
1221 | unsigned input_index; |
1222 | @@ -999,10 +1040,10 @@ |
1223 | } else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE) { |
1224 | Layout::InputStreamTextSource *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[input_index]); |
1225 | |
1226 | - // create the font_instance |
1227 | - font_instance *font = text_source->styleGetFontInstance(); |
1228 | - if (font == NULL) |
1229 | - continue; // bad news: we'll have to ignore all this text because we know of no font to render it |
1230 | + // create the font_instance |
1231 | + font_instance *font = text_source->styleGetFontInstance(); |
1232 | + if (font == NULL) |
1233 | + continue; // bad news: we'll have to ignore all this text because we know of no font to render it |
1234 | |
1235 | PangoAttribute *attribute_font_description = pango_attr_font_desc_new(font->descr); |
1236 | attribute_font_description->start_index = para_text.bytes(); |
1237 | @@ -1028,25 +1069,22 @@ |
1238 | |
1239 | TRACE(("whole para: \"%s\"\n", para_text.data())); |
1240 | TRACE(("%d input sources used\n", input_index - para->first_input_index)); |
1241 | - |
1242 | // do the pango_itemize() |
1243 | GList *pango_items_glist = NULL; |
1244 | + para->direction = LEFT_TO_RIGHT; // CSS default |
1245 | if (_flow._input_stream[para->first_input_index]->Type() == TEXT_SOURCE) { |
1246 | Layout::InputStreamTextSource const *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[para->first_input_index]); |
1247 | - if (text_source->style->direction.set) { |
1248 | - PangoDirection pango_direction = (PangoDirection)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_pango_direction, sizeof(enum_convert_spstyle_direction_to_pango_direction)/sizeof(enum_convert_spstyle_direction_to_pango_direction[0])); |
1249 | - pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); |
1250 | - para->direction = (Layout::Direction)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_my_direction, sizeof(enum_convert_spstyle_direction_to_my_direction)/sizeof(enum_convert_spstyle_direction_to_my_direction[0])); |
1251 | - } |
1252 | + |
1253 | + para->direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; |
1254 | + PangoDirection pango_direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL; |
1255 | + pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); |
1256 | } |
1257 | - if (pango_items_glist == NULL) { // no direction specified, guess it |
1258 | + |
1259 | + if( pango_items_glist == NULL ) { |
1260 | + // Type wasn't TEXT_SOURCE or direction was not set. |
1261 | pango_items_glist = pango_itemize(_pango_context, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); |
1262 | + } |
1263 | |
1264 | - // I think according to the css spec this is wrong and we're never allowed to guess the directionality |
1265 | - // of a paragraph. Need to talk to an rtl speaker. |
1266 | - if (pango_items_glist == NULL || pango_items_glist->data == NULL) para->direction = LEFT_TO_RIGHT; |
1267 | - else para->direction = (((PangoItem*)pango_items_glist->data)->analysis.level & 1) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; |
1268 | - } |
1269 | pango_attr_list_unref(attributes_list); |
1270 | |
1271 | // convert the GList to our vector<> and make the font_instance for each PangoItem at the same time |
1272 | @@ -1070,44 +1108,32 @@ |
1273 | } |
1274 | |
1275 | /** |
1276 | - * Gets the ascent, descent and leading for a font and the alteration that has to be performed |
1277 | - * according to the value specified by the line-height css property. The result of multiplying |
1278 | - * \a line_height by \a line_height_multiplier is the inline box height as specified in css2 |
1279 | - * section 10.8. |
1280 | + * Finds the value of line_height_multiplier given the 'line-height' property. The result of |
1281 | + * multiplying \a l by \a line_height_multiplier is the inline box height as specified in css2 |
1282 | + * section 10.8. http://www.w3.org/TR/CSS2/visudet.html#line-height |
1283 | + * |
1284 | + * The 'computed' value of 'line-height' does not have a consistent meaning. We need to find the |
1285 | + * 'used' value and divide that by the font size. |
1286 | */ |
1287 | -void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font_size, |
1288 | - SPStyle const *style, LineHeight *line_height, |
1289 | - double *line_height_multiplier) |
1290 | +double Layout::Calculator::_computeFontLineHeight( SPStyle const *style ) |
1291 | { |
1292 | - if (font == NULL) { |
1293 | - line_height->setZero(); |
1294 | - *line_height_multiplier = 1.0; |
1295 | - } |
1296 | - else { |
1297 | - font->FontMetrics(line_height->ascent, line_height->descent, line_height->leading); |
1298 | - } |
1299 | - *line_height *= font_size; |
1300 | - |
1301 | // yet another borked SPStyle member that we're going to have to fix ourselves |
1302 | + // We shouldn't need to climb the element tree... |
1303 | for ( ; ; ) { |
1304 | if (style->line_height.set && !style->line_height.inherit) { |
1305 | if (style->line_height.normal) |
1306 | break; |
1307 | switch (style->line_height.unit) { |
1308 | case SP_CSS_UNIT_NONE: |
1309 | - *line_height_multiplier = style->line_height.computed * font_size / line_height->total(); |
1310 | - return; |
1311 | + return style->line_height.computed; |
1312 | case SP_CSS_UNIT_EX: |
1313 | - *line_height_multiplier = style->line_height.value * 0.5 * font_size / line_height->total(); |
1314 | + return style->line_height.value * 0.5; |
1315 | // 0.5 is an approximation of the x-height. Fixme. |
1316 | - return; |
1317 | case SP_CSS_UNIT_EM: |
1318 | case SP_CSS_UNIT_PERCENT: |
1319 | - *line_height_multiplier = style->line_height.value * font_size / line_height->total(); |
1320 | - return; |
1321 | + return style->line_height.value; |
1322 | default: // absolute values |
1323 | - *line_height_multiplier = style->line_height.computed / line_height->total(); |
1324 | - return; |
1325 | + return style->line_height.computed / style->font_size.computed; |
1326 | } |
1327 | break; |
1328 | } |
1329 | @@ -1115,7 +1141,7 @@ |
1330 | style = style->object->parent->style; |
1331 | if (style == NULL) break; |
1332 | } |
1333 | - *line_height_multiplier = LINE_HEIGHT_NORMAL * font_size / line_height->total(); |
1334 | + return (LINE_HEIGHT_NORMAL); |
1335 | } |
1336 | |
1337 | bool compareGlyphWidth(const PangoGlyphInfo &a, const PangoGlyphInfo &b) |
1338 | @@ -1155,7 +1181,6 @@ |
1339 | new_span.input_index = input_index; |
1340 | new_span.line_height.ascent = control_code->ascent * _flow.getTextLengthMultiplierDue(); |
1341 | new_span.line_height.descent = control_code->descent * _flow.getTextLengthMultiplierDue(); |
1342 | - new_span.line_height.leading = 0.0; |
1343 | new_span.text_bytes = 0; |
1344 | new_span.char_index_in_para = char_index_in_para; |
1345 | para->unbroken_spans.push_back(new_span); |
1346 | @@ -1194,11 +1219,13 @@ |
1347 | new_span.dy._set = false; |
1348 | new_span.rotate._set = false; |
1349 | if (_block_progression == TOP_TO_BOTTOM || _block_progression == BOTTOM_TO_TOP) { |
1350 | + // Horizontal text |
1351 | if (text_source->x.size() > char_index_in_source) new_span.x = text_source->x[char_index_in_source]; |
1352 | if (text_source->y.size() > char_index_in_source) new_span.y = text_source->y[char_index_in_source]; |
1353 | if (text_source->dx.size() > char_index_in_source) new_span.dx = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); |
1354 | if (text_source->dy.size() > char_index_in_source) new_span.dy = text_source->dy[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); |
1355 | } else { |
1356 | + // Vertical text |
1357 | if (text_source->x.size() > char_index_in_source) new_span.y = text_source->x[char_index_in_source]; |
1358 | if (text_source->y.size() > char_index_in_source) new_span.x = text_source->y[char_index_in_source]; |
1359 | if (text_source->dx.size() > char_index_in_source) new_span.dy = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); |
1360 | @@ -1231,7 +1258,7 @@ |
1361 | } |
1362 | |
1363 | // now we know the length, do some final calculations and add the UnbrokenSpan to the list |
1364 | - new_span.font_size = text_source->styleComputeFontSize() * _flow.getTextLengthMultiplierDue(); |
1365 | + new_span.font_size = text_source->style->font_size.computed * _flow.getTextLengthMultiplierDue(); |
1366 | if (new_span.text_bytes) { |
1367 | new_span.glyph_string = pango_glyph_string_new(); |
1368 | /* Some assertions intended to help diagnose bug #1277746. */ |
1369 | @@ -1240,6 +1267,7 @@ |
1370 | g_assert( span_start_byte_in_source + new_span.text_bytes <= text_source->text->bytes() ); |
1371 | g_assert( memchr(text_source->text->data() + span_start_byte_in_source, '\0', static_cast<size_t>(new_span.text_bytes)) |
1372 | == NULL ); |
1373 | + |
1374 | /* Notes as of 4/29/13. Pango_shape is not generating English language ligatures, but it is generating |
1375 | them for Hebrew (and probably other similar languages). In the case observed 3 unicode characters (a base |
1376 | and 2 Mark, nonspacings) are merged into two glyphs (the base + first Mn, the 2nd Mn). All of these map |
1377 | @@ -1247,6 +1275,8 @@ |
1378 | characters and glyphs. A big chunk of the conditional code which immediately follows this call |
1379 | is there to clean up the resulting mess. |
1380 | */ |
1381 | + |
1382 | + // Convert characters to glyphs |
1383 | pango_shape(text_source->text->data() + span_start_byte_in_source, |
1384 | new_span.text_bytes, |
1385 | ¶->pango_items[pango_item_index].item->analysis, |
1386 | @@ -1324,11 +1354,14 @@ |
1387 | /* glyphs[].x_offset values may be out of order within any log_clusters, apparently harmless */ |
1388 | } |
1389 | new_span.pango_item_index = pango_item_index; |
1390 | - _computeFontLineHeight(para->pango_items[pango_item_index].font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier); |
1391 | + new_span.line_height_multiplier = _computeFontLineHeight( text_source->style ); |
1392 | + new_span.line_height.set( para->pango_items[pango_item_index].font ); |
1393 | + new_span.line_height *= new_span.font_size; |
1394 | |
1395 | // At some point we may want to calculate baseline_shift here (to take advantage |
1396 | // of otm features like superscript baseline), but for now we use style baseline_shift. |
1397 | new_span.baseline_shift = text_source->style->baseline_shift.computed; |
1398 | + new_span.text_orientation = (SPCSSTextOrientation)text_source->style->text_orientation.computed; |
1399 | |
1400 | // TODO: metrics for vertical text |
1401 | TRACE(("add text span %lu \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str())); |
1402 | @@ -1338,11 +1371,13 @@ |
1403 | new_span.pango_item_index = -1; |
1404 | font_instance *font = text_source->styleGetFontInstance(); |
1405 | if (font) { |
1406 | - _computeFontLineHeight(font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier); |
1407 | + new_span.line_height_multiplier = _computeFontLineHeight( text_source->style ); |
1408 | + new_span.line_height.set( font ); |
1409 | + new_span.line_height *= new_span.font_size; |
1410 | font->Unref(); |
1411 | } else { |
1412 | - new_span.line_height.setZero(); |
1413 | - new_span.line_height_multiplier = 1.0; |
1414 | + new_span.line_height *= 0.0; // Set all to zero |
1415 | + new_span.line_height_multiplier = LINE_HEIGHT_NORMAL; |
1416 | } |
1417 | TRACE(("add style init span %lu\n", para->unbroken_spans.size())); |
1418 | } |
1419 | @@ -1399,7 +1434,7 @@ |
1420 | bool Layout::Calculator::_findChunksForLine(ParagraphInfo const ¶, |
1421 | UnbrokenSpanPosition *start_span_pos, |
1422 | std::vector<ChunkInfo> *chunk_info, |
1423 | - LineHeight *line_height) |
1424 | + FontMetrics *line_height) |
1425 | { |
1426 | // init the initial line_height |
1427 | if (start_span_pos->iter_span == para.unbroken_spans.end()) { |
1428 | @@ -1408,9 +1443,9 @@ |
1429 | InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front()); |
1430 | font_instance *font = text_source->styleGetFontInstance(); |
1431 | if (font) { |
1432 | - double font_size = text_source->styleComputeFontSize(); |
1433 | - double multiplier; |
1434 | - _computeFontLineHeight(font, font_size, text_source->style, line_height, &multiplier); |
1435 | + double multiplier = _computeFontLineHeight(text_source->style); |
1436 | + line_height->set( font ); |
1437 | + *line_height *= text_source->style->font_size.computed; |
1438 | font->Unref(); |
1439 | *line_height *= multiplier; |
1440 | _scanline_maker->setNewYCoordinate(_scanline_maker->yCoordinate() - line_height->ascent); |
1441 | @@ -1422,7 +1457,6 @@ |
1442 | // if we're not wrapping set the line_height big and negative so we can use negative line height |
1443 | line_height->ascent = -1.0e10; |
1444 | line_height->descent = -1.0e10; |
1445 | - line_height->leading = -1.0e10; |
1446 | } |
1447 | else |
1448 | line_height->setZero(); |
1449 | @@ -1474,7 +1508,7 @@ |
1450 | UnbrokenSpanPosition const &start_span_pos, |
1451 | ScanlineMaker::ScanRun const &scan_run, |
1452 | std::vector<ChunkInfo> *chunk_info, |
1453 | - LineHeight *line_height) const |
1454 | + FontMetrics *line_height) const |
1455 | { |
1456 | ChunkInfo new_chunk; |
1457 | new_chunk.text_width = 0.0; |
1458 | @@ -1511,16 +1545,17 @@ |
1459 | } |
1460 | |
1461 | // see if this span is too tall to fit on the current line |
1462 | - LineHeight total_height = new_span.start.iter_span->line_height; |
1463 | - total_height *= new_span.start.iter_span->line_height_multiplier; |
1464 | + FontMetrics new_span_height = new_span.start.iter_span->line_height; |
1465 | + new_span_height.computeEffective( new_span.start.iter_span->line_height_multiplier ); |
1466 | /* floating point 80-bit/64-bit rounding problems require epsilon. See |
1467 | discussion http://inkscape.gristle.org/2005-03-16.txt around 22:00 */ |
1468 | - if ( total_height.ascent > line_height->ascent + FLT_EPSILON |
1469 | - || total_height.descent > line_height->descent + FLT_EPSILON |
1470 | - || total_height.leading > line_height->leading + FLT_EPSILON) { |
1471 | - line_height->max(total_height); |
1472 | - if (!_scanline_maker->canExtendCurrentScanline(*line_height)) |
1473 | + if ( new_span_height.ascent > line_height->ascent + FLT_EPSILON || |
1474 | + new_span_height.descent > line_height->descent + FLT_EPSILON) { |
1475 | + // Take larger of each of the two ascents and two descents per CSS |
1476 | + line_height->max(new_span_height); |
1477 | + if (!_scanline_maker->canExtendCurrentScanline(*line_height)) { |
1478 | return false; |
1479 | + } |
1480 | } |
1481 | |
1482 | bool span_fitted = _measureUnbrokenSpan(para, &new_span, &last_span_at_break, &last_span_at_emergency_break, new_chunk.scanrun_width - new_chunk.text_width); |
1483 | @@ -1540,7 +1575,7 @@ |
1484 | TRACE(("chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size())); |
1485 | chunk_info->push_back(new_chunk); |
1486 | |
1487 | - if (scan_run.width() >= 4.0 * line_height->total() && last_span_at_break.end == start_span_pos) { |
1488 | + if (scan_run.width() >= 4.0 * line_height->emSize() && last_span_at_break.end == start_span_pos) { |
1489 | /* **non-SVG spec bit**: See bug #1191102 |
1490 | If the user types a very long line with no spaces, the way the spec |
1491 | is written at the moment means that when the length of the text |
1492 | @@ -1619,14 +1654,27 @@ |
1493 | _flow._clearOutputObjects(); |
1494 | |
1495 | _pango_context = (font_factory::Default())->fontContext; |
1496 | + |
1497 | _font_factory_size_multiplier = (font_factory::Default())->fontSize; |
1498 | |
1499 | + // Reset gravity hint in case it was changed via previous use of 'text-orientation' |
1500 | + // (scripts take their natural gravity given base gravity). |
1501 | + pango_context_set_gravity_hint(_pango_context, PANGO_GRAVITY_HINT_NATURAL); |
1502 | + |
1503 | _block_progression = _flow._blockProgression(); |
1504 | + if( _block_progression == RIGHT_TO_LEFT || _block_progression == LEFT_TO_RIGHT ) { |
1505 | + // Vertical text, CJK |
1506 | + pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_EAST); |
1507 | + } else { |
1508 | + // Horizontal text |
1509 | + pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_AUTO); |
1510 | + } |
1511 | + |
1512 | _y_offset = 0.0; |
1513 | _createFirstScanlineMaker(); |
1514 | |
1515 | ParagraphInfo para; |
1516 | - LineHeight line_height; // needs to be maintained across paragraphs to be able to deal with blank paras |
1517 | + FontMetrics line_height; // needs to be maintained across paragraphs to be able to deal with blank paras |
1518 | for(para.first_input_index = 0 ; para.first_input_index < _flow._input_stream.size() ; ) { |
1519 | // jump to the next wrap shape if this is a SHAPE_BREAK control code |
1520 | if (_flow._input_stream[para.first_input_index]->Type() == CONTROL_CODE) { |
1521 | @@ -1640,7 +1688,10 @@ |
1522 | if (_scanline_maker == NULL) |
1523 | break; // we're trying to flow past the last wrap shape |
1524 | |
1525 | - _buildPangoItemizationForPara(¶); |
1526 | + // Break things up into little pango units with unique direction, gravity, etc. |
1527 | + _buildPangoItemizationForPara(¶); |
1528 | + |
1529 | + // Do shaping (convert characters to glyphs) |
1530 | unsigned para_end_input_index = _buildSpansForPara(¶); |
1531 | |
1532 | if (_flow._input_stream[para.first_input_index]->Type() == TEXT_SOURCE) |
1533 | @@ -1679,7 +1730,7 @@ |
1534 | Layout::Span new_span; |
1535 | if (_flow._spans.empty()) { |
1536 | new_span.font = NULL; |
1537 | - new_span.font_size = line_height.ascent + line_height.descent; |
1538 | + new_span.font_size = line_height.emSize(); |
1539 | new_span.line_height = line_height; |
1540 | new_span.x_end = 0.0; |
1541 | } else { |
1542 | @@ -1755,19 +1806,16 @@ |
1543 | InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream.front()); |
1544 | |
1545 | font_instance *font = text_source->styleGetFontInstance(); |
1546 | - double font_size = text_source->styleComputeFontSize(); |
1547 | + double font_size = text_source->style->font_size.computed; |
1548 | double caret_slope_run = 0.0, caret_slope_rise = 1.0; |
1549 | - LineHeight line_height; |
1550 | + FontMetrics line_height; |
1551 | if (font) { |
1552 | const_cast<font_instance*>(font)->FontSlope(caret_slope_run, caret_slope_rise); |
1553 | - font->FontMetrics(line_height.ascent, line_height.descent, line_height.leading); |
1554 | + font->FontMetrics(line_height.ascent, line_height.descent, line_height.xheight); |
1555 | line_height *= font_size; |
1556 | font->Unref(); |
1557 | - } else { |
1558 | - line_height.ascent = font_size * 0.85; // random guesses |
1559 | - line_height.descent = font_size * 0.15; |
1560 | - line_height.leading = 0.0; |
1561 | } |
1562 | + |
1563 | double caret_slope = atan2(caret_slope_run, caret_slope_rise); |
1564 | _empty_cursor_shape.height = font_size / cos(caret_slope); |
1565 | _empty_cursor_shape.rotation = caret_slope; |
1566 | @@ -1780,10 +1828,13 @@ |
1567 | ShapeScanlineMaker scanline_maker(_input_wrap_shapes.front().shape, block_progression); |
1568 | std::vector<ScanlineMaker::ScanRun> scan_runs = scanline_maker.makeScanline(line_height); |
1569 | if (!scan_runs.empty()) { |
1570 | - if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) |
1571 | + if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) { |
1572 | + // Vertical text |
1573 | _empty_cursor_shape.position = Geom::Point(scan_runs.front().y + font_size, scan_runs.front().x_start); |
1574 | - else |
1575 | + } else { |
1576 | + // Horizontal text |
1577 | _empty_cursor_shape.position = Geom::Point(scan_runs.front().x_start, scan_runs.front().y + font_size); |
1578 | + } |
1579 | } |
1580 | } |
1581 | } |
1582 | |
1583 | === modified file 'src/libnrtype/Layout-TNG-Input.cpp' |
1584 | --- src/libnrtype/Layout-TNG-Input.cpp 2015-10-15 12:14:01 +0000 |
1585 | +++ src/libnrtype/Layout-TNG-Input.cpp 2015-11-24 09:40:36 +0000 |
1586 | @@ -126,52 +126,6 @@ |
1587 | return conversion_table[0].output; |
1588 | } |
1589 | |
1590 | -// ***** the style format interface |
1591 | -// this doesn't include all accesses to SPStyle, only the ones that are non-trivial |
1592 | - |
1593 | -static const float medium_font_size = 12.0; // more of a default if all else fails than anything else |
1594 | -float Layout::InputStreamTextSource::styleComputeFontSize() const |
1595 | -{ |
1596 | - return style->font_size.computed; |
1597 | - |
1598 | - // in case the computed value's not good enough, here's some manual code held in reserve: |
1599 | - SPStyle const *this_style = style; |
1600 | - float inherit_multiplier = 1.0; |
1601 | - |
1602 | - for ( ; ; ) { |
1603 | - if (this_style->font_size.set && !this_style->font_size.inherit) { |
1604 | - switch (this_style->font_size.type) { |
1605 | - case SP_FONT_SIZE_LITERAL: { |
1606 | - switch(this_style->font_size.literal) { // these multipliers are straight out of the CSS spec |
1607 | - case SP_CSS_FONT_SIZE_XX_SMALL: return medium_font_size * inherit_multiplier * (3.0/5.0); |
1608 | - case SP_CSS_FONT_SIZE_X_SMALL: return medium_font_size * inherit_multiplier * (3.0/4.0); |
1609 | - case SP_CSS_FONT_SIZE_SMALL: return medium_font_size * inherit_multiplier * (8.0/9.0); |
1610 | - default: |
1611 | - case SP_CSS_FONT_SIZE_MEDIUM: return medium_font_size * inherit_multiplier; |
1612 | - case SP_CSS_FONT_SIZE_LARGE: return medium_font_size * inherit_multiplier * (6.0/5.0); |
1613 | - case SP_CSS_FONT_SIZE_X_LARGE: return medium_font_size * inherit_multiplier * (3.0/2.0); |
1614 | - case SP_CSS_FONT_SIZE_XX_LARGE: return medium_font_size * inherit_multiplier * 2.0; |
1615 | - case SP_CSS_FONT_SIZE_SMALLER: inherit_multiplier *= 0.84; break; //not exactly according to spec |
1616 | - case SP_CSS_FONT_SIZE_LARGER: inherit_multiplier *= 1.26; break; //not exactly according to spec |
1617 | - } |
1618 | - break; |
1619 | - } |
1620 | - case SP_FONT_SIZE_PERCENTAGE: { // 'em' units should be in here, but aren't. Fix in style.cpp. |
1621 | - inherit_multiplier *= this_style->font_size.value; |
1622 | - break; |
1623 | - } |
1624 | - case SP_FONT_SIZE_LENGTH: { |
1625 | - return this_style->font_size.value * inherit_multiplier; |
1626 | - } |
1627 | - } |
1628 | - } |
1629 | - if (this_style->object == NULL || this_style->object->parent == NULL) break; |
1630 | - this_style = this_style->object->parent->style; |
1631 | - if (this_style == NULL) break; |
1632 | - } |
1633 | - return medium_font_size * inherit_multiplier; |
1634 | -} |
1635 | - |
1636 | Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const |
1637 | { |
1638 | switch( style->writing_mode.computed ) { |
1639 | @@ -192,6 +146,16 @@ |
1640 | return TOP_TO_BOTTOM; |
1641 | } |
1642 | |
1643 | +SPCSSTextOrientation Layout::InputStreamTextSource::styleGetTextOrientation() const |
1644 | +{ |
1645 | + return ((SPCSSTextOrientation)style->text_orientation.computed); |
1646 | +} |
1647 | + |
1648 | +SPCSSBaseline Layout::InputStreamTextSource::styleGetDominantBaseline() const |
1649 | +{ |
1650 | + return ((SPCSSBaseline)style->dominant_baseline.computed); |
1651 | +} |
1652 | + |
1653 | static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction) |
1654 | { |
1655 | switch (anchor) { |
1656 | |
1657 | === modified file 'src/libnrtype/Layout-TNG-OutIter.cpp' |
1658 | --- src/libnrtype/Layout-TNG-OutIter.cpp 2015-08-17 01:16:35 +0000 |
1659 | +++ src/libnrtype/Layout-TNG-OutIter.cpp 2015-11-24 09:40:36 +0000 |
1660 | @@ -120,7 +120,8 @@ |
1661 | double best_y_range = DBL_MAX; |
1662 | double best_x_range = DBL_MAX; |
1663 | for (chunk_index = 0 ; chunk_index < _chunks.size() ; chunk_index++) { |
1664 | - LineHeight line_height = {0.0, 0.0, 0.0}; |
1665 | + FontMetrics line_height; |
1666 | + line_height *= 0.0; // Set all metrics to zero. |
1667 | double chunk_width = 0.0; |
1668 | for ( ; span_index < _spans.size() && _spans[span_index].in_chunk == chunk_index ; span_index++) { |
1669 | line_height.max(_spans[span_index].line_height); |
1670 | @@ -340,8 +341,8 @@ |
1671 | |
1672 | double baseline_y = _characters[char_index].line(this).baseline_y + _characters[char_index].span(this).baseline_shift; |
1673 | if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { |
1674 | - double span_height = _spans[_characters[char_index].in_span].line_height.ascent + _spans[_characters[char_index].in_span].line_height.descent; |
1675 | - top_left[Geom::Y] = top_left[Geom::X]; |
1676 | + double span_height = _spans[_characters[char_index].in_span].line_height.emSize(); |
1677 | + top_left[Geom::Y] = top_left[Geom::X]; |
1678 | top_left[Geom::X] = baseline_y - span_height * 0.5; |
1679 | bottom_right[Geom::Y] = bottom_right[Geom::X]; |
1680 | bottom_right[Geom::X] = baseline_y + span_height * 0.5; |
1681 | @@ -404,7 +405,7 @@ |
1682 | double vertical_scale = _glyphs.back().vertical_scale; |
1683 | |
1684 | if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { |
1685 | - double span_height = vertical_scale * (_spans[span_index].line_height.ascent + _spans[span_index].line_height.descent); |
1686 | + double span_height = vertical_scale * _spans[span_index].line_height.emSize(); |
1687 | top_left[Geom::Y] = top_left[Geom::X]; |
1688 | top_left[Geom::X] = baseline_y - span_height * 0.5; |
1689 | bottom_right[Geom::Y] = bottom_right[Geom::X]; |
1690 | @@ -510,17 +511,19 @@ |
1691 | double vertical_scale = _glyphs.empty() ? 1.0 : _glyphs.back().vertical_scale; |
1692 | |
1693 | if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { |
1694 | - height = vertical_scale * span->line_height.ascent + span->line_height.descent; |
1695 | + // Vertical text |
1696 | + height = vertical_scale * span->line_height.emSize(); |
1697 | rotation += M_PI / 2; |
1698 | std::swap(position[Geom::X], position[Geom::Y]); |
1699 | position[Geom::X] -= vertical_scale * sin(rotation) * height * 0.5; |
1700 | position[Geom::Y] += vertical_scale * cos(rotation) * height * 0.5; |
1701 | } else { |
1702 | + // Horizontal text |
1703 | double caret_slope_run = 0.0, caret_slope_rise = 1.0; |
1704 | if (span->font) |
1705 | const_cast<font_instance*>(span->font)->FontSlope(caret_slope_run, caret_slope_rise); |
1706 | double caret_slope = atan2(caret_slope_run, caret_slope_rise); |
1707 | - height = vertical_scale * (span->line_height.ascent + span->line_height.descent) / cos(caret_slope); |
1708 | + height = vertical_scale * (span->line_height.emSize()) / cos(caret_slope); |
1709 | rotation += caret_slope; |
1710 | position[Geom::X] -= sin(rotation) * vertical_scale * span->line_height.descent; |
1711 | position[Geom::Y] += cos(rotation) * vertical_scale * span->line_height.descent; |
1712 | |
1713 | === modified file 'src/libnrtype/Layout-TNG-Output.cpp' |
1714 | --- src/libnrtype/Layout-TNG-Output.cpp 2015-01-05 10:17:51 +0000 |
1715 | +++ src/libnrtype/Layout-TNG-Output.cpp 2015-11-24 09:40:36 +0000 |
1716 | @@ -93,26 +93,55 @@ |
1717 | _path_fitted = NULL; |
1718 | } |
1719 | |
1720 | -void Layout::LineHeight::max(LineHeight const &other) |
1721 | -{ |
1722 | - if (other.ascent > ascent) ascent = other.ascent; |
1723 | - if (other.descent > descent) descent = other.descent; |
1724 | - if (other.leading > leading) leading = other.leading; |
1725 | +void Layout::FontMetrics::set(font_instance *font) |
1726 | +{ |
1727 | + if( font != NULL ) { |
1728 | + ascent = font->GetTypoAscent(); |
1729 | + descent = font->GetTypoDescent(); |
1730 | + xheight = font->GetXHeight(); |
1731 | + ascent_max = font->GetMaxAscent(); |
1732 | + descent_max = font->GetMaxDescent(); |
1733 | + } |
1734 | +} |
1735 | + |
1736 | +void Layout::FontMetrics::max(FontMetrics const &other) |
1737 | +{ |
1738 | + if (other.ascent > ascent ) ascent = other.ascent; |
1739 | + if (other.descent > descent ) descent = other.descent; |
1740 | + if( other.xheight > xheight ) xheight = other.xheight; |
1741 | + if( other.ascent_max > ascent_max ) ascent_max = other.ascent_max; |
1742 | + if( other.descent_max > descent_max ) descent_max = other.descent_max; |
1743 | +} |
1744 | + |
1745 | +void Layout::FontMetrics::computeEffective( const double &line_height_multiplier ) { |
1746 | + double half_leading = 0.5 * (line_height_multiplier - 1.0) * emSize(); |
1747 | + ascent += half_leading; |
1748 | + descent += half_leading; |
1749 | } |
1750 | |
1751 | void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const |
1752 | { |
1753 | Span const &span = _glyphs[glyph_index].span(this); |
1754 | - double sin_rotation = sin(_glyphs[glyph_index].rotation); |
1755 | - double cos_rotation = cos(_glyphs[glyph_index].rotation); |
1756 | + double rotation = _glyphs[glyph_index].rotation; |
1757 | + if ( (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) && |
1758 | + _glyphs[glyph_index].orientation == ORIENTATION_SIDEWAYS ) { |
1759 | + // Vertical sideways text |
1760 | + rotation += M_PI/2.0; |
1761 | + } |
1762 | + double sin_rotation = sin(rotation); |
1763 | + double cos_rotation = cos(rotation); |
1764 | (*matrix)[0] = span.font_size * cos_rotation; |
1765 | (*matrix)[1] = span.font_size * sin_rotation; |
1766 | (*matrix)[2] = span.font_size * sin_rotation; |
1767 | (*matrix)[3] = -span.font_size * cos_rotation * (_glyphs[glyph_index].vertical_scale); // unscale vertically so the specified text height is preserved if lengthAdjust=spacingAndGlyphs |
1768 | if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) { |
1769 | + // Vertical text |
1770 | + // This effectively swaps x for y which changes handedness of coordinate system. This is a bit strange |
1771 | + // and not what one would expect but the compute code already reverses y so OK. |
1772 | (*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y; |
1773 | (*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x; |
1774 | } else { |
1775 | + // Horizontal text |
1776 | (*matrix)[4] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x; |
1777 | (*matrix)[5] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y; |
1778 | } |
1779 | @@ -127,9 +156,9 @@ |
1780 | InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[_spans[span_index].in_input_stream_item]); |
1781 | |
1782 | text_source->style->text_decoration_data.tspan_width = _spans[span_index].width(); |
1783 | - text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getAscent(); |
1784 | - text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getDescent(); |
1785 | - text_source->style->text_decoration_data.line_gap = _spans[span_index].line_height.getLeading(); |
1786 | + text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getTypoAscent(); |
1787 | + text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getTypoDescent(); |
1788 | + |
1789 | if(!span_index || |
1790 | (_chunks[_spans[span_index].in_chunk].in_line != _chunks[_spans[span_index-1].in_chunk].in_line)){ |
1791 | text_source->style->text_decoration_data.tspan_line_start = true; |
1792 | @@ -170,11 +199,14 @@ |
1793 | first_line_glyph = false; |
1794 | phase0 = glyph_matrix.translation()[Geom::X]; |
1795 | } |
1796 | - // save the starting coordinates for the line - these are needed for figuring out dot/dash/wave phase |
1797 | + // Save the starting coordinates for the line - these are needed for figuring out |
1798 | + // dot/dash/wave phase. |
1799 | + // Use maximum ascent and descent to ensure glpyhs that extend outside the embox |
1800 | + // are fully drawn. |
1801 | (void) nr_text->addComponent(_spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix, |
1802 | _glyphs[glyph_index].width, |
1803 | - _spans[span_index].line_height.getAscent(), |
1804 | - _spans[span_index].line_height.getDescent(), |
1805 | + _spans[span_index].line_height.getMaxAscent(), |
1806 | + _spans[span_index].line_height.getMaxDescent(), |
1807 | glyph_matrix.translation()[Geom::X] - phase0 |
1808 | ); |
1809 | } |
1810 | @@ -580,7 +612,7 @@ |
1811 | result += Glib::ustring::compose(" font '%1' %2 %3 %4\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr))); |
1812 | } |
1813 | result += Glib::ustring::compose(" x_start = %1, x_end = %2\n", _spans[span_index].x_start, _spans[span_index].x_end) |
1814 | - + Glib::ustring::compose(" line height: ascent %1, descent %2 leading %3\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent, _spans[span_index].line_height.leading) |
1815 | + + Glib::ustring::compose(" line height: ascent %1, descent %2\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent) |
1816 | + Glib::ustring::compose(" direction %1, block-progression %2\n", direction_to_text(_spans[span_index].direction), direction_to_text(_spans[span_index].block_progression)) |
1817 | + " ** characters:\n"; |
1818 | Glib::ustring::const_iterator iter_char = _spans[span_index].input_stream_first_character; |
1819 | |
1820 | === modified file 'src/libnrtype/Layout-TNG-Scanline-Maker.h' |
1821 | --- src/libnrtype/Layout-TNG-Scanline-Maker.h 2010-11-17 02:12:56 +0000 |
1822 | +++ src/libnrtype/Layout-TNG-Scanline-Maker.h 2015-11-24 09:40:36 +0000 |
1823 | @@ -47,7 +47,7 @@ |
1824 | between calls if the new height too big to fit in the space remaining in |
1825 | this shape. Returns an empty vector if there is no space left in the |
1826 | current shape. */ |
1827 | - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height) =0; |
1828 | + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height) =0; |
1829 | |
1830 | /** Indicates that the caller has successfully filled the current line |
1831 | and hence that the next call to makeScanline() should return lines on |
1832 | @@ -71,7 +71,7 @@ |
1833 | The metrics given here are considered to be the ones that are being |
1834 | used now, and hence is the line advance height used by completeLine(). |
1835 | */ |
1836 | - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height) =0; |
1837 | + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height) =0; |
1838 | }; |
1839 | |
1840 | /** \brief private to Layout. Generates infinite scanlines for when you don't want wrapping |
1841 | @@ -90,7 +90,7 @@ |
1842 | virtual ~InfiniteScanlineMaker(); |
1843 | |
1844 | /** Returns a single infinite run at the current location */ |
1845 | - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height); |
1846 | + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height); |
1847 | |
1848 | /** Increments the current y by the current line height */ |
1849 | virtual void completeLine(); |
1850 | @@ -102,11 +102,11 @@ |
1851 | virtual void setNewYCoordinate(double new_y); |
1852 | |
1853 | /** Always true, but has to save the new height */ |
1854 | - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height); |
1855 | + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height); |
1856 | |
1857 | private: |
1858 | double _x, _y; |
1859 | - Layout::LineHeight _current_line_height; |
1860 | + Layout::FontMetrics _current_line_height; |
1861 | bool _negative_block_progression; /// if true, indicates that completeLine() should decrement rather than increment, ie block-progression is either rl or bt |
1862 | }; |
1863 | |
1864 | @@ -122,7 +122,7 @@ |
1865 | ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression); |
1866 | virtual ~ShapeScanlineMaker(); |
1867 | |
1868 | - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height); |
1869 | + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height); |
1870 | |
1871 | virtual void completeLine(); |
1872 | |
1873 | @@ -131,7 +131,7 @@ |
1874 | virtual void setNewYCoordinate(double new_y); |
1875 | |
1876 | /** never true */ |
1877 | - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height); |
1878 | + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height); |
1879 | private: |
1880 | /** To generate scanlines for top-to-bottom text it is easiest if we |
1881 | simply rotate the given shape by a multiple of 90 degrees. This stores |
1882 | |
1883 | === modified file 'src/libnrtype/Layout-TNG-Scanline-Makers.cpp' |
1884 | --- src/libnrtype/Layout-TNG-Scanline-Makers.cpp 2011-02-02 21:24:36 +0000 |
1885 | +++ src/libnrtype/Layout-TNG-Scanline-Makers.cpp 2015-11-24 09:40:36 +0000 |
1886 | @@ -19,9 +19,7 @@ |
1887 | |
1888 | Layout::InfiniteScanlineMaker::InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression) |
1889 | { |
1890 | - _current_line_height.ascent = 0.0; |
1891 | - _current_line_height.descent = 0.0; |
1892 | - _current_line_height.leading = 0.0; |
1893 | + _current_line_height.setZero(); |
1894 | switch (block_progression) { |
1895 | case LEFT_TO_RIGHT: |
1896 | case RIGHT_TO_LEFT: |
1897 | @@ -41,7 +39,7 @@ |
1898 | { |
1899 | } |
1900 | |
1901 | -std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::LineHeight const &line_height) |
1902 | +std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::FontMetrics const &line_height) |
1903 | { |
1904 | std::vector<ScanRun> runs(1); |
1905 | runs[0].x_start = _x; |
1906 | @@ -54,12 +52,10 @@ |
1907 | void Layout::InfiniteScanlineMaker::completeLine() |
1908 | { |
1909 | if (_negative_block_progression) |
1910 | - _y -= _current_line_height.total(); |
1911 | + _y -= _current_line_height.emSize(); |
1912 | else |
1913 | - _y += _current_line_height.total(); |
1914 | - _current_line_height.ascent = 0.0; |
1915 | - _current_line_height.descent = 0.0; |
1916 | - _current_line_height.leading = 0.0; |
1917 | + _y += _current_line_height.emSize(); |
1918 | + _current_line_height.setZero(); |
1919 | } |
1920 | |
1921 | void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y) |
1922 | @@ -67,7 +63,7 @@ |
1923 | _y = new_y; |
1924 | } |
1925 | |
1926 | -bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &line_height) |
1927 | +bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &line_height) |
1928 | { |
1929 | _current_line_height = line_height; |
1930 | return true; |
1931 | @@ -111,29 +107,29 @@ |
1932 | delete _rotated_shape; |
1933 | } |
1934 | |
1935 | -std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::LineHeight const &line_height) |
1936 | +std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::FontMetrics const &line_height) |
1937 | { |
1938 | - FloatLigne line_rasterization; |
1939 | - FloatLigne line_decent_length_runs; |
1940 | - float line_text_height = (float)(line_height.ascent + line_height.descent); |
1941 | - |
1942 | if (_y > _bounding_box_bottom) |
1943 | return std::vector<ScanRun>(); |
1944 | |
1945 | if (_y < _bounding_box_top) |
1946 | _y = _bounding_box_top; |
1947 | |
1948 | + FloatLigne line_rasterization; |
1949 | + FloatLigne line_decent_length_runs; |
1950 | + float line_text_height = (float)(line_height.emSize()); |
1951 | if (line_text_height == 0.0) |
1952 | line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do |
1953 | |
1954 | - _current_line_height = (float)line_height.total(); |
1955 | + _current_line_height = (float)line_height.emSize(); |
1956 | |
1957 | // I think what's going on here is that we're moving the top of the scanline to the given position... |
1958 | _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y, line_text_height); |
1959 | // ...then actually retreiving the scanline (which alters the first two parameters) |
1960 | _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y + line_text_height , &line_rasterization, true, line_text_height); |
1961 | - // sanitise the raw rasterisation, which could have weird overlaps |
1962 | + // sanitise the raw rasterisation, which could have weird overlaps |
1963 | line_rasterization.Flatten(); |
1964 | + // line_rasterization.Affiche(); |
1965 | // cut out runs that cover less than 90% of the line |
1966 | line_decent_length_runs.Over(&line_rasterization, 0.9 * line_text_height); |
1967 | |
1968 | @@ -179,7 +175,7 @@ |
1969 | // it's not an important question because <flowSpan> doesn't have a y attribute |
1970 | } |
1971 | |
1972 | -bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &/*line_height*/) |
1973 | +bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &/*line_height*/) |
1974 | { |
1975 | //we actually could return true if only the leading changed, but that's too much effort for something that rarely happens |
1976 | return false; |
1977 | |
1978 | === modified file 'src/libnrtype/Layout-TNG.h' |
1979 | --- src/libnrtype/Layout-TNG.h 2015-05-08 15:19:23 +0000 |
1980 | +++ src/libnrtype/Layout-TNG.h 2015-11-24 09:40:36 +0000 |
1981 | @@ -22,6 +22,7 @@ |
1982 | #include <vector> |
1983 | #include <boost/optional.hpp> |
1984 | #include <svg/svg-length.h> |
1985 | +#include "style-enums.h" |
1986 | |
1987 | #ifdef HAVE_CAIRO_PDF |
1988 | namespace Inkscape { |
1989 | @@ -157,6 +158,9 @@ |
1990 | both the 'direction' and 'block-progression' CSS attributes. */ |
1991 | enum Direction {LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP}; |
1992 | |
1993 | + /** Used to specify orientation of glyphs in vertical text. */ |
1994 | + enum Orientation {ORIENTATION_UPRIGHT, ORIENTATION_SIDEWAYS}; |
1995 | + |
1996 | /** Display alignment for shapes. See appendWrapShape(). */ |
1997 | enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER}; |
1998 | |
1999 | @@ -603,19 +607,69 @@ |
2000 | |
2001 | //@} |
2002 | |
2003 | - /// it's useful for this to be public so that ScanlineMaker can use it |
2004 | - struct LineHeight { |
2005 | - double ascent; |
2006 | - double descent; |
2007 | - double leading; |
2008 | - inline double total() const {return ascent + descent + leading;} |
2009 | - inline void setZero() {ascent = descent = leading = 0.0;} |
2010 | - inline LineHeight& operator*=(double x) {ascent *= x; descent *= x; leading *= x; return *this;} |
2011 | - void max(LineHeight const &other); /// makes this object contain the largest of all three members between this object and other |
2012 | - inline double getAscent() const {return ascent; } |
2013 | - inline double getDescent() const {return descent; } |
2014 | - inline double getLeading() const {return leading; } |
2015 | - }; |
2016 | + |
2017 | + /** |
2018 | + * Keep track of font metrics. Two use cases: |
2019 | + * 1. Keep track of ascent, descent, and x-height of an individual font. |
2020 | + * 2. Keep track of effective ascent and descent that includes half-leading. |
2021 | + * |
2022 | + * Note: Leading refers to the "external" leading which is added (subtracted) due to |
2023 | + * a computed value of 'line-height' that differs from 'font-size'. "Internal" leading |
2024 | + * which is specified inside a font is not used in CSS. The 'font-size' is based on |
2025 | + * the font's em size which is 'ascent' + 'descent'. |
2026 | + * |
2027 | + * This structure was renamed (and modified) from "LineHeight". |
2028 | + * |
2029 | + * It's useful for this to be public so that ScanlineMaker can use it. |
2030 | + */ |
2031 | + class FontMetrics { |
2032 | + |
2033 | + public: |
2034 | + FontMetrics() { reset(); } |
2035 | + |
2036 | + void reset() { |
2037 | + ascent = 0.8; |
2038 | + descent = -0.2; |
2039 | + xheight = 0.5; |
2040 | + ascent_max = 0.8; |
2041 | + descent_max = 0.2; |
2042 | + } |
2043 | + |
2044 | + void set( font_instance *font ); |
2045 | + |
2046 | + // CSS 2.1 dictates that font-size is based on em-size which is defined as ascent + descent |
2047 | + inline double emSize() const {return ascent + descent;} |
2048 | + // Alternatively name function for use 2. |
2049 | + inline double lineSize() const { return ascent + descent; } |
2050 | + inline void setZero() {ascent = descent = xheight = ascent_max = descent_max = 0.0;} |
2051 | + |
2052 | + // For scaling for 'font-size'. |
2053 | + inline FontMetrics& operator*=(double x) { |
2054 | + ascent *= x; descent *= x; xheight *= x; ascent_max *= x; descent_max *= x; |
2055 | + return *this; |
2056 | + } |
2057 | + |
2058 | + /// Save the larger values of ascent and descent between this and other. Needed for laying |
2059 | + /// out a line with mixed font-sizes, fonts, or line spacings. |
2060 | + void max(FontMetrics const &other); |
2061 | + |
2062 | + /// Calculate the effective ascent and descent including half "leading". |
2063 | + void computeEffective( const double &line_height ); |
2064 | + |
2065 | + inline double getTypoAscent() const {return ascent; } |
2066 | + inline double getTypoDescent() const {return descent; } |
2067 | + inline double getXHeight() const {return xheight; } |
2068 | + inline double getMaxAscent() const {return ascent_max; } |
2069 | + inline double getMaxDescent() const {return descent_max; } |
2070 | + |
2071 | + // private: |
2072 | + double ascent; // Typographic ascent. |
2073 | + double descent; // Typographic descent. |
2074 | + double xheight; // Height of 'x' measured from alphabetic baseline. |
2075 | + double ascent_max; // Maximum ascent of all glyphs in font. |
2076 | + double descent_max; // Maximum descent of all glyphs in font. |
2077 | + |
2078 | + }; // End FontMetrics |
2079 | |
2080 | /// see _enum_converter() |
2081 | struct EnumConversionItem { |
2082 | @@ -664,11 +718,12 @@ |
2083 | LengthAdjust lengthAdjust; |
2084 | |
2085 | // a few functions for some of the more complicated style accesses |
2086 | - float styleComputeFontSize() const; |
2087 | /// The return value must be freed with pango_font_description_free() |
2088 | PangoFontDescription *styleGetFontDescription() const; |
2089 | font_instance *styleGetFontInstance() const; |
2090 | Direction styleGetBlockProgression() const; |
2091 | + SPCSSTextOrientation styleGetTextOrientation() const; |
2092 | + SPCSSBaseline styleGetDominantBaseline() const; |
2093 | Alignment styleGetAlignment(Direction para_direction, bool try_text_align) const; |
2094 | }; |
2095 | |
2096 | @@ -707,6 +762,22 @@ |
2097 | return TOP_TO_BOTTOM; |
2098 | } |
2099 | |
2100 | + /** The overall text-orientation of the whole flow. */ |
2101 | + inline SPCSSTextOrientation _blockTextOrientation() const |
2102 | + { |
2103 | + if(!_input_stream.empty()) |
2104 | + return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetTextOrientation(); |
2105 | + return SP_CSS_TEXT_ORIENTATION_MIXED; |
2106 | + } |
2107 | + |
2108 | + /** The overall text-orientation of the whole flow. */ |
2109 | + inline SPCSSBaseline _blockBaseline() const |
2110 | + { |
2111 | + if(!_input_stream.empty()) |
2112 | + return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetDominantBaseline(); |
2113 | + return SP_CSS_BASELINE_AUTO; |
2114 | + } |
2115 | + |
2116 | /** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */ |
2117 | static bool _directions_are_orthogonal(Direction d1, Direction d2); |
2118 | |
2119 | @@ -748,6 +819,7 @@ |
2120 | float x; /// relative to the start of the chunk |
2121 | float y; /// relative to the current line's baseline |
2122 | float rotation; /// absolute, modulo any object transforms, which we don't know about |
2123 | + Orientation orientation; /// Orientation of glyph in vertical text |
2124 | float width; |
2125 | float vertical_scale; /// to implement lengthAdjust="spacingAndGlyphs" that must scale glyphs only horizontally; instead we change font size and then undo that change vertically only |
2126 | inline Span const & span(Layout const *l) const {return l->_spans[l->_characters[in_character].in_span];} |
2127 | @@ -772,8 +844,9 @@ |
2128 | float x_start; /// relative to the start of the chunk |
2129 | float x_end; /// relative to the start of the chunk |
2130 | inline float width() const {return std::abs(x_start - x_end);} |
2131 | - LineHeight line_height; |
2132 | + FontMetrics line_height; |
2133 | double baseline_shift; /// relative to the line's baseline |
2134 | + SPCSSTextOrientation text_orientation; |
2135 | Direction direction; /// See CSS3 section 3.2. Either rtl or ltr |
2136 | Direction block_progression; /// See CSS3 section 3.2. The direction in which lines go. |
2137 | unsigned in_input_stream_item; |
2138 | |
2139 | === modified file 'src/libnrtype/TextWrapper.cpp' |
2140 | --- src/libnrtype/TextWrapper.cpp 2014-03-27 01:33:44 +0000 |
2141 | +++ src/libnrtype/TextWrapper.cpp 2015-11-24 09:40:36 +0000 |
2142 | @@ -862,7 +862,7 @@ |
2143 | for (int i = 0; i < nbBox; i++) { |
2144 | boxes[i].ascent = 0; |
2145 | boxes[i].descent = 0; |
2146 | - boxes[i].leading = 0; |
2147 | + boxes[i].xheight = 0; |
2148 | boxes[i].width = 0; |
2149 | |
2150 | PangoFont *curPF = glyph_text[boxes[i].g_st].font; |
2151 | @@ -870,7 +870,7 @@ |
2152 | PangoFontDescription *pfd = pango_font_describe(curPF); |
2153 | font_instance *curF = f_src->Face(pfd); |
2154 | if ( curF ) { |
2155 | - curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].leading); |
2156 | + curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].xheight); |
2157 | curF->Unref(); |
2158 | } |
2159 | pango_font_description_free(pfd); |
2160 | |
2161 | === modified file 'src/libnrtype/font-instance.h' |
2162 | --- src/libnrtype/font-instance.h 2015-06-25 11:46:43 +0000 |
2163 | +++ src/libnrtype/font-instance.h 2015-11-24 09:40:36 +0000 |
2164 | @@ -57,19 +57,31 @@ |
2165 | |
2166 | // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply |
2167 | // by the fontsize to get the real sizes |
2168 | + |
2169 | + // Return 2geom pathvector for glyph. Deallocated when font instance dies. |
2170 | Geom::PathVector* PathVector(int glyph_id); |
2171 | - // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies |
2172 | + |
2173 | + // Horizontal advance if 'vertical' is false, vertical advance if true. |
2174 | double Advance(int glyph_id, bool vertical); |
2175 | - // nominal advance of the font. |
2176 | + |
2177 | + double GetTypoAscent() { return _ascent; } |
2178 | + double GetTypoDescent() { return _descent; } |
2179 | + double GetXHeight() { return _xheight; } |
2180 | + double GetMaxAscent() { return _ascent_max; } |
2181 | + double GetMaxDescent() { return _descent_max; } |
2182 | + const double* GetBaselines() { return _baselines; } |
2183 | + |
2184 | bool FontMetrics(double &ascent, double &descent, double &leading); |
2185 | - bool FontDecoration(double &underline_position, double &underline_thickness, |
2186 | - double &linethrough_position, double &linethrough_thickness); |
2187 | + bool FontDecoration(double &underline_position, double &underline_thickness, |
2188 | + double &linethrough_position, double &linethrough_thickness); |
2189 | bool FontSlope(double &run, double &rise); |
2190 | // for generating slanted cursors for oblique fonts |
2191 | - Geom::OptRect BBox(int glyph_id); |
2192 | + Geom::OptRect BBox(int glyph_id); |
2193 | |
2194 | private: |
2195 | void FreeTheFace(); |
2196 | + // Find ascent, descent, x-height, and baselines. |
2197 | + void FindFontMetrics(); |
2198 | |
2199 | // Temp: make public |
2200 | public: |
2201 | @@ -81,6 +93,17 @@ |
2202 | // as long as pFont is valid, theFace is too |
2203 | #endif |
2204 | |
2205 | +private: |
2206 | + |
2207 | + // Font metrics in em-box units |
2208 | + double _ascent; // Typographic ascent. |
2209 | + double _descent; // Typographic descent. |
2210 | + double _xheight; // x-height of font. |
2211 | + double _ascent_max; // Maxiumum ascent of all glyphs in font. |
2212 | + double _descent_max; // Maxiumum descent of all glyphs in font. |
2213 | + |
2214 | + // Baselines |
2215 | + double _baselines[SP_CSS_BASELINE_SIZE]; |
2216 | }; |
2217 | |
2218 | |
2219 | |
2220 | === modified file 'src/libnrtype/one-box.h' |
2221 | --- src/libnrtype/one-box.h 2010-11-17 02:12:56 +0000 |
2222 | +++ src/libnrtype/one-box.h 2015-11-24 09:40:36 +0000 |
2223 | @@ -9,7 +9,7 @@ |
2224 | // this time for sp-typeset |
2225 | struct one_box { |
2226 | int g_st, g_en; ///< First and last glyph of this word. |
2227 | - double ascent, descent, leading; |
2228 | + double ascent, descent, xheight; |
2229 | double width; |
2230 | bool word_start, word_end; |
2231 | }; |
2232 | |
2233 | === modified file 'src/style-enums.h' |
2234 | --- src/style-enums.h 2015-10-15 11:52:47 +0000 |
2235 | +++ src/style-enums.h 2015-11-24 09:40:36 +0000 |
2236 | @@ -174,10 +174,7 @@ |
2237 | enum SPCSSTextOrientation { |
2238 | SP_CSS_TEXT_ORIENTATION_MIXED, |
2239 | SP_CSS_TEXT_ORIENTATION_UPRIGHT, |
2240 | - SP_CSS_TEXT_ORIENTATION_SIDEWAYS_RIGHT, |
2241 | - SP_CSS_TEXT_ORIENTATION_SIDEWAYS_LEFT, |
2242 | - SP_CSS_TEXT_ORIENTATION_SIDEWAYS, |
2243 | - SP_CSS_TEXT_ORIENTATION_USE_GLYPH_ORIENTATION |
2244 | + SP_CSS_TEXT_ORIENTATION_SIDEWAYS |
2245 | }; |
2246 | |
2247 | enum SPTextAnchor { |
2248 | @@ -194,10 +191,24 @@ |
2249 | SP_CSS_WHITE_SPACE_PRELINE |
2250 | }; |
2251 | |
2252 | +// Not complete list |
2253 | +enum SPCSSBaseline { |
2254 | + SP_CSS_BASELINE_AUTO, |
2255 | + SP_CSS_BASELINE_ALPHABETIC, |
2256 | + SP_CSS_BASELINE_IDEOGRAPHIC, |
2257 | + SP_CSS_BASELINE_HANGING, |
2258 | + SP_CSS_BASELINE_MATHEMATICAL, |
2259 | + SP_CSS_BASELINE_CENTRAL, |
2260 | + SP_CSS_BASELINE_MIDDLE, |
2261 | + SP_CSS_BASELINE_TEXT_BEFORE_EDGE, |
2262 | + SP_CSS_BASELINE_TEXT_AFTER_EDGE, |
2263 | + SP_CSS_BASELINE_SIZE // Size of enum, keep last. |
2264 | +}; |
2265 | + |
2266 | enum SPCSSBaselineShift { |
2267 | - SP_CSS_BASELINE_SHIFT_BASELINE, |
2268 | - SP_CSS_BASELINE_SHIFT_SUB, |
2269 | - SP_CSS_BASELINE_SHIFT_SUPER |
2270 | + SP_CSS_BASELINE_SHIFT_BASELINE, |
2271 | + SP_CSS_BASELINE_SHIFT_SUB, |
2272 | + SP_CSS_BASELINE_SHIFT_SUPER |
2273 | }; |
2274 | |
2275 | enum SPVisibility { |
2276 | @@ -519,10 +530,20 @@ |
2277 | static SPStyleEnum const enum_text_orientation[] = { |
2278 | {"mixed", SP_CSS_TEXT_ORIENTATION_MIXED}, // Default |
2279 | {"upright", SP_CSS_TEXT_ORIENTATION_UPRIGHT}, |
2280 | - {"sideways-right", SP_CSS_TEXT_ORIENTATION_SIDEWAYS_RIGHT}, |
2281 | - {"sideways-left", SP_CSS_TEXT_ORIENTATION_SIDEWAYS_LEFT}, |
2282 | {"sideways", SP_CSS_TEXT_ORIENTATION_SIDEWAYS}, |
2283 | - {"use-glyph-orientation", SP_CSS_TEXT_ORIENTATION_USE_GLYPH_ORIENTATION}, |
2284 | + {NULL, -1} |
2285 | +}; |
2286 | + |
2287 | +static SPStyleEnum const enum_baseline[] = { |
2288 | + {"auto", SP_CSS_BASELINE_AUTO}, // Default |
2289 | + {"alphabetic", SP_CSS_BASELINE_ALPHABETIC}, |
2290 | + {"ideographic", SP_CSS_BASELINE_IDEOGRAPHIC}, |
2291 | + {"hanging", SP_CSS_BASELINE_HANGING}, |
2292 | + {"mathematical", SP_CSS_BASELINE_MATHEMATICAL}, |
2293 | + {"central", SP_CSS_BASELINE_CENTRAL}, |
2294 | + {"middle", SP_CSS_BASELINE_MIDDLE}, |
2295 | + {"text-before-edge", SP_CSS_BASELINE_TEXT_BEFORE_EDGE}, |
2296 | + {"text-after-edge", SP_CSS_BASELINE_TEXT_AFTER_EDGE}, |
2297 | {NULL, -1} |
2298 | }; |
2299 | |
2300 | |
2301 | === modified file 'src/style-internal.h' |
2302 | --- src/style-internal.h 2015-06-22 10:10:30 +0000 |
2303 | +++ src/style-internal.h 2015-11-24 09:40:36 +0000 |
2304 | @@ -1260,7 +1260,6 @@ |
2305 | float tspan_width; // from libnrtype, when it calculates spans |
2306 | float ascender; // the rest from tspan's font |
2307 | float descender; |
2308 | - float line_gap; |
2309 | float underline_thickness; |
2310 | float underline_position; |
2311 | float line_through_thickness; |
2312 | |
2313 | === modified file 'src/style.cpp' |
2314 | --- src/style.cpp 2015-10-15 11:52:47 +0000 |
2315 | +++ src/style.cpp 2015-11-24 09:40:36 +0000 |
2316 | @@ -113,7 +113,7 @@ |
2317 | font_weight( "font-weight", enum_font_weight, SP_CSS_FONT_WEIGHT_NORMAL, SP_CSS_FONT_WEIGHT_400 ), |
2318 | font_stretch( "font-stretch", enum_font_stretch, SP_CSS_FONT_STRETCH_NORMAL ), |
2319 | font_size(), |
2320 | - line_height( "line-height", 1.0 ), // SPILengthOrNormal |
2321 | + line_height( "line-height", 1.25 ), // SPILengthOrNormal |
2322 | font_family( "font-family", "sans-serif" ), // SPIString w/default |
2323 | font(), // SPIFont |
2324 | font_specification( "-inkscape-font-specification" ), // SPIString |
2325 | @@ -138,6 +138,7 @@ |
2326 | direction( "direction", enum_direction, SP_CSS_DIRECTION_LTR ), |
2327 | writing_mode( "writing-mode", enum_writing_mode, SP_CSS_WRITING_MODE_LR_TB ), |
2328 | text_orientation( "text-orientation",enum_text_orientation,SP_CSS_TEXT_ORIENTATION_MIXED ), |
2329 | + dominant_baseline("dominant-baseline",enum_baseline, SP_CSS_BASELINE_AUTO ), |
2330 | baseline_shift(), |
2331 | text_anchor( "text-anchor", enum_text_anchor, SP_CSS_TEXT_ANCHOR_START ), |
2332 | white_space( "white-space", enum_white_space, SP_CSS_WHITE_SPACE_NORMAL ), |
2333 | @@ -321,6 +322,7 @@ |
2334 | _properties.push_back( &writing_mode ); |
2335 | _properties.push_back( &direction ); |
2336 | _properties.push_back( &text_orientation ); |
2337 | + _properties.push_back( &dominant_baseline ); |
2338 | _properties.push_back( &baseline_shift ); |
2339 | _properties.push_back( &text_anchor ); |
2340 | _properties.push_back( &white_space ); |
2341 | @@ -415,6 +417,7 @@ |
2342 | // _propmap.insert( std::make_pair( direction.name, reinterpret_cast<SPIBasePtr>(&SPStyle::direction ) ) ); |
2343 | // _propmap.insert( std::make_pair( writing_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::writing_mode ) ) ); |
2344 | // _propmap.insert( std::make_pair( text_orientation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_orientation ) ) ); |
2345 | + // _propmap.insert( std::make_pair( dominant_baseline.name, reinterpret_cast<SPIBasePtr>(&SPStyle::dominant_baseline ) ) ); |
2346 | // _propmap.insert( std::make_pair( baseline_shift.name, reinterpret_cast<SPIBasePtr>(&SPStyle::baseline_shift ) ) ); |
2347 | // _propmap.insert( std::make_pair( text_anchor.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_anchor ) ) ); |
2348 | // _propmap.insert( std::make_pair( white_space.name, reinterpret_cast<SPIBasePtr>(&SPStyle::white_space ) ) ); |
2349 | @@ -796,6 +799,9 @@ |
2350 | case SP_PROP_SHAPE_PADDING: |
2351 | shape_padding.readIfUnset( val ); |
2352 | break; |
2353 | + case SP_PROP_DOMINANT_BASELINE: |
2354 | + dominant_baseline.readIfUnset( val ); |
2355 | + break; |
2356 | case SP_PROP_BASELINE_SHIFT: |
2357 | baseline_shift.readIfUnset( val ); |
2358 | break; |
2359 | @@ -805,9 +811,6 @@ |
2360 | case SP_PROP_ALIGNMENT_BASELINE: |
2361 | g_warning("Unimplemented style property SP_PROP_ALIGNMENT_BASELINE: value: %s", val); |
2362 | break; |
2363 | - case SP_PROP_DOMINANT_BASELINE: |
2364 | - g_warning("Unimplemented style property SP_PROP_DOMINANT_BASELINE: value: %s", val); |
2365 | - break; |
2366 | case SP_PROP_GLYPH_ORIENTATION_HORIZONTAL: |
2367 | g_warning("Unimplemented style property SP_PROP_ORIENTATION_HORIZONTAL: value: %s", val); |
2368 | break; |
2369 | |
2370 | === modified file 'src/style.h' |
2371 | --- src/style.h 2015-10-15 11:52:47 +0000 |
2372 | +++ src/style.h 2015-11-24 09:40:36 +0000 |
2373 | @@ -148,6 +148,8 @@ |
2374 | SPIEnum writing_mode; |
2375 | /** Text orientation (CSS Writing Modes 3) */ |
2376 | SPIEnum text_orientation; |
2377 | + /** Dominant baseline (svg1.1) */ |
2378 | + SPIEnum dominant_baseline; |
2379 | /** Baseline shift (svg1.1 10.9.2) */ |
2380 | SPIBaselineShift baseline_shift; |
2381 | |
2382 | |
2383 | === modified file 'src/widgets/text-toolbar.cpp' |
2384 | --- src/widgets/text-toolbar.cpp 2015-11-13 17:54:23 +0000 |
2385 | +++ src/widgets/text-toolbar.cpp 2015-11-24 09:40:36 +0000 |
2386 | @@ -737,28 +737,88 @@ |
2387 | g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); |
2388 | } |
2389 | |
2390 | -static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl ) |
2391 | -{ |
2392 | - // quit if run by the _changed callbacks |
2393 | - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { |
2394 | - return; |
2395 | - } |
2396 | - g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); |
2397 | - |
2398 | - int mode = ege_select_one_action_get_active( act ); |
2399 | - |
2400 | - SPCSSAttr *css = sp_repr_css_attr_new (); |
2401 | - switch (mode) |
2402 | - { |
2403 | - case 0: |
2404 | - { |
2405 | - sp_repr_css_set_property (css, "writing-mode", "lr"); |
2406 | - break; |
2407 | - } |
2408 | - |
2409 | - case 1: |
2410 | - { |
2411 | - sp_repr_css_set_property (css, "writing-mode", "tb"); |
2412 | +static void sp_writing_mode_changed( EgeSelectOneAction *act, GObject *tbl ) |
2413 | +{ |
2414 | + // quit if run by the _changed callbacks |
2415 | + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { |
2416 | + return; |
2417 | + } |
2418 | + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); |
2419 | + |
2420 | + int mode = ege_select_one_action_get_active( act ); |
2421 | + |
2422 | + SPCSSAttr *css = sp_repr_css_attr_new (); |
2423 | + switch (mode) |
2424 | + { |
2425 | + case 0: |
2426 | + { |
2427 | + sp_repr_css_set_property (css, "writing-mode", "lr-tb"); |
2428 | + break; |
2429 | + } |
2430 | + |
2431 | + case 1: |
2432 | + { |
2433 | + sp_repr_css_set_property (css, "writing-mode", "tb-rl"); |
2434 | + break; |
2435 | + } |
2436 | + |
2437 | + case 2: |
2438 | + { |
2439 | + sp_repr_css_set_property (css, "writing-mode", "vertical-lr"); |
2440 | + break; |
2441 | + } |
2442 | +} |
2443 | + |
2444 | + SPStyle query(SP_ACTIVE_DOCUMENT); |
2445 | + int result_numbers = |
2446 | + sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); |
2447 | + |
2448 | + // If querying returned nothing, update default style. |
2449 | + if (result_numbers == QUERY_STYLE_NOTHING) |
2450 | + { |
2451 | + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
2452 | + prefs->mergeStyle("/tools/text/style", css); |
2453 | + } |
2454 | + |
2455 | + sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); |
2456 | + if(result_numbers != QUERY_STYLE_NOTHING) |
2457 | + { |
2458 | + DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_TEXT, |
2459 | + _("Text: Change writing mode")); |
2460 | + } |
2461 | + sp_repr_css_attr_unref (css); |
2462 | + |
2463 | + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); |
2464 | +} |
2465 | + |
2466 | +static void sp_text_orientation_changed( EgeSelectOneAction *act, GObject *tbl ) |
2467 | +{ |
2468 | + // quit if run by the _changed callbacks |
2469 | + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { |
2470 | + return; |
2471 | + } |
2472 | + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); |
2473 | + |
2474 | + int mode = ege_select_one_action_get_active( act ); |
2475 | + |
2476 | + SPCSSAttr *css = sp_repr_css_attr_new (); |
2477 | + switch (mode) |
2478 | + { |
2479 | + case 0: |
2480 | + { |
2481 | + sp_repr_css_set_property (css, "text-orientation", "auto"); |
2482 | + break; |
2483 | + } |
2484 | + |
2485 | + case 1: |
2486 | + { |
2487 | + sp_repr_css_set_property (css, "text-orientation", "upright"); |
2488 | + break; |
2489 | + } |
2490 | + |
2491 | + case 2: |
2492 | + { |
2493 | + sp_repr_css_set_property (css, "text-orientation", "sideways"); |
2494 | break; |
2495 | } |
2496 | } |
2497 | @@ -893,13 +953,17 @@ |
2498 | int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE); |
2499 | int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); |
2500 | int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_BASELINES); |
2501 | + int result_wmode = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_WRITINGMODES); |
2502 | |
2503 | /* |
2504 | * If no text in selection (querying returned nothing), read the style from |
2505 | * the /tools/text preferencess (default style for new texts). Return if |
2506 | * tool bar already set to these preferences. |
2507 | */ |
2508 | - if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) { |
2509 | + if (result_family == QUERY_STYLE_NOTHING || |
2510 | + result_style == QUERY_STYLE_NOTHING || |
2511 | + result_numbers == QUERY_STYLE_NOTHING || |
2512 | + result_wmode == QUERY_STYLE_NOTHING ) { |
2513 | // There are no texts in selection, read from preferences. |
2514 | query.readFromPrefs("/tools/text"); |
2515 | #ifdef DEBUG_TEXT |
2516 | @@ -1047,13 +1111,42 @@ |
2517 | gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing ); |
2518 | |
2519 | |
2520 | + // Writing mode |
2521 | + int activeButton2 = 0; |
2522 | + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB) activeButton2 = 0; |
2523 | + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_RL) activeButton2 = 1; |
2524 | + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_LR) activeButton2 = 2; |
2525 | + |
2526 | + EgeSelectOneAction* writingModeAction = |
2527 | + EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextWritingModeAction" ) ); |
2528 | + ege_select_one_action_set_active( writingModeAction, activeButton2 ); |
2529 | + |
2530 | // Orientation |
2531 | - int activeButton2 = (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1); |
2532 | + int activeButton3 = 0; |
2533 | + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED ) activeButton3 = 0; |
2534 | + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_UPRIGHT ) activeButton3 = 1; |
2535 | + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS) activeButton3 = 2; |
2536 | |
2537 | EgeSelectOneAction* textOrientationAction = |
2538 | EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) ); |
2539 | - ege_select_one_action_set_active( textOrientationAction, activeButton2 ); |
2540 | - |
2541 | + ege_select_one_action_set_active( textOrientationAction, activeButton3 ); |
2542 | + |
2543 | + // Disable text orientation for horizontal text.. See above for why this nonsense |
2544 | + model = GTK_LIST_STORE( ege_select_one_action_get_model( textOrientationAction ) ); |
2545 | + |
2546 | + path = gtk_tree_path_new_from_string("0"); |
2547 | + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); |
2548 | + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); |
2549 | + |
2550 | + path = gtk_tree_path_new_from_string("1"); |
2551 | + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); |
2552 | + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); |
2553 | + |
2554 | + path = gtk_tree_path_new_from_string("2"); |
2555 | + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); |
2556 | + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); |
2557 | + |
2558 | + ege_select_one_action_update_sensitive( textOrientationAction ); |
2559 | |
2560 | } |
2561 | |
2562 | @@ -1387,7 +1480,7 @@ |
2563 | g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder ); |
2564 | } |
2565 | |
2566 | - /* Orientation (Left to Right, Top to Bottom */ |
2567 | + /* Writing mode (Horizontal, Vertical-LR, Vertical-RL) */ |
2568 | { |
2569 | GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); |
2570 | |
2571 | @@ -1402,14 +1495,73 @@ |
2572 | |
2573 | gtk_list_store_append( model, &iter ); |
2574 | gtk_list_store_set( model, &iter, |
2575 | - 0, _("Vertical"), |
2576 | - 1, _("Vertical text"), |
2577 | + 0, _("Vertical — RL"), |
2578 | + 1, _("Vertical text — lines: right to left"), |
2579 | 2, INKSCAPE_ICON("format-text-direction-vertical"), |
2580 | -1 ); |
2581 | |
2582 | + gtk_list_store_append( model, &iter ); |
2583 | + gtk_list_store_set( model, &iter, |
2584 | + 0, _("Vertical — LR"), |
2585 | + 1, _("Vertical text — lines: left to right"), // Mongolian! |
2586 | + 2, INKSCAPE_ICON("format-text-direction-vertical-lr"), |
2587 | + -1 ); |
2588 | + |
2589 | + EgeSelectOneAction* act = ege_select_one_action_new( "TextWritingModeAction", // Name |
2590 | + _("Writing mode"), // Label |
2591 | + _("Block progression"), // Tooltip |
2592 | + NULL, // Icon name |
2593 | + GTK_TREE_MODEL(model) ); // Model |
2594 | + |
2595 | + g_object_set( act, "short_label", "NotUsed", NULL ); |
2596 | + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); |
2597 | + g_object_set_data( holder, "TextWritingModeAction", act ); |
2598 | + |
2599 | + ege_select_one_action_set_appearance( act, "full" ); |
2600 | + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); |
2601 | + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); |
2602 | + ege_select_one_action_set_icon_column( act, 2 ); |
2603 | + ege_select_one_action_set_icon_size( act, secondarySize ); |
2604 | + ege_select_one_action_set_tooltip_column( act, 1 ); |
2605 | + |
2606 | + gint mode = prefs->getInt("/tools/text/writing_mode", 0); |
2607 | + ege_select_one_action_set_active( act, mode ); |
2608 | + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_writing_mode_changed), holder ); |
2609 | + } |
2610 | + |
2611 | + /* Text (glyph) orientation (Auto (mixed), Upright, Sideways) */ |
2612 | + { |
2613 | + GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ); |
2614 | + |
2615 | + GtkTreeIter iter; |
2616 | + |
2617 | + gtk_list_store_append( model, &iter ); |
2618 | + gtk_list_store_set( model, &iter, |
2619 | + 0, _("Auto"), |
2620 | + 1, _("Auto glyph orientation"), |
2621 | + 2, INKSCAPE_ICON("text-orientation-auto"), |
2622 | + 3, true, |
2623 | + -1 ); |
2624 | + |
2625 | + gtk_list_store_append( model, &iter ); |
2626 | + gtk_list_store_set( model, &iter, |
2627 | + 0, _("Upright"), |
2628 | + 1, _("Upright glyph orientation"), |
2629 | + 2, INKSCAPE_ICON("text-orientation-upright"), |
2630 | + 3, true, |
2631 | + -1 ); |
2632 | + |
2633 | + gtk_list_store_append( model, &iter ); |
2634 | + gtk_list_store_set( model, &iter, |
2635 | + 0, _("Sideways"), |
2636 | + 1, _("Sideways glyph orientation"), |
2637 | + 2, INKSCAPE_ICON("text-orientation-sideways"), |
2638 | + 3, true, |
2639 | + -1 ); |
2640 | + |
2641 | EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name |
2642 | - _("Orientation"), // Label |
2643 | - _("Text orientation"), // Tooltip |
2644 | + _("Text orientation"), // Label |
2645 | + _("Text (glyph) orientation in vertical text."), // Tooltip |
2646 | NULL, // Icon name |
2647 | GTK_TREE_MODEL(model) ); // Model |
2648 | |
2649 | @@ -1423,10 +1575,11 @@ |
2650 | ege_select_one_action_set_icon_column( act, 2 ); |
2651 | ege_select_one_action_set_icon_size( act, secondarySize ); |
2652 | ege_select_one_action_set_tooltip_column( act, 1 ); |
2653 | + ege_select_one_action_set_sensitive_column( act, 3 ); |
2654 | |
2655 | - gint mode = prefs->getInt("/tools/text/orientation", 0); |
2656 | + gint mode = prefs->getInt("/tools/text/text_orientation", 0); |
2657 | ege_select_one_action_set_active( act, mode ); |
2658 | - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder ); |
2659 | + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_changed), holder ); |
2660 | } |
2661 | |
2662 | /* Line height */ |
2663 | |
2664 | === modified file 'src/widgets/toolbox.cpp' |
2665 | --- src/widgets/toolbox.cpp 2015-11-21 12:48:59 +0000 |
2666 | +++ src/widgets/toolbox.cpp 2015-11-24 09:40:36 +0000 |
2667 | @@ -517,6 +517,8 @@ |
2668 | " <toolitem action='TextDyAction' />" |
2669 | " <toolitem action='TextRotationAction' />" |
2670 | " <separator />" |
2671 | + " <toolitem action='TextWritingModeAction' />" |
2672 | + " <separator />" |
2673 | " <toolitem action='TextOrientationAction' />" |
2674 | " </toolbar>" |
2675 |