Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1311)

Side by Side Diff: Source/core/platform/graphics/WidthIterator.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2003, 2006, 2008, 2009, 2010, 2011 Apple Inc. All rights reserv ed.
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 "core/platform/graphics/WidthIterator.h"
24
25 #include "core/platform/graphics/SimpleFontData.h"
26 #include "platform/fonts/GlyphBuffer.h"
27 #include "platform/fonts/Latin1TextIterator.h"
28 #include "platform/text/SurrogatePairAwareTextIterator.h"
29 #include "wtf/MathExtras.h"
30
31 using namespace WTF;
32 using namespace Unicode;
33 using namespace std;
34
35 namespace WebCore {
36
37 WidthIterator::WidthIterator(const Font* font, const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, bool accountForGlyphBounds, bool forTextEmphas is)
38 : m_font(font)
39 , m_run(run)
40 , m_currentCharacter(0)
41 , m_runWidthSoFar(0)
42 , m_isAfterExpansion(!run.allowsLeadingExpansion())
43 , m_finalRoundingWidth(0)
44 , m_typesettingFeatures(font->typesettingFeatures())
45 , m_fallbackFonts(fallbackFonts)
46 , m_accountForGlyphBounds(accountForGlyphBounds)
47 , m_maxGlyphBoundingBoxY(numeric_limits<float>::min())
48 , m_minGlyphBoundingBoxY(numeric_limits<float>::max())
49 , m_firstGlyphOverflow(0)
50 , m_lastGlyphOverflow(0)
51 , m_forTextEmphasis(forTextEmphasis)
52 {
53 // If the padding is non-zero, count the number of spaces in the run
54 // and divide that by the padding for per space addition.
55 m_expansion = m_run.expansion();
56 if (!m_expansion)
57 m_expansionPerOpportunity = 0;
58 else {
59 bool isAfterExpansion = m_isAfterExpansion;
60 unsigned expansionOpportunityCount = m_run.is8Bit() ? Font::expansionOpp ortunityCount(m_run.characters8(), m_run.length(), m_run.ltr() ? LTR : RTL, isAf terExpansion) : Font::expansionOpportunityCount(m_run.characters16(), m_run.leng th(), m_run.ltr() ? LTR : RTL, isAfterExpansion);
61 if (isAfterExpansion && !m_run.allowsTrailingExpansion())
62 expansionOpportunityCount--;
63
64 if (!expansionOpportunityCount)
65 m_expansionPerOpportunity = 0;
66 else
67 m_expansionPerOpportunity = m_expansion / expansionOpportunityCount;
68 }
69 }
70
71 GlyphData WidthIterator::glyphDataForCharacter(UChar32 character, bool mirror, i nt currentCharacter, unsigned& advanceLength)
72 {
73 ASSERT(m_font);
74
75 #if ENABLE(SVG_FONTS)
76 if (TextRun::RenderingContext* renderingContext = m_run.renderingContext())
77 return renderingContext->glyphDataForCharacter(*m_font, m_run, *this, ch aracter, mirror, currentCharacter, advanceLength);
78 #else
79 UNUSED_PARAM(currentCharacter);
80 UNUSED_PARAM(advanceLength);
81 #endif
82
83 return m_font->glyphDataForCharacter(character, mirror);
84 }
85
86 struct OriginalAdvancesForCharacterTreatedAsSpace {
87 public:
88 OriginalAdvancesForCharacterTreatedAsSpace(bool isSpace, float advanceBefore , float advanceAt)
89 : characterIsSpace(isSpace)
90 , advanceBeforeCharacter(advanceBefore)
91 , advanceAtCharacter(advanceAt)
92 {
93 }
94
95 bool characterIsSpace;
96 float advanceBeforeCharacter;
97 float advanceAtCharacter;
98 };
99
100 typedef Vector<pair<int, OriginalAdvancesForCharacterTreatedAsSpace>, 64> Charac tersTreatedAsSpace;
101
102 static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, unsi gned& lastGlyphCount, const SimpleFontData* fontData, TypesettingFeatures typese ttingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace)
103 {
104 ASSERT(typesettingFeatures & (Kerning | Ligatures));
105
106 if (!glyphBuffer)
107 return 0;
108
109 unsigned glyphBufferSize = glyphBuffer->size();
110 if (glyphBuffer->size() <= lastGlyphCount + 1)
111 return 0;
112
113 GlyphBufferAdvance* advances = glyphBuffer->advances(0);
114 float widthDifference = 0;
115 for (unsigned i = lastGlyphCount; i < glyphBufferSize; ++i)
116 widthDifference -= advances[i].width();
117
118 if (!ltr)
119 glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);
120
121 fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + la stGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures);
122
123 if (!ltr)
124 glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);
125
126 for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) {
127 int spaceOffset = charactersTreatedAsSpace[i].first;
128 const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = cha ractersTreatedAsSpace[i].second;
129 if (spaceOffset && !originalAdvances.characterIsSpace)
130 glyphBuffer->advances(spaceOffset - 1)->setWidth(originalAdvances.ad vanceBeforeCharacter);
131 glyphBuffer->advances(spaceOffset)->setWidth(originalAdvances.advanceAtC haracter);
132 }
133 charactersTreatedAsSpace.clear();
134
135 for (unsigned i = lastGlyphCount; i < glyphBufferSize; ++i)
136 widthDifference += advances[i].width();
137
138 lastGlyphCount = glyphBufferSize;
139 return widthDifference;
140 }
141
142 template <typename TextIterator>
143 inline unsigned WidthIterator::advanceInternal(TextIterator& textIterator, Glyph Buffer* glyphBuffer)
144 {
145 bool rtl = m_run.rtl();
146 bool hasExtraSpacing = (m_font->letterSpacing() || m_font->wordSpacing() || m_expansion) && !m_run.spacingDisabled();
147
148 float widthSinceLastRounding = m_runWidthSoFar;
149 m_runWidthSoFar = floorf(m_runWidthSoFar);
150 widthSinceLastRounding -= m_runWidthSoFar;
151
152 float lastRoundingWidth = m_finalRoundingWidth;
153 FloatRect bounds;
154
155 const SimpleFontData* primaryFont = m_font->primaryFont();
156 const SimpleFontData* lastFontData = primaryFont;
157 unsigned lastGlyphCount = glyphBuffer ? glyphBuffer->size() : 0;
158
159 UChar32 character = 0;
160 unsigned clusterLength = 0;
161 CharactersTreatedAsSpace charactersTreatedAsSpace;
162 while (textIterator.consume(character, clusterLength)) {
163 unsigned advanceLength = clusterLength;
164 const GlyphData& glyphData = glyphDataForCharacter(character, rtl, textI terator.currentCharacter(), advanceLength);
165 Glyph glyph = glyphData.glyph;
166 const SimpleFontData* fontData = glyphData.fontData;
167
168 ASSERT(fontData);
169
170 // Now that we have a glyph and font data, get its width.
171 float width;
172 if (character == '\t' && m_run.allowTabs())
173 width = m_font->tabWidth(*fontData, m_run.tabSize(), m_run.xPos() + m_runWidthSoFar + widthSinceLastRounding);
174 else {
175 width = fontData->widthForGlyph(glyph);
176
177 // SVG uses horizontalGlyphStretch(), when textLength is used to str etch/squeeze text.
178 width *= m_run.horizontalGlyphStretch();
179
180 // We special case spaces in two ways when applying word rounding.
181 // First, we round spaces to an adjusted width in all fonts.
182 // Second, in fixed-pitch fonts we ensure that all characters that
183 // match the width of the space character have the same width as the space character.
184 if (m_run.applyWordRounding() && width == fontData->spaceWidth() && (fontData->pitch() == FixedPitch || glyph == fontData->spaceGlyph()))
185 width = fontData->adjustedSpaceWidth();
186 }
187
188 if (fontData != lastFontData && width) {
189 if (shouldApplyFontTransforms())
190 m_runWidthSoFar += applyFontTransforms(glyphBuffer, m_run.ltr(), lastGlyphCount, lastFontData, m_typesettingFeatures, charactersTreatedAsSpace);
191
192 lastFontData = fontData;
193 if (m_fallbackFonts && fontData != primaryFont) {
194 // FIXME: This does a little extra work that could be avoided if
195 // glyphDataForCharacter() returned whether it chose to use a sm all caps font.
196 if (!m_font->isSmallCaps() || character == toUpper(character))
197 m_fallbackFonts->add(fontData);
198 else {
199 const GlyphData& uppercaseGlyphData = m_font->glyphDataForCh aracter(toUpper(character), rtl);
200 if (uppercaseGlyphData.fontData != primaryFont)
201 m_fallbackFonts->add(uppercaseGlyphData.fontData);
202 }
203 }
204 }
205
206 if (hasExtraSpacing) {
207 // Account for letter-spacing.
208 if (width && m_font->letterSpacing())
209 width += m_font->letterSpacing();
210
211 static bool expandAroundIdeographs = Font::canExpandAroundIdeographs InComplexText();
212 bool treatAsSpace = Font::treatAsSpace(character);
213 if (treatAsSpace || (expandAroundIdeographs && Font::isCJKIdeographO rSymbol(character))) {
214 // Distribute the run's total expansion evenly over all expansio n opportunities in the run.
215 if (m_expansion) {
216 float previousExpansion = m_expansion;
217 if (!treatAsSpace && !m_isAfterExpansion) {
218 // Take the expansion opportunity before this ideograph.
219 m_expansion -= m_expansionPerOpportunity;
220 float expansionAtThisOpportunity = !m_run.applyWordRound ing() ? m_expansionPerOpportunity : roundf(previousExpansion) - roundf(m_expansi on);
221 m_runWidthSoFar += expansionAtThisOpportunity;
222 if (glyphBuffer) {
223 if (glyphBuffer->isEmpty()) {
224 if (m_forTextEmphasis)
225 glyphBuffer->add(fontData->zeroWidthSpaceGly ph(), fontData, m_expansionPerOpportunity);
226 else
227 glyphBuffer->add(fontData->spaceGlyph(), fon tData, expansionAtThisOpportunity);
228 } else
229 glyphBuffer->expandLastAdvance(expansionAtThisOp portunity);
230 }
231 previousExpansion = m_expansion;
232 }
233 if (m_run.allowsTrailingExpansion() || (m_run.ltr() && textI terator.currentCharacter() + advanceLength < static_cast<size_t>(m_run.length()) )
234 || (m_run.rtl() && textIterator.currentCharacter())) {
235 m_expansion -= m_expansionPerOpportunity;
236 width += !m_run.applyWordRounding() ? m_expansionPerOppo rtunity : roundf(previousExpansion) - roundf(m_expansion);
237 m_isAfterExpansion = true;
238 }
239 } else
240 m_isAfterExpansion = false;
241
242 // Account for word spacing.
243 // We apply additional space between "words" by adding width to the space character.
244 if (treatAsSpace && (character != '\t' || !m_run.allowTabs()) && (textIterator.currentCharacter() || character == noBreakSpace) && m_font->wordS pacing())
245 width += m_font->wordSpacing();
246 } else
247 m_isAfterExpansion = false;
248 }
249
250 if (shouldApplyFontTransforms() && glyphBuffer && Font::treatAsSpace(cha racter))
251 charactersTreatedAsSpace.append(make_pair(glyphBuffer->size(),
252 OriginalAdvancesForCharacterTreatedAsSpace(character == ' ', gly phBuffer->size() ? glyphBuffer->advanceAt(glyphBuffer->size() - 1) : 0, width))) ;
253
254 if (m_accountForGlyphBounds) {
255 bounds = fontData->boundsForGlyph(glyph);
256 if (!textIterator.currentCharacter())
257 m_firstGlyphOverflow = max<float>(0, -bounds.x());
258 }
259
260 if (m_forTextEmphasis && !Font::canReceiveTextEmphasis(character))
261 glyph = 0;
262
263 // Advance past the character we just dealt with.
264 textIterator.advance(advanceLength);
265
266 float oldWidth = width;
267
268 // Force characters that are used to determine word boundaries for the r ounding hack
269 // to be integer width, so following words will start on an integer boun dary.
270 if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(character )) {
271 width = ceilf(width);
272
273 // Since widthSinceLastRounding can lose precision if we include mea surements for
274 // preceding whitespace, we bypass it here.
275 m_runWidthSoFar += width;
276
277 // Since this is a rounding hack character, we should have reset thi s sum on the previous
278 // iteration.
279 ASSERT(!widthSinceLastRounding);
280 } else {
281 // Check to see if the next character is a "rounding hack character" , if so, adjust
282 // width so that the total run width will be on an integer boundary.
283 if ((m_run.applyWordRounding() && textIterator.currentCharacter() < m_run.length() && Font::isRoundingHackCharacter(*(textIterator.characters())))
284 || (m_run.applyRunRounding() && textIterator.currentCharacter() >= m_run.length())) {
285 float totalWidth = widthSinceLastRounding + width;
286 widthSinceLastRounding = ceilf(totalWidth);
287 width += widthSinceLastRounding - totalWidth;
288 m_runWidthSoFar += widthSinceLastRounding;
289 widthSinceLastRounding = 0;
290 } else
291 widthSinceLastRounding += width;
292 }
293
294 if (glyphBuffer)
295 glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidt h : width));
296
297 lastRoundingWidth = width - oldWidth;
298
299 if (m_accountForGlyphBounds) {
300 m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, bounds.maxY());
301 m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, bounds.y());
302 m_lastGlyphOverflow = max<float>(0, bounds.maxX() - width);
303 }
304 }
305
306 if (shouldApplyFontTransforms())
307 m_runWidthSoFar += applyFontTransforms(glyphBuffer, m_run.ltr(), lastGly phCount, lastFontData, m_typesettingFeatures, charactersTreatedAsSpace);
308
309 unsigned consumedCharacters = textIterator.currentCharacter() - m_currentCha racter;
310 m_currentCharacter = textIterator.currentCharacter();
311 m_runWidthSoFar += widthSinceLastRounding;
312 m_finalRoundingWidth = lastRoundingWidth;
313 return consumedCharacters;
314 }
315
316 unsigned WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
317 {
318 int length = m_run.length();
319
320 if (offset > length)
321 offset = length;
322
323 if (m_currentCharacter >= static_cast<unsigned>(offset))
324 return 0;
325
326 if (m_run.is8Bit()) {
327 Latin1TextIterator textIterator(m_run.data8(m_currentCharacter), m_curre ntCharacter, offset, length);
328 return advanceInternal(textIterator, glyphBuffer);
329 }
330
331 SurrogatePairAwareTextIterator textIterator(m_run.data16(m_currentCharacter) , m_currentCharacter, offset, length);
332 return advanceInternal(textIterator, glyphBuffer);
333 }
334
335 bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer& glyphBuffer)
336 {
337 unsigned oldSize = glyphBuffer.size();
338 advance(m_currentCharacter + 1, &glyphBuffer);
339 float w = 0;
340 for (unsigned i = oldSize; i < glyphBuffer.size(); ++i)
341 w += glyphBuffer.advanceAt(i);
342 width = w;
343 return glyphBuffer.size() > oldSize;
344 }
345
346 }
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/WidthIterator.h ('k') | Source/core/platform/graphics/android/FontCacheAndroid.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698