• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #include "config.h"
25 #include "Font.h"
26 
27 #include "FloatRect.h"
28 #include "FontCache.h"
29 #include "FontTranscoder.h"
30 #include "IntPoint.h"
31 #include "GlyphBuffer.h"
32 #include "TextRun.h"
33 #include "WidthIterator.h"
34 #include <wtf/MathExtras.h>
35 #include <wtf/UnusedParam.h>
36 
37 using namespace WTF;
38 using namespace Unicode;
39 
40 namespace WebCore {
41 
42 Font::CodePath Font::s_codePath = Auto;
43 
44 // ============================================================================================
45 // Font Implementation (Cross-Platform Portion)
46 // ============================================================================================
47 
Font()48 Font::Font()
49     : m_letterSpacing(0)
50     , m_wordSpacing(0)
51     , m_isPlatformFont(false)
52     , m_needsTranscoding(false)
53 {
54 }
55 
Font(const FontDescription & fd,short letterSpacing,short wordSpacing)56 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
57     : m_fontDescription(fd)
58     , m_letterSpacing(letterSpacing)
59     , m_wordSpacing(wordSpacing)
60     , m_isPlatformFont(false)
61     , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
62 {
63 }
64 
Font(const FontPlatformData & fontData,bool isPrinterFont,FontSmoothingMode fontSmoothingMode)65 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
66     : m_fontList(FontFallbackList::create())
67     , m_letterSpacing(0)
68     , m_wordSpacing(0)
69     , m_isPlatformFont(true)
70 {
71     m_fontDescription.setUsePrinterFont(isPrinterFont);
72     m_fontDescription.setFontSmoothing(fontSmoothingMode);
73     m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
74     m_fontList->setPlatformFont(fontData);
75 }
76 
Font(const Font & other)77 Font::Font(const Font& other)
78     : m_fontDescription(other.m_fontDescription)
79     , m_fontList(other.m_fontList)
80     , m_letterSpacing(other.m_letterSpacing)
81     , m_wordSpacing(other.m_wordSpacing)
82     , m_isPlatformFont(other.m_isPlatformFont)
83     , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
84 {
85 }
86 
operator =(const Font & other)87 Font& Font::operator=(const Font& other)
88 {
89     m_fontDescription = other.m_fontDescription;
90     m_fontList = other.m_fontList;
91     m_letterSpacing = other.m_letterSpacing;
92     m_wordSpacing = other.m_wordSpacing;
93     m_isPlatformFont = other.m_isPlatformFont;
94     m_needsTranscoding = other.m_needsTranscoding;
95     return *this;
96 }
97 
operator ==(const Font & other) const98 bool Font::operator==(const Font& other) const
99 {
100     // Our FontData don't have to be checked, since checking the font description will be fine.
101     // FIXME: This does not work if the font was made with the FontPlatformData constructor.
102     if (loadingCustomFonts() || other.loadingCustomFonts())
103         return false;
104 
105     FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
106     FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
107 
108     return first == second
109            && m_fontDescription == other.m_fontDescription
110            && m_letterSpacing == other.m_letterSpacing
111            && m_wordSpacing == other.m_wordSpacing
112            && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
113 }
114 
update(PassRefPtr<FontSelector> fontSelector) const115 void Font::update(PassRefPtr<FontSelector> fontSelector) const
116 {
117     // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
118     // being reasonably safe (because inherited fonts in the render tree pick up the new
119     // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
120     // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
121     // and could eventually be rectified by using RefPtrs for Fonts themselves.
122     if (!m_fontList)
123         m_fontList = FontFallbackList::create();
124     m_fontList->invalidate(fontSelector);
125 }
126 
drawText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const127 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
128 {
129     // Don't draw anything while we are using custom fonts that are in the process of loading.
130     if (loadingCustomFonts())
131         return;
132 
133     to = (to == -1 ? run.length() : to);
134 
135 #if ENABLE(SVG_FONTS)
136     if (primaryFont()->isSVGFont()) {
137         drawTextUsingSVGFont(context, run, point, from, to);
138         return;
139     }
140 #endif
141 
142     if (codePath(run) != Complex)
143         return drawSimpleText(context, run, point, from, to);
144 
145     return drawComplexText(context, run, point, from, to);
146 }
147 
drawEmphasisMarks(GraphicsContext * context,const TextRun & run,const AtomicString & mark,const FloatPoint & point,int from,int to) const148 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
149 {
150     if (loadingCustomFonts())
151         return;
152 
153     if (to < 0)
154         to = run.length();
155 
156 #if ENABLE(SVG_FONTS)
157     // FIXME: Implement for SVG fonts.
158     if (primaryFont()->isSVGFont())
159         return;
160 #endif
161 
162     if (codePath(run) != Complex)
163         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
164     else
165         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
166 }
167 
width(const TextRun & run,HashSet<const SimpleFontData * > * fallbackFonts,GlyphOverflow * glyphOverflow) const168 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
169 {
170 #if ENABLE(SVG_FONTS)
171     if (primaryFont()->isSVGFont())
172         return floatWidthUsingSVGFont(run);
173 #endif
174 
175     CodePath codePathToUse = codePath(run);
176     if (codePathToUse != Complex) {
177         // If the complex text implementation cannot return fallback fonts, avoid
178         // returning them for simple text as well.
179         static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
180         return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0);
181     }
182 
183     return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
184 }
185 
width(const TextRun & run,int extraCharsAvailable,int & charsConsumed,String & glyphName) const186 float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
187 {
188 #if !ENABLE(SVG_FONTS)
189     UNUSED_PARAM(extraCharsAvailable);
190 #else
191     if (primaryFont()->isSVGFont())
192         return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
193 #endif
194 
195     charsConsumed = run.length();
196     glyphName = "";
197 
198     if (codePath(run) != Complex)
199         return floatWidthForSimpleText(run, 0);
200 
201     return floatWidthForComplexText(run);
202 }
203 
selectionRectForText(const TextRun & run,const FloatPoint & point,int h,int from,int to) const204 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
205 {
206 #if ENABLE(SVG_FONTS)
207     if (primaryFont()->isSVGFont())
208         return selectionRectForTextUsingSVGFont(run, point, h, from, to);
209 #endif
210 
211     to = (to == -1 ? run.length() : to);
212 
213     if (codePath(run) != Complex)
214         return selectionRectForSimpleText(run, point, h, from, to);
215 
216     return selectionRectForComplexText(run, point, h, from, to);
217 }
218 
offsetForPosition(const TextRun & run,float x,bool includePartialGlyphs) const219 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
220 {
221 #if ENABLE(SVG_FONTS)
222     if (primaryFont()->isSVGFont())
223         return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
224 #endif
225 
226     if (codePath(run) != Complex)
227         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
228 
229     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
230 }
231 
232 #if ENABLE(SVG_FONTS)
isSVGFont() const233 bool Font::isSVGFont() const
234 {
235     return primaryFont()->isSVGFont();
236 }
237 #endif
238 
normalizeSpaces(const UChar * characters,unsigned length)239 String Font::normalizeSpaces(const UChar* characters, unsigned length)
240 {
241     UChar* buffer;
242     String normalized = String::createUninitialized(length, buffer);
243 
244     for (unsigned i = 0; i < length; ++i)
245         buffer[i] = normalizeSpaces(characters[i]);
246 
247     return normalized;
248 }
249 
250 static bool shouldUseFontSmoothing = true;
251 
setShouldUseSmoothing(bool shouldUseSmoothing)252 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
253 {
254     ASSERT(isMainThread());
255     shouldUseFontSmoothing = shouldUseSmoothing;
256 }
257 
shouldUseSmoothing()258 bool Font::shouldUseSmoothing()
259 {
260     return shouldUseFontSmoothing;
261 }
262 
setCodePath(CodePath p)263 void Font::setCodePath(CodePath p)
264 {
265     s_codePath = p;
266 }
267 
codePath()268 Font::CodePath Font::codePath()
269 {
270     return s_codePath;
271 }
272 
codePath(const TextRun & run) const273 Font::CodePath Font::codePath(const TextRun& run) const
274 {
275     if (s_codePath != Auto)
276         return s_codePath;
277 
278 #if PLATFORM(QT)
279     if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
280         return Complex;
281 #endif
282 
283     CodePath result = Simple;
284 
285     // Start from 0 since drawing and highlighting also measure the characters before run->from
286     for (int i = 0; i < run.length(); i++) {
287         const UChar c = run[i];
288         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
289             continue;
290         if (c <= 0x36F)
291             return Complex;
292 
293         if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
294             continue;
295         if (c <= 0x05CF)
296             return Complex;
297 
298         if (c < 0x0600) // U+0600 through U+1059 Arabic, Syriac, Thaana, Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
299             continue;
300         if (c <= 0x1059)
301             return Complex;
302 
303         if (c < 0x1100) // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose; Modern Korean will be precomposed as a result of step A)
304             continue;
305         if (c <= 0x11FF)
306             return Complex;
307 
308         if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
309             continue;
310         if (c <= 0x18AF)
311             return Complex;
312 
313         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
314             continue;
315         if (c <= 0x194F)
316             return Complex;
317 
318         if (c < 0x1E00) // U+1E00 through U+2000 characters with diacritics and stacked diacritics
319             continue;
320         if (c <= 0x2000) {
321             result = SimpleWithGlyphOverflow;
322             continue;
323         }
324 
325         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
326             continue;
327         if (c <= 0x20FF)
328             return Complex;
329 
330         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
331             continue;
332         if (c <= 0xFE2F)
333             return Complex;
334     }
335 
336     if (typesettingFeatures())
337         return Complex;
338 
339     return result;
340 }
341 
isCJKIdeograph(UChar32 c)342 bool Font::isCJKIdeograph(UChar32 c)
343 {
344     // The basic CJK Unified Ideographs block.
345     if (c >= 0x4E00 && c <= 0x9FFF)
346         return true;
347 
348     // CJK Unified Ideographs Extension A.
349     if (c >= 0x3400 && c <= 0x4DBF)
350         return true;
351 
352     // CJK Radicals Supplement.
353     if (c >= 0x2E80 && c <= 0x2EFF)
354         return true;
355 
356     // Kangxi Radicals.
357     if (c >= 0x2F00 && c <= 0x2FDF)
358         return true;
359 
360     // CJK Strokes.
361     if (c >= 0x31C0 && c <= 0x31EF)
362         return true;
363 
364     // CJK Compatibility Ideographs.
365     if (c >= 0xF900 && c <= 0xFAFF)
366         return true;
367 
368     // CJK Unified Ideographs Extension B.
369     if (c >= 0x20000 && c <= 0x2A6DF)
370         return true;
371 
372     // CJK Unified Ideographs Extension C.
373     if (c >= 0x2A700 && c <= 0x2B73F)
374         return true;
375 
376     // CJK Unified Ideographs Extension D.
377     if (c >= 0x2B740 && c <= 0x2B81F)
378         return true;
379 
380     // CJK Compatibility Ideographs Supplement.
381     if (c >= 0x2F800 && c <= 0x2FA1F)
382         return true;
383 
384     return false;
385 }
386 
isCJKIdeographOrSymbol(UChar32 c)387 bool Font::isCJKIdeographOrSymbol(UChar32 c)
388 {
389     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
390     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
391     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
392     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
393     if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
394         return true;
395 
396     // Ideographic Description Characters.
397     if (c >= 0x2FF0 && c <= 0x2FFF)
398         return true;
399 
400     // CJK Symbols and Punctuation.
401     if (c >= 0x3000 && c <= 0x303F)
402         return true;
403 
404     // Hiragana
405     if (c >= 0x3040 && c <= 0x309F)
406         return true;
407 
408     // Katakana
409     if (c >= 0x30A0 && c <= 0x30FF)
410         return true;
411 
412     // Bopomofo
413     if (c >= 0x3100 && c <= 0x312F)
414         return true;
415 
416     // Bopomofo Extended
417     if (c >= 0x31A0 && c <= 0x31BF)
418         return true;
419 
420     // Enclosed CJK Letters and Months.
421     if (c >= 0x3200 && c <= 0x32FF)
422         return true;
423 
424     // CJK Compatibility.
425     if (c >= 0x3300 && c <= 0x33FF)
426         return true;
427 
428     // CJK Compatibility Forms.
429     if (c >= 0xFE30 && c <= 0xFE4F)
430         return true;
431 
432     // Halfwidth and Fullwidth Forms
433     // Usually only used in CJK
434     if (c >= 0xFF00 && c <= 0xFFEF)
435         return true;
436 
437     // Emoji.
438     if (c >= 0x1F200 && c <= 0x1F6F)
439         return true;
440 
441     return isCJKIdeograph(c);
442 }
443 
expansionOpportunityCount(const UChar * characters,size_t length,TextDirection direction,bool & isAfterExpansion)444 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
445 {
446     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
447     unsigned count = 0;
448     if (direction == LTR) {
449         for (size_t i = 0; i < length; ++i) {
450             UChar32 character = characters[i];
451             if (treatAsSpace(character)) {
452                 count++;
453                 isAfterExpansion = true;
454                 continue;
455             }
456             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
457                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
458                 i++;
459             }
460             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
461                 if (!isAfterExpansion)
462                     count++;
463                 count++;
464                 isAfterExpansion = true;
465                 continue;
466             }
467             isAfterExpansion = false;
468         }
469     } else {
470         for (size_t i = length; i > 0; --i) {
471             UChar32 character = characters[i - 1];
472             if (treatAsSpace(character)) {
473                 count++;
474                 isAfterExpansion = true;
475                 continue;
476             }
477             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
478                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
479                 i--;
480             }
481             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
482                 if (!isAfterExpansion)
483                     count++;
484                 count++;
485                 isAfterExpansion = true;
486                 continue;
487             }
488             isAfterExpansion = false;
489         }
490     }
491     return count;
492 }
493 
canReceiveTextEmphasis(UChar32 c)494 bool Font::canReceiveTextEmphasis(UChar32 c)
495 {
496     CharCategory category = Unicode::category(c);
497     if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
498         return false;
499 
500     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
501     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
502         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
503         return false;
504 
505     return true;
506 }
507 
508 }
509