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

Side by Side Diff: webkit/pending/Font.cpp

Issue 6500: Cleaning up the unfork (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months 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
« no previous file with comments | « webkit/pending/FileSystemWin.cpp ('k') | webkit/pending/FontCache.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /**
2 * This file is part of the html renderer for KDE.
3 *
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2000 Dirk Mueller (mueller@kde.org)
7 * Copyright (C) 2003, 2006 Apple Computer, Inc.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26 #include "config.h"
27 #include "Font.h"
28
29 #include "CharacterNames.h"
30 #include "FloatRect.h"
31 #include "FontCache.h"
32 #include "FontFallbackList.h"
33 #include "IntPoint.h"
34 #include "GlyphBuffer.h"
35 #include <wtf/unicode/Unicode.h>
36 #include <wtf/MathExtras.h>
37
38 #if USE(ICU_UNICODE)
39 #include <unicode/unorm.h>
40 #endif
41
42 using namespace WTF;
43 using namespace Unicode;
44
45 namespace WebCore {
46
47 // According to http://www.unicode.org/Public/UNIDATA/UCD.html#Canonical_Combini ng_Class_Values
48 const uint8_t hiraganaKatakanaVoicingMarksCombiningClass = 8;
49
50 const uint8_t Font::gRoundingHackCharacterTable[256] = {
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/,
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0,
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0,
56 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0,
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0, 0
59 };
60
61 Font::CodePath Font::codePath = Auto;
62
63 struct WidthIterator {
64 WidthIterator(const Font* font, const TextRun& run);
65
66 void advance(int to, GlyphBuffer* glyphBuffer = 0);
67 bool advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer = 0);
68
69 const Font* m_font;
70
71 const TextRun& m_run;
72 int m_end;
73
74 unsigned m_currentCharacter;
75 float m_runWidthSoFar;
76 float m_padding;
77 float m_padPerSpace;
78 float m_finalRoundingWidth;
79
80 private:
81 UChar32 normalizeVoicingMarks(int currentCharacter);
82 };
83
84 WidthIterator::WidthIterator(const Font* font, const TextRun& run)
85 : m_font(font)
86 , m_run(run)
87 , m_end(run.length())
88 , m_currentCharacter(0)
89 , m_runWidthSoFar(0)
90 , m_finalRoundingWidth(0)
91 {
92 // If the padding is non-zero, count the number of spaces in the run
93 // and divide that by the padding for per space addition.
94 m_padding = m_run.padding();
95 if (!m_padding)
96 m_padPerSpace = 0;
97 else {
98 float numSpaces = 0;
99 for (int i = 0; i < run.length(); i++)
100 if (Font::treatAsSpace(m_run[i]))
101 numSpaces++;
102
103 if (numSpaces == 0)
104 m_padPerSpace = 0;
105 else
106 m_padPerSpace = ceilf(m_run.padding() / numSpaces);
107 }
108 }
109
110 void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
111 {
112 if (offset > m_end)
113 offset = m_end;
114
115 int currentCharacter = m_currentCharacter;
116 const UChar* cp = m_run.data(currentCharacter);
117
118 bool rtl = m_run.rtl();
119 bool hasExtraSpacing = m_font->letterSpacing() || m_font->wordSpacing() || m _padding;
120
121 float runWidthSoFar = m_runWidthSoFar;
122 float lastRoundingWidth = m_finalRoundingWidth;
123
124 while (currentCharacter < offset) {
125 UChar32 c = *cp;
126 unsigned clusterLength = 1;
127 if (c >= 0x3041) {
128 if (c <= 0x30FE) {
129 // Deal with Hiragana and Katakana voiced and semi-voiced syllab les.
130 // Normalize into composed form, and then look for glyph with ba se + combined mark.
131 // Check above for character range to minimize performance impac t.
132 UChar32 normalized = normalizeVoicingMarks(currentCharacter);
133 if (normalized) {
134 c = normalized;
135 clusterLength = 2;
136 }
137 } else if (U16_IS_SURROGATE(c)) {
138 if (!U16_IS_SURROGATE_LEAD(c))
139 break;
140
141 // Do we have a surrogate pair? If so, determine the full Unico de (32 bit)
142 // code point before glyph lookup.
143 // Make sure we have another character and it's a low surrogate.
144 if (currentCharacter + 1 >= m_run.length())
145 break;
146 UChar low = cp[1];
147 if (!U16_IS_TRAIL(low))
148 break;
149 c = U16_GET_SUPPLEMENTARY(c, low);
150 clusterLength = 2;
151 }
152 }
153
154 const GlyphData& glyphData = m_font->glyphDataForCharacter(c, rtl);
155 Glyph glyph = glyphData.glyph;
156 const SimpleFontData* fontData = glyphData.fontData;
157
158 ASSERT(fontData);
159
160 // Now that we have a glyph and font data, get its width.
161 float width;
162 if (c == '\t' && m_run.allowTabs()) {
163 float tabWidth = m_font->tabWidth();
164 width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth);
165 } else {
166 width = fontData->widthForGlyph(glyph);
167 // We special case spaces in two ways when applying word rounding.
168 // First, we round spaces to an adjusted width in all fonts.
169 // Second, in fixed-pitch fonts we ensure that all characters that
170 // match the width of the space character have the same width as the space character.
171 if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitc h || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding())
172 width = fontData->m_adjustedSpaceWidth;
173 }
174
175 if (hasExtraSpacing && !m_run.spacingDisabled()) {
176 // Account for letter-spacing.
177 if (width && m_font->letterSpacing())
178 width += m_font->letterSpacing();
179
180 if (Font::treatAsSpace(c)) {
181 // Account for padding. WebCore uses space padding to justify te xt.
182 // We distribute the specified padding over the available spaces in the run.
183 if (m_padding) {
184 // Use left over padding if not evenly divisible by number o f spaces.
185 if (m_padding < m_padPerSpace) {
186 width += m_padding;
187 m_padding = 0;
188 } else {
189 width += m_padPerSpace;
190 m_padding -= m_padPerSpace;
191 }
192 }
193
194 // Account for word spacing.
195 // We apply additional space between "words" by adding width to the space character.
196 if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_fo nt->wordSpacing())
197 width += m_font->wordSpacing();
198 }
199 }
200
201 // Advance past the character we just dealt with.
202 cp += clusterLength;
203 currentCharacter += clusterLength;
204
205 // Account for float/integer impedance mismatch between CG and KHTML. "W ords" (characters
206 // followed by a character defined by isRoundingHackCharacter()) are alw ays an integer width.
207 // We adjust the width of the last character of a "word" to ensure an in teger width.
208 // If we move KHTML to floats we can remove this (and related) hacks.
209
210 float oldWidth = width;
211
212 // Force characters that are used to determine word boundaries for the r ounding hack
213 // to be integer width, so following words will start on an integer boun dary.
214 if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c))
215 width = ceilf(width);
216
217 // Check to see if the next character is a "rounding hack character", if so, adjust
218 // width so that the total run width will be on an integer boundary.
219 if ((m_run.applyWordRounding() && currentCharacter < m_run.length() && F ont::isRoundingHackCharacter(*cp))
220 || (m_run.applyRunRounding() && currentCharacter >= m_end)) {
221 float totalWidth = runWidthSoFar + width;
222 width += ceilf(totalWidth) - totalWidth;
223 }
224
225 runWidthSoFar += width;
226
227 if (glyphBuffer)
228 glyphBuffer->add(glyph, fontData, (rtl ? oldWidth + lastRoundingWidt h : width));
229
230 lastRoundingWidth = width - oldWidth;
231 }
232
233 m_currentCharacter = currentCharacter;
234 m_runWidthSoFar = runWidthSoFar;
235 m_finalRoundingWidth = lastRoundingWidth;
236 }
237
238 bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
239 {
240 glyphBuffer->clear();
241 advance(m_currentCharacter + 1, glyphBuffer);
242 float w = 0;
243 for (int i = 0; i < glyphBuffer->size(); ++i)
244 w += glyphBuffer->advanceAt(i);
245 width = w;
246 return !glyphBuffer->isEmpty();
247 }
248
249 UChar32 WidthIterator::normalizeVoicingMarks(int currentCharacter)
250 {
251 if (currentCharacter + 1 < m_end) {
252 if (combiningClass(m_run[currentCharacter + 1]) == hiraganaKatakanaVoici ngMarksCombiningClass) {
253 #if USE(ICU_UNICODE)
254 // Normalize into composed form using 3.2 rules.
255 UChar normalizedCharacters[2] = { 0, 0 };
256 UErrorCode uStatus = U_ZERO_ERROR;
257 int32_t resultLength = unorm_normalize(m_run.data(currentCharacter), 2,
258 UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0], 2, &uSta tus);
259 if (resultLength == 1 && uStatus == 0)
260 return normalizedCharacters[0];
261 #elif USE(QT4_UNICODE)
262 QString tmp(reinterpret_cast<const QChar*>(m_run.data(currentCharact er)), 2);
263 QString res = tmp.normalized(QString::NormalizationForm_C, QChar::Un icode_3_2);
264 if (res.length() == 1)
265 return res.at(0).unicode();
266 #endif
267 }
268 }
269 return 0;
270 }
271
272 // ============================================================================= ===============
273 // Font Implementation (Cross-Platform Portion)
274 // ============================================================================= ===============
275
276 Font::Font()
277 : m_pageZero(0)
278 , m_cachedPrimaryFont(0)
279 , m_letterSpacing(0)
280 , m_wordSpacing(0)
281 , m_isPlatformFont(false)
282 {
283 }
284
285 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
286 : m_fontDescription(fd)
287 , m_pageZero(0)
288 , m_cachedPrimaryFont(0)
289 , m_letterSpacing(letterSpacing)
290 , m_wordSpacing(wordSpacing)
291 , m_isPlatformFont(false)
292 {
293 }
294
295 Font::Font(const FontPlatformData& fontData, bool isPrinterFont)
296 : m_fontList(FontFallbackList::create())
297 , m_pageZero(0)
298 , m_cachedPrimaryFont(0)
299 , m_letterSpacing(0)
300 , m_wordSpacing(0)
301 , m_isPlatformFont(true)
302 {
303 m_fontDescription.setUsePrinterFont(isPrinterFont);
304 m_fontList->setPlatformFont(fontData);
305 }
306
307 Font::Font(const Font& other)
308 : m_fontDescription(other.m_fontDescription)
309 , m_fontList(other.m_fontList)
310 , m_pages(other.m_pages)
311 , m_pageZero(other.m_pageZero)
312 , m_cachedPrimaryFont(other.m_cachedPrimaryFont)
313 , m_letterSpacing(other.m_letterSpacing)
314 , m_wordSpacing(other.m_wordSpacing)
315 , m_isPlatformFont(other.m_isPlatformFont)
316 {
317 }
318
319 Font& Font::operator=(const Font& other)
320 {
321 m_fontDescription = other.m_fontDescription;
322 m_fontList = other.m_fontList;
323 m_pages = other.m_pages;
324 m_pageZero = other.m_pageZero;
325 m_cachedPrimaryFont = other.m_cachedPrimaryFont;
326 m_letterSpacing = other.m_letterSpacing;
327 m_wordSpacing = other.m_wordSpacing;
328 m_isPlatformFont = other.m_isPlatformFont;
329 return *this;
330 }
331
332 Font::~Font()
333 {
334 }
335
336 bool Font::operator==(const Font& other) const
337 {
338 // Our FontData don't have to be checked, since checking the font descriptio n will be fine.
339 // FIXME: This does not work if the font was made with the FontPlatformData constructor.
340 if ((m_fontList && m_fontList->loadingCustomFonts()) ||
341 (other.m_fontList && other.m_fontList->loadingCustomFonts()))
342 return false;
343
344 FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
345 FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
346
347 return first == second
348 && m_fontDescription == other.m_fontDescription
349 && m_letterSpacing == other.m_letterSpacing
350 && m_wordSpacing == other.m_wordSpacing
351 && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
352 }
353
354 const GlyphData& Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceS mallCaps) const
355 {
356 bool useSmallCapsFont = forceSmallCaps;
357 if (m_fontDescription.smallCaps()) {
358 UChar32 upperC = Unicode::toUpper(c);
359 if (upperC != c) {
360 c = upperC;
361 useSmallCapsFont = true;
362 }
363 }
364
365 if (mirror)
366 c = mirroredChar(c);
367
368 unsigned pageNumber = (c / GlyphPage::size);
369
370 GlyphPageTreeNode* node = pageNumber ? m_pages.get(pageNumber) : m_pageZero;
371 if (!node) {
372 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
373 if (pageNumber)
374 m_pages.set(pageNumber, node);
375 else
376 m_pageZero = node;
377 }
378
379 GlyphPage* page;
380 if (!useSmallCapsFont) {
381 // Fastest loop, for the common case (not small caps).
382 while (true) {
383 page = node->page();
384 if (page) {
385 const GlyphData& data = page->glyphDataForCharacter(c);
386 if (data.fontData)
387 return data;
388 if (node->isSystemFallback())
389 break;
390 }
391
392 // Proceed with the fallback list.
393 node = node->getChild(fontDataAt(node->level()), pageNumber);
394 if (pageNumber)
395 m_pages.set(pageNumber, node);
396 else
397 m_pageZero = node;
398 }
399 } else {
400 while (true) {
401 page = node->page();
402 if (page) {
403 const GlyphData& data = page->glyphDataForCharacter(c);
404 if (data.fontData) {
405 // The smallCapsFontData function should not normally return 0.
406 // But if it does, we will just render the capital letter bi g.
407 const SimpleFontData* smallCapsFontData = data.fontData->sma llCapsFontData(m_fontDescription);
408 if (!smallCapsFontData)
409 return data;
410
411 GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRoo tChild(smallCapsFontData, pageNumber);
412 const GlyphPage* smallCapsPage = smallCapsNode->page();
413 if (smallCapsPage) {
414 const GlyphData& data = smallCapsPage->glyphDataForChara cter(c);
415 if (data.fontData)
416 return data;
417 }
418
419 // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
420 // a font has the lowercase character but the small caps fon t does not have its uppercase version.
421 return smallCapsFontData->missingGlyphData();
422 }
423
424 if (node->isSystemFallback())
425 break;
426 }
427
428 // Proceed with the fallback list.
429 node = node->getChild(fontDataAt(node->level()), pageNumber);
430 if (pageNumber)
431 m_pages.set(pageNumber, node);
432 else
433 m_pageZero = node;
434 }
435 }
436
437 ASSERT(page);
438 ASSERT(node->isSystemFallback());
439
440 // System fallback is character-dependent. When we get here, we
441 // know that the character in question isn't in the system fallback
442 // font's glyph page. Try to lazily create it here.
443 UChar codeUnits[2];
444 int codeUnitsLength;
445 if (c <= 0xFFFF) {
446 UChar c16 = c;
447 if (Font::treatAsSpace(c16))
448 codeUnits[0] = ' ';
449 else if (Font::treatAsZeroWidthSpace(c16))
450 codeUnits[0] = zeroWidthSpace;
451 else
452 codeUnits[0] = c16;
453 codeUnitsLength = 1;
454 } else {
455 codeUnits[0] = U16_LEAD(c);
456 codeUnits[1] = U16_TRAIL(c);
457 codeUnitsLength = 2;
458 }
459 const SimpleFontData* characterFontData = FontCache::getFontDataForCharacter s(*this, codeUnits, codeUnitsLength);
460 if (useSmallCapsFont)
461 characterFontData = characterFontData->smallCapsFontData(m_fontDescripti on);
462 if (characterFontData) {
463 // Got the fallback glyph and font.
464 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontD ata, pageNumber)->page();
465 const GlyphData& data = fallbackPage && fallbackPage->glyphDataForCharac ter(c).fontData ? fallbackPage->glyphDataForCharacter(c) : characterFontData->mi ssingGlyphData();
466 // Cache it so we don't have to do system fallback again next time.
467 if (!useSmallCapsFont)
468 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
469 return data;
470 }
471
472 // Even system fallback can fail; use the missing glyph in that case.
473 // FIXME: It would be nicer to use the missing glyph from the last resort fo nt instead.
474 const GlyphData& data = primaryFont()->missingGlyphData();
475 if (!useSmallCapsFont)
476 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
477 return data;
478 }
479
480 void Font::cachePrimaryFont() const
481 {
482 ASSERT(m_fontList);
483 ASSERT(!m_cachedPrimaryFont);
484 m_cachedPrimaryFont = m_fontList->primaryFont(this)->fontDataForCharacter(' ');
485 }
486
487 const FontData* Font::fontDataAt(unsigned index) const
488 {
489 ASSERT(m_fontList);
490 return m_fontList->fontDataAt(this, index);
491 }
492
493 const FontData* Font::fontDataForCharacters(const UChar* characters, int length) const
494 {
495 ASSERT(m_fontList);
496 return m_fontList->fontDataForCharacters(this, characters, length);
497 }
498
499 void Font::update(PassRefPtr<FontSelector> fontSelector) const
500 {
501 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
502 // being reasonably safe (because inherited fonts in the render tree pick up the new
503 // style anyway. Other copies are transient, e.g., the state in the Graphics Context, and
504 // won't stick around long enough to get you in trouble). Still, this is pre tty disgusting,
505 // and could eventually be rectified by using RefPtrs for Fonts themselves.
506 if (!m_fontList)
507 m_fontList = FontFallbackList::create();
508 m_fontList->invalidate(fontSelector);
509 m_cachedPrimaryFont = 0;
510 m_pageZero = 0;
511 m_pages.clear();
512 }
513
514 int Font::width(const TextRun& run) const
515 {
516 return lroundf(floatWidth(run));
517 }
518
519 int Font::ascent() const
520 {
521 return primaryFont()->ascent();
522 }
523
524 int Font::descent() const
525 {
526 return primaryFont()->descent();
527 }
528
529 int Font::lineSpacing() const
530 {
531 return primaryFont()->lineSpacing();
532 }
533
534 int Font::lineGap() const
535 {
536 return primaryFont()->lineGap();
537 }
538
539 float Font::xHeight() const
540 {
541 return primaryFont()->xHeight();
542 }
543
544 unsigned Font::unitsPerEm() const
545 {
546 return primaryFont()->unitsPerEm();
547 }
548
549 int Font::spaceWidth() const
550 {
551 return (int)ceilf(primaryFont()->m_adjustedSpaceWidth + m_letterSpacing);
552 }
553
554 bool Font::isFixedPitch() const
555 {
556 ASSERT(m_fontList);
557 return m_fontList->isFixedPitch(this);
558 }
559
560 void Font::setCodePath(CodePath p)
561 {
562 codePath = p;
563 }
564
565 bool Font::canUseGlyphCache(const TextRun& run) const
566 {
567 switch (codePath) {
568 case Auto:
569 break;
570 case Simple:
571 return true;
572 case Complex:
573 return false;
574 }
575
576 // Start from 0 since drawing and highlighting also measure the characters b efore run->from
577 for (int i = 0; i < run.length(); i++) {
578 const UChar c = run[i];
579 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
580 continue;
581 if (c <= 0x36F)
582 return false;
583
584 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+ 05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
585 continue;
586 if (c <= 0x05CF)
587 return false;
588
589 if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Dev anagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
590 continue;
591 if (c <= 0x1059)
592 return false;
593
594 if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient K orean should be left here if you precompose; Modern Korean will be precomposed a s a result of step A)
595 continue;
596 if (c <= 0x11FF)
597 return false;
598
599 if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
600 continue;
601 if (c <= 0x18AF)
602 return false;
603
604 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
605 continue;
606 if (c <= 0x194F)
607 return false;
608
609 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
610 continue;
611 if (c <= 0x20FF)
612 return false;
613
614 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
615 continue;
616 if (c <= 0xFE2F)
617 return false;
618 }
619
620 return true;
621
622 }
623
624 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl oatPoint& point, int from, int to) const
625 {
626 // This glyph buffer holds our glyphs+advances+font data for each glyph.
627 GlyphBuffer glyphBuffer;
628
629 float startX = point.x();
630 WidthIterator it(this, run);
631 it.advance(from);
632 float beforeWidth = it.m_runWidthSoFar;
633 it.advance(to, &glyphBuffer);
634
635 // We couldn't generate any glyphs for the run. Give up.
636 if (glyphBuffer.isEmpty())
637 return;
638
639 float afterWidth = it.m_runWidthSoFar;
640
641 if (run.rtl()) {
642 float finalRoundingWidth = it.m_finalRoundingWidth;
643 it.advance(run.length());
644 startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
645 } else
646 startX += beforeWidth;
647
648 // Swap the order of the glyphs if right-to-left.
649 if (run.rtl())
650 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2 ; ++i, --end)
651 glyphBuffer.swap(i, end);
652
653 // Calculate the starting point of the glyphs to be displayed by adding
654 // all the advances up to the first glyph.
655 FloatPoint startPoint(startX, point.y());
656 drawGlyphBuffer(context, glyphBuffer, run, startPoint);
657 }
658
659 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuf fer,
660 const TextRun& run, const FloatPoint& point) const
661 {
662 // Draw each contiguous run of glyphs that use the same font data.
663 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
664 FloatSize offset = glyphBuffer.offsetAt(0);
665 FloatPoint startPoint(point);
666 float nextX = startPoint.x();
667 int lastFrom = 0;
668 int nextGlyph = 0;
669 while (nextGlyph < glyphBuffer.size()) {
670 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
671 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
672 if (nextFontData != fontData || nextOffset != offset) {
673 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - las tFrom, startPoint);
674
675 lastFrom = nextGlyph;
676 fontData = nextFontData;
677 offset = nextOffset;
678 startPoint.setX(nextX);
679 }
680 nextX += glyphBuffer.advanceAt(nextGlyph);
681 nextGlyph++;
682 }
683
684 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, s tartPoint);
685 }
686
687 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoi nt& point, int from, int to) const
688 {
689 // Don't draw anything while we are using custom fonts that are in the proce ss of loading.
690 if (m_fontList && m_fontList->loadingCustomFonts())
691 return;
692
693 to = (to == -1 ? run.length() : to);
694
695 #if ENABLE(SVG_FONTS)
696 if (primaryFont()->isSVGFont()) {
697 drawTextUsingSVGFont(context, run, point, from, to);
698 return;
699 }
700 #endif
701
702 if (canUseGlyphCache(run))
703 drawSimpleText(context, run, point, from, to);
704 else
705 drawComplexText(context, run, point, from, to);
706 }
707
708 float Font::floatWidth(const TextRun& run) const
709 {
710 #if ENABLE(SVG_FONTS)
711 if (primaryFont()->isSVGFont())
712 return floatWidthUsingSVGFont(run);
713 #endif
714
715 if (canUseGlyphCache(run))
716 return floatWidthForSimpleText(run, 0);
717 return floatWidthForComplexText(run);
718 }
719
720 float Font::floatWidth(const TextRun& run, int extraCharsAvailable, int& charsCo nsumed, String& glyphName) const
721 {
722 #if ENABLE(SVG_FONTS)
723 if (primaryFont()->isSVGFont())
724 return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, g lyphName);
725 #endif
726
727 charsConsumed = run.length();
728 glyphName = "";
729 if (canUseGlyphCache(run))
730 return floatWidthForSimpleText(run, 0);
731 return floatWidthForComplexText(run);
732 }
733
734 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer ) const
735 {
736 WidthIterator it(this, run);
737 it.advance(run.length(), glyphBuffer);
738 return it.m_runWidthSoFar;
739 }
740
741 FloatRect Font::selectionRectForText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
742 {
743 #if ENABLE(SVG_FONTS)
744 if (primaryFont()->isSVGFont())
745 return selectionRectForTextUsingSVGFont(run, point, h, from, to);
746 #endif
747
748 to = (to == -1 ? run.length() : to);
749 if (canUseGlyphCache(run))
750 return selectionRectForSimpleText(run, point, h, from, to);
751 return selectionRectForComplexText(run, point, h, from, to);
752 }
753
754 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& p oint, int h, int from, int to) const
755 {
756 WidthIterator it(this, run);
757 it.advance(from);
758 float beforeWidth = it.m_runWidthSoFar;
759 it.advance(to);
760 float afterWidth = it.m_runWidthSoFar;
761
762 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
763 if (run.rtl()) {
764 it.advance(run.length());
765 float totalWidth = it.m_runWidthSoFar;
766 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
767 } else {
768 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afte rWidth) - floorf(beforeWidth), h);
769 }
770 }
771
772 int Font::offsetForPosition(const TextRun& run, int x, bool includePartialGlyphs ) const
773 {
774 #if ENABLE(SVG_FONTS)
775 if (primaryFont()->isSVGFont())
776 return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs );
777 #endif
778
779 if (canUseGlyphCache(run))
780 return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
781 return offsetForPositionForComplexText(run, x, includePartialGlyphs);
782 }
783
784 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool include PartialGlyphs) const
785 {
786 float delta = (float)x;
787
788 WidthIterator it(this, run);
789 GlyphBuffer localGlyphBuffer;
790 unsigned offset;
791 if (run.rtl()) {
792 delta -= floatWidthForSimpleText(run, 0);
793 while (1) {
794 offset = it.m_currentCharacter;
795 float w;
796 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
797 break;
798 delta += w;
799 if (includePartialGlyphs) {
800 if (delta - w / 2 >= 0)
801 break;
802 } else {
803 if (delta >= 0)
804 break;
805 }
806 }
807 } else {
808 while (1) {
809 offset = it.m_currentCharacter;
810 float w;
811 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
812 break;
813 delta -= w;
814 if (includePartialGlyphs) {
815 if (delta + w / 2 <= 0)
816 break;
817 } else {
818 if (delta <= 0)
819 break;
820 }
821 }
822 }
823
824 return offset;
825 }
826
827 #if ENABLE(SVG_FONTS)
828 bool Font::isSVGFont() const
829 {
830 return primaryFont()->isSVGFont();
831 }
832 #endif
833
834 FontSelector* Font::fontSelector() const
835 {
836 return m_fontList ? m_fontList->fontSelector() : 0;
837 }
838
839 }
OLDNEW
« no previous file with comments | « webkit/pending/FileSystemWin.cpp ('k') | webkit/pending/FontCache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698