OSDN Git Service

HW accelate button focus rings
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / WidthIterator.cpp
1 /*
2  * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Holger Hans Peter Freyther
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "WidthIterator.h"
24
25 #include "Font.h"
26 #include "GlyphBuffer.h"
27 #include "SimpleFontData.h"
28 #include "TextRun.h"
29 #include <wtf/MathExtras.h>
30
31 #if USE(ICU_UNICODE)
32 #include <unicode/unorm.h>
33 #endif
34
35 using namespace WTF;
36 using namespace Unicode;
37 using namespace std;
38
39 namespace WebCore {
40
41 // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combining_Class_Values
42 static const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
43
44 WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds, bool forTextEmphasis)
45     : m_font(font)
46     , m_run(run)
47     , m_end(run.length())
48     , m_currentCharacter(0)
49     , m_runWidthSoFar(0)
50     , m_isAfterExpansion(!run.allowsLeadingExpansion())
51     , m_fallbackFonts(fallbackFonts)
52     , m_accountForGlyphBounds(accountForGlyphBounds)
53     , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
54     , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
55     , m_firstGlyphOverflow(0)
56     , m_lastGlyphOverflow(0)
57     , m_forTextEmphasis(forTextEmphasis)
58 {
59     // If the padding is non-zero, count the number of spaces in the run
60     // and divide that by the padding for per space addition.
61     m_expansion = m_run.expansion();
62     if (!m_expansion)
63         m_expansionPerOpportunity = 0;
64     else {
65         bool isAfterExpansion = m_isAfterExpansion;
66         unsigned expansionOpportunityCount = Font::expansionOpportunityCount(m_run.characters(), m_end, m_run.ltr() ? LTR : RTL, isAfterExpansion);
67         if (isAfterExpansion && !m_run.allowsTrailingExpansion())
68             expansionOpportunityCount--;
69
70         if (!expansionOpportunityCount)
71             m_expansionPerOpportunity = 0;
72         else
73             m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
74     }
75 }
76
77 void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
78 {
79     if (offset > m_end)
80         offset = m_end;
81
82     int currentCharacter = m_currentCharacter;
83     const UChar* cp = m_run.data(currentCharacter);
84
85     bool rtl = m_run.rtl();
86     bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_expansion) && !m_run.spacingDisabled();
87
88     FloatRect bounds;
89
90     const SimpleFontData* primaryFont = m_font->primaryFont();
91     const SimpleFontData* lastFontData = primaryFont;
92
93     while (currentCharacter < offset) {
94         UChar32 c = *cp;
95         unsigned clusterLength = 1;
96         if (c >= 0x3041) {
97             if (c <= 0x30FE) {
98                 // Deal with Hiragana and Katakana voiced and semi-voiced syllables.
99                 // Normalize into composed form, and then look for glyph with base + combined mark.
100                 // Check above for character range to minimize performance impact.
101                 UChar32 normalized = normalizeVoicingMarks(currentCharacter);
102                 if (normalized) {
103                     c = normalized;
104                     clusterLength = 2;
105                 }
106             } else if (U16_IS_SURROGATE(c)) {
107                 if (!U16_IS_SURROGATE_LEAD(c))
108                     break;
109
110                 // Do we have a surrogate pair?  If so, determine the full Unicode (32 bit)
111                 // code point before glyph lookup.
112                 // Make sure we have another character and it's a low surrogate.
113                 if (currentCharacter + 1 >= m_run.length())
114                     break;
115                 UChar low = cp[1];
116                 if (!U16_IS_TRAIL(low))
117                     break;
118                 c = U16_GET_SUPPLEMENTARY(c, low);
119                 clusterLength = 2;
120             }
121         }
122
123         const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl);
124         Glyph glyph = glyphData.glyph;
125         const SimpleFontData* fontData = glyphData.fontData;
126
127         ASSERT(fontData);
128
129         // Now that we have a glyph and font data, get its width.
130         float width;
131         if (c == '\t' && m_run.allowTabs()) {
132             float tabWidth = m_font->tabWidth(*fontData);
133             width = tabWidth - fmodf(m_run.xPos() + m_runWidthSoFar, tabWidth);
134         } else {
135             width = fontData->widthForGlyph(glyph);
136
137 #if ENABLE(SVG)
138             // SVG uses horizontalGlyphStretch(), when textLength is used to stretch/squeeze text.
139             width *= m_run.horizontalGlyphStretch();
140 #endif
141         }
142
143         if (fontData != lastFontData && width) {
144             lastFontData = fontData;
145             if (m_fallbackFonts && fontData != primaryFont) {
146                 // FIXME: This does a little extra work that could be avoided if
147                 // glyphDataForCharacter() returned whether it chose to use a small caps font.
148                 if (!m_font->isSmallCaps() || c == toUpper(c))
149                     m_fallbackFonts->add(fontData);
150                 else {
151                     const GlyphData& uppercaseGlyphData = m_font->glyphDataForCharacter(toUpper(c), rtl);
152                     if (uppercaseGlyphData.fontData != primaryFont)
153                         m_fallbackFonts->add(uppercaseGlyphData.fontData);
154                 }
155             }
156         }
157
158         if (hasExtraSpacing) {
159             // Account for letter-spacing.
160             if (width && m_font->letterSpacing())
161                 width += m_font->letterSpacing();
162
163             static bool expandAroundIdeographs = Font::canExpandAroundIdeographsInComplexText();
164             bool treatAsSpace = Font::treatAsSpace(c);
165             if (treatAsSpace || (expandAroundIdeographs && Font::isCJKIdeographOrSymbol(c))) {
166                 // Distribute the run's total expansion evenly over all expansion opportunities in the run.
167                 if (m_expansion) {
168                     if (!treatAsSpace && !m_isAfterExpansion) {
169                         // Take the expansion opportunity before this ideograph.
170                         m_expansion -= m_expansionPerOpportunity;
171                         m_runWidthSoFar += m_expansionPerOpportunity;
172                         if (glyphBuffer) {
173                             if (glyphBuffer->isEmpty())
174                                 glyphBuffer->add(fontData->spaceGlyph(), fontData, m_expansionPerOpportunity);
175                             else
176                                 glyphBuffer->expandLastAdvance(m_expansionPerOpportunity);
177                         }
178                     }
179                     if (m_run.allowsTrailingExpansion() || (m_run.ltr() && currentCharacter + clusterLength < static_cast<size_t>(m_run.length()))
180                         || (m_run.rtl() && currentCharacter)) {
181                         m_expansion -= m_expansionPerOpportunity;
182                         width += m_expansionPerOpportunity;
183                         m_isAfterExpansion = true;
184                     }
185                 } else
186                     m_isAfterExpansion = false;
187
188                 // Account for word spacing.
189                 // We apply additional space between "words" by adding width to the space character.
190                 if (treatAsSpace && currentCharacter && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing())
191                     width += m_font->wordSpacing();
192             } else
193                 m_isAfterExpansion = false;
194         }
195
196         if (m_accountForGlyphBounds) {
197             bounds = fontData->boundsForGlyph(glyph);
198             if (!currentCharacter)
199                 m_firstGlyphOverflow = max<float>(0, -bounds.x());
200         }
201
202         if (m_forTextEmphasis && !Font::canReceiveTextEmphasis(c))
203             glyph = 0;
204
205         // Advance past the character we just dealt with.
206         cp += clusterLength;
207         currentCharacter += clusterLength;
208
209         m_runWidthSoFar += width;
210
211         if (glyphBuffer)
212             glyphBuffer->add(glyph, fontData, width);
213
214         if (m_accountForGlyphBounds) {
215             m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.maxY());
216             m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, bounds.y());
217             m_lastGlyphOverflow = max<float>(0, bounds.maxX() - width);
218         }
219     }
220
221     m_currentCharacter = currentCharacter;
222 }
223
224 bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
225 {
226     int oldSize = glyphBuffer->size();
227     advance(m_currentCharacter + 1, glyphBuffer);
228     float w = 0;
229     for (int i = oldSize; i < glyphBuffer->size(); ++i)
230         w += glyphBuffer->advanceAt(i);
231     width = w;
232     return glyphBuffer->size() > oldSize;
233 }
234
235 UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter)
236 {
237     if (currentCharacter + 1 < m_end) {
238         if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoicingMarksCombiningClass) {
239 #if USE(ICU_UNICODE)
240             // Normalize into composed form using 3.2 rules.
241             UChar normalizedCharacters[2] = { 0, 0 };
242             UErrorCode uStatus = U_ZERO_ERROR;  
243             int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2,
244                 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uStatus);
245             if (resultLength == 1 && uStatus == 0)
246                 return normalizedCharacters[0];
247 #elif USE(QT4_UNICODE)
248             QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharacter)), 2);
249             QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Unicode_3_2);
250             if (res.length() == 1)
251                 return res.at(0).unicode();
252 #endif
253         }
254     }
255     return 0;
256 }
257
258 }