• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 
22 #if ENABLE(SVG)
23 #include "SVGTextLayoutEngineBaseline.h"
24 
25 #include "Font.h"
26 #include "RenderObject.h"
27 #include "SVGRenderStyle.h"
28 #include "SVGTextMetrics.h"
29 #include "UnicodeRange.h"
30 
31 namespace WebCore {
32 
SVGTextLayoutEngineBaseline(const Font & font)33 SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font)
34     : m_font(font)
35 {
36 }
37 
calculateBaselineShift(const SVGRenderStyle * style,SVGElement * lengthContext) const38 float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* lengthContext) const
39 {
40     if (style->baselineShift() == BS_LENGTH) {
41         SVGLength baselineShiftValueLength = style->baselineShiftValue();
42         if (baselineShiftValueLength.unitType() == LengthTypePercentage)
43             return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize();
44 
45         return baselineShiftValueLength.value(lengthContext);
46     }
47 
48     switch (style->baselineShift()) {
49     case BS_BASELINE:
50         return 0;
51     case BS_SUB:
52         return -m_font.fontMetrics().floatHeight() / 2;
53     case BS_SUPER:
54         return m_font.fontMetrics().floatHeight() / 2;
55     default:
56         ASSERT_NOT_REACHED();
57         return 0;
58     }
59 }
60 
dominantBaselineToAlignmentBaseline(bool isVerticalText,const RenderObject * textRenderer) const61 EAlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const
62 {
63     ASSERT(textRenderer);
64     ASSERT(textRenderer->style());
65     ASSERT(textRenderer->parent());
66     ASSERT(textRenderer->parent()->style());
67 
68     const SVGRenderStyle* style = textRenderer->style()->svgStyle();
69     ASSERT(style);
70 
71     EDominantBaseline baseline = style->dominantBaseline();
72     if (baseline == DB_AUTO) {
73         if (isVerticalText)
74             baseline = DB_CENTRAL;
75         else
76             baseline = DB_ALPHABETIC;
77     }
78 
79     switch (baseline) {
80     case DB_USE_SCRIPT:
81         // FIXME: The dominant-baseline and the baseline-table components are set by determining the predominant script of the character data content.
82         return AB_ALPHABETIC;
83     case DB_NO_CHANGE:
84         return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
85     case DB_RESET_SIZE:
86         return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
87     case DB_IDEOGRAPHIC:
88         return AB_IDEOGRAPHIC;
89     case DB_ALPHABETIC:
90         return AB_ALPHABETIC;
91     case DB_HANGING:
92         return AB_HANGING;
93     case DB_MATHEMATICAL:
94         return AB_MATHEMATICAL;
95     case DB_CENTRAL:
96         return AB_CENTRAL;
97     case DB_MIDDLE:
98         return AB_MIDDLE;
99     case DB_TEXT_AFTER_EDGE:
100         return AB_TEXT_AFTER_EDGE;
101     case DB_TEXT_BEFORE_EDGE:
102         return AB_TEXT_BEFORE_EDGE;
103     default:
104         ASSERT_NOT_REACHED();
105         return AB_AUTO;
106     }
107 }
108 
calculateAlignmentBaselineShift(bool isVerticalText,const RenderObject * textRenderer) const109 float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const
110 {
111     ASSERT(textRenderer);
112     ASSERT(textRenderer->style());
113     ASSERT(textRenderer->style()->svgStyle());
114     ASSERT(textRenderer->parent());
115 
116     const RenderObject* textRendererParent = textRenderer->parent();
117     ASSERT(textRendererParent);
118 
119     EAlignmentBaseline baseline = textRenderer->style()->svgStyle()->alignmentBaseline();
120     if (baseline == AB_AUTO) {
121         baseline = dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
122         ASSERT(baseline != AB_AUTO);
123     }
124 
125     const FontMetrics& fontMetrics = m_font.fontMetrics();
126 
127     // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
128     switch (baseline) {
129     case AB_BASELINE:
130         return dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
131     case AB_BEFORE_EDGE:
132     case AB_TEXT_BEFORE_EDGE:
133         return fontMetrics.floatAscent();
134     case AB_MIDDLE:
135         return fontMetrics.xHeight() / 2;
136     case AB_CENTRAL:
137         return (fontMetrics.floatAscent() - fontMetrics.floatDescent()) / 2;
138     case AB_AFTER_EDGE:
139     case AB_TEXT_AFTER_EDGE:
140     case AB_IDEOGRAPHIC:
141         return fontMetrics.floatDescent();
142     case AB_ALPHABETIC:
143         return 0;
144     case AB_HANGING:
145         return fontMetrics.floatAscent() * 8 / 10.f;
146     case AB_MATHEMATICAL:
147         return fontMetrics.floatAscent() / 2;
148     default:
149         ASSERT_NOT_REACHED();
150         return 0;
151     }
152 }
153 
calculateGlyphOrientationAngle(bool isVerticalText,const SVGRenderStyle * style,const UChar & character) const154 float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle* style, const UChar& character) const
155 {
156     ASSERT(style);
157 
158     switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) {
159     case GO_AUTO: {
160         // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees.
161         // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees.
162         unsigned int unicodeRange = findCharUnicodeRange(character);
163         if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic)
164             return 90;
165 
166         return 0;
167     }
168     case GO_90DEG:
169         return 90;
170     case GO_180DEG:
171         return 180;
172     case GO_270DEG:
173         return 270;
174     case GO_0DEG:
175     default:
176         return 0;
177     }
178 }
179 
glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)180 static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
181 {
182     return !fabsf(fmodf(orientationAngle, 180));
183 }
184 
calculateGlyphAdvanceAndOrientation(bool isVerticalText,SVGTextMetrics & metrics,float angle,float & xOrientationShift,float & yOrientationShift) const185 float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics& metrics, float angle, float& xOrientationShift, float& yOrientationShift) const
186 {
187     bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(angle);
188 
189     // The function is based on spec requirements:
190     //
191     // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of
192     // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph.
193     //
194     // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of
195     // 180 degrees, then the current text position is incremented according to the horizontal metrics of the glyph.
196 
197     const FontMetrics& fontMetrics = m_font.fontMetrics();
198 
199     // Vertical orientation handling.
200     if (isVerticalText) {
201         float ascentMinusDescent = fontMetrics.floatAscent() - fontMetrics.floatDescent();
202         if (!angle) {
203             xOrientationShift = (ascentMinusDescent - metrics.width()) / 2;
204             yOrientationShift = fontMetrics.floatAscent();
205         } else if (angle == 180)
206             xOrientationShift = (ascentMinusDescent + metrics.width()) / 2;
207         else if (angle == 270) {
208             yOrientationShift = metrics.width();
209             xOrientationShift = ascentMinusDescent;
210         }
211 
212         // Vertical advance calculation.
213         if (angle && !orientationIsMultiplyOf180Degrees)
214             return metrics.width();
215 
216         return metrics.height();
217     }
218 
219     // Horizontal orientation handling.
220     if (angle == 90)
221         yOrientationShift = -metrics.width();
222     else if (angle == 180) {
223         xOrientationShift = metrics.width();
224         yOrientationShift = -fontMetrics.floatAscent();
225     } else if (angle == 270)
226         xOrientationShift = metrics.width();
227 
228     // Horizontal advance calculation.
229     if (angle && !orientationIsMultiplyOf180Degrees)
230         return metrics.height();
231 
232     return metrics.width();
233 }
234 
235 }
236 
237 #endif // ENABLE(SVG)
238