2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
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.
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.
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.
23 #include "SVGTextLayoutEngineBaseline.h"
26 #include "RenderObject.h"
27 #include "SVGRenderStyle.h"
28 #include "SVGTextMetrics.h"
29 #include "UnicodeRange.h"
33 SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font)
38 float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* lengthContext) const
40 if (style->baselineShift() == BS_LENGTH) {
41 SVGLength baselineShiftValueLength = style->baselineShiftValue();
42 if (baselineShiftValueLength.unitType() == LengthTypePercentage)
43 return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize();
45 return baselineShiftValueLength.value(lengthContext);
48 switch (style->baselineShift()) {
52 return -m_font.fontMetrics().floatHeight() / 2;
54 return m_font.fontMetrics().floatHeight() / 2;
61 EAlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const
64 ASSERT(textRenderer->style());
65 ASSERT(textRenderer->parent());
66 ASSERT(textRenderer->parent()->style());
68 const SVGRenderStyle* style = textRenderer->style()->svgStyle();
71 EDominantBaseline baseline = style->dominantBaseline();
72 if (baseline == DB_AUTO) {
74 baseline = DB_CENTRAL;
76 baseline = DB_ALPHABETIC;
81 // FIXME: The dominant-baseline and the baseline-table components are set by determining the predominant script of the character data content.
84 return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
86 return dominantBaselineToAlignmentBaseline(isVerticalText, textRenderer->parent());
88 return AB_IDEOGRAPHIC;
94 return AB_MATHEMATICAL;
99 case DB_TEXT_AFTER_EDGE:
100 return AB_TEXT_AFTER_EDGE;
101 case DB_TEXT_BEFORE_EDGE:
102 return AB_TEXT_BEFORE_EDGE;
104 ASSERT_NOT_REACHED();
109 float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const
111 ASSERT(textRenderer);
112 ASSERT(textRenderer->style());
113 ASSERT(textRenderer->style()->svgStyle());
114 ASSERT(textRenderer->parent());
116 const RenderObject* textRendererParent = textRenderer->parent();
117 ASSERT(textRendererParent);
119 EAlignmentBaseline baseline = textRenderer->style()->svgStyle()->alignmentBaseline();
120 if (baseline == AB_AUTO) {
121 baseline = dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
122 ASSERT(baseline != AB_AUTO);
125 const FontMetrics& fontMetrics = m_font.fontMetrics();
127 // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
130 return dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent);
132 case AB_TEXT_BEFORE_EDGE:
133 return fontMetrics.floatAscent();
135 return fontMetrics.xHeight() / 2;
137 return (fontMetrics.floatAscent() - fontMetrics.floatDescent()) / 2;
139 case AB_TEXT_AFTER_EDGE:
141 return fontMetrics.floatDescent();
145 return fontMetrics.floatAscent() * 8 / 10.f;
146 case AB_MATHEMATICAL:
147 return fontMetrics.floatAscent() / 2;
149 ASSERT_NOT_REACHED();
154 float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle* style, const UChar& character) const
158 switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) {
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)
180 static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle)
182 return !fabsf(fmodf(orientationAngle, 180));
185 float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics& metrics, float angle, float& xOrientationShift, float& yOrientationShift) const
187 bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(angle);
189 // The function is based on spec requirements:
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.
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.
197 const FontMetrics& fontMetrics = m_font.fontMetrics();
199 // Vertical orientation handling.
200 if (isVerticalText) {
201 float ascentMinusDescent = fontMetrics.floatAscent() - fontMetrics.floatDescent();
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;
212 // Vertical advance calculation.
213 if (angle && !orientationIsMultiplyOf180Degrees)
214 return metrics.width();
216 return metrics.height();
219 // Horizontal orientation handling.
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();
228 // Horizontal advance calculation.
229 if (angle && !orientationIsMultiplyOf180Degrees)
230 return metrics.height();
232 return metrics.width();
237 #endif // ENABLE(SVG)