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 #if PLATFORM(QT) && HAVE(QRAWFONT)
31 #include "ContextShadow.h"
32 #include "GraphicsContext.h"
33 #endif
34 #include "IntPoint.h"
35 #include "GlyphBuffer.h"
36 #include "TextRun.h"
37 #include "WidthIterator.h"
38 #include <wtf/MathExtras.h>
39 #include <wtf/UnusedParam.h>
40 
41 using namespace WTF;
42 using namespace Unicode;
43 
44 namespace WebCore {
45 
46 Font::CodePath Font::s_codePath = Auto;
47 
48 // ============================================================================================
49 // Font Implementation (Cross-Platform Portion)
50 // ============================================================================================
51 
Font()52 Font::Font()
53     : m_letterSpacing(0)
54     , m_wordSpacing(0)
55     , m_isPlatformFont(false)
56     , m_needsTranscoding(false)
57 {
58 }
59 
Font(const FontDescription & fd,short letterSpacing,short wordSpacing)60 Font::Font(const FontDescription& fd, short letterSpacing, short wordSpacing)
61     : m_fontDescription(fd)
62     , m_letterSpacing(letterSpacing)
63     , m_wordSpacing(wordSpacing)
64     , m_isPlatformFont(false)
65     , m_needsTranscoding(fontTranscoder().needsTranscoding(fd))
66 {
67 }
68 
Font(const FontPlatformData & fontData,bool isPrinterFont,FontSmoothingMode fontSmoothingMode)69 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMode fontSmoothingMode)
70     : m_fontList(FontFallbackList::create())
71     , m_letterSpacing(0)
72     , m_wordSpacing(0)
73     , m_isPlatformFont(true)
74 {
75     m_fontDescription.setUsePrinterFont(isPrinterFont);
76     m_fontDescription.setFontSmoothing(fontSmoothingMode);
77     m_needsTranscoding = fontTranscoder().needsTranscoding(fontDescription());
78     m_fontList->setPlatformFont(fontData);
79 }
80 
Font(const Font & other)81 Font::Font(const Font& other)
82     : m_fontDescription(other.m_fontDescription)
83     , m_fontList(other.m_fontList)
84     , m_letterSpacing(other.m_letterSpacing)
85     , m_wordSpacing(other.m_wordSpacing)
86     , m_isPlatformFont(other.m_isPlatformFont)
87     , m_needsTranscoding(fontTranscoder().needsTranscoding(other.m_fontDescription))
88 {
89 }
90 
operator =(const Font & other)91 Font& Font::operator=(const Font& other)
92 {
93     m_fontDescription = other.m_fontDescription;
94     m_fontList = other.m_fontList;
95     m_letterSpacing = other.m_letterSpacing;
96     m_wordSpacing = other.m_wordSpacing;
97     m_isPlatformFont = other.m_isPlatformFont;
98     m_needsTranscoding = other.m_needsTranscoding;
99     return *this;
100 }
101 
operator ==(const Font & other) const102 bool Font::operator==(const Font& other) const
103 {
104     // Our FontData don't have to be checked, since checking the font description will be fine.
105     // FIXME: This does not work if the font was made with the FontPlatformData constructor.
106     if (loadingCustomFonts() || other.loadingCustomFonts())
107         return false;
108 
109     FontSelector* first = m_fontList ? m_fontList->fontSelector() : 0;
110     FontSelector* second = other.m_fontList ? other.m_fontList->fontSelector() : 0;
111 
112     return first == second
113            && m_fontDescription == other.m_fontDescription
114            && m_letterSpacing == other.m_letterSpacing
115            && m_wordSpacing == other.m_wordSpacing
116            && (m_fontList ? m_fontList->generation() : 0) == (other.m_fontList ? other.m_fontList->generation() : 0);
117 }
118 
update(PassRefPtr<FontSelector> fontSelector) const119 void Font::update(PassRefPtr<FontSelector> fontSelector) const
120 {
121     // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
122     // being reasonably safe (because inherited fonts in the render tree pick up the new
123     // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
124     // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
125     // and could eventually be rectified by using RefPtrs for Fonts themselves.
126     if (!m_fontList)
127         m_fontList = FontFallbackList::create();
128     m_fontList->invalidate(fontSelector);
129 }
130 
drawText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const131 void Font::drawText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
132 {
133     // Don't draw anything while we are using custom fonts that are in the process of loading.
134     if (loadingCustomFonts())
135         return;
136 
137     to = (to == -1 ? run.length() : to);
138 
139 #if ENABLE(SVG_FONTS)
140     if (primaryFont()->isSVGFont()) {
141         drawTextUsingSVGFont(context, run, point, from, to);
142         return;
143     }
144 #endif
145 
146     CodePath codePathToUse = codePath(run);
147 
148 #if PLATFORM(QT) && HAVE(QRAWFONT)
149     if (context->textDrawingMode() & TextModeStroke || context->contextShadow()->m_type != ContextShadow::NoShadow)
150         codePathToUse = Complex;
151 #endif
152 
153     if (codePathToUse != Complex)
154         return drawSimpleText(context, run, point, from, to);
155 
156     return drawComplexText(context, run, point, from, to);
157 }
158 
drawEmphasisMarks(GraphicsContext * context,const TextRun & run,const AtomicString & mark,const FloatPoint & point,int from,int to) const159 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
160 {
161     if (loadingCustomFonts())
162         return;
163 
164     if (to < 0)
165         to = run.length();
166 
167 #if ENABLE(SVG_FONTS)
168     // FIXME: Implement for SVG fonts.
169     if (primaryFont()->isSVGFont())
170         return;
171 #endif
172 
173     if (codePath(run) != Complex)
174         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
175     else
176         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
177 }
178 
width(const TextRun & run,HashSet<const SimpleFontData * > * fallbackFonts,GlyphOverflow * glyphOverflow) const179 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
180 {
181 #if ENABLE(SVG_FONTS)
182     if (primaryFont()->isSVGFont())
183         return floatWidthUsingSVGFont(run);
184 #endif
185 
186     CodePath codePathToUse = codePath(run);
187     if (codePathToUse != Complex) {
188         // If the complex text implementation cannot return fallback fonts, avoid
189         // returning them for simple text as well.
190         static bool returnFallbackFonts = canReturnFallbackFontsForComplexText();
191         return floatWidthForSimpleText(run, 0, returnFallbackFonts ? fallbackFonts : 0, codePathToUse == SimpleWithGlyphOverflow || (glyphOverflow && glyphOverflow->computeBounds) ? glyphOverflow : 0);
192     }
193 
194     return floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
195 }
196 
width(const TextRun & run,int extraCharsAvailable,int & charsConsumed,String & glyphName) const197 float Font::width(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
198 {
199 #if !ENABLE(SVG_FONTS)
200     UNUSED_PARAM(extraCharsAvailable);
201 #else
202     if (primaryFont()->isSVGFont())
203         return floatWidthUsingSVGFont(run, extraCharsAvailable, charsConsumed, glyphName);
204 #endif
205 
206     charsConsumed = run.length();
207     glyphName = "";
208 
209     if (codePath(run) != Complex)
210         return floatWidthForSimpleText(run, 0);
211 
212     return floatWidthForComplexText(run);
213 }
214 
selectionRectForText(const TextRun & run,const FloatPoint & point,int h,int from,int to) const215 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
216 {
217 #if ENABLE(SVG_FONTS)
218     if (primaryFont()->isSVGFont())
219         return selectionRectForTextUsingSVGFont(run, point, h, from, to);
220 #endif
221 
222     to = (to == -1 ? run.length() : to);
223 
224     if (codePath(run) != Complex)
225         return selectionRectForSimpleText(run, point, h, from, to);
226 
227     return selectionRectForComplexText(run, point, h, from, to);
228 }
229 
offsetForPosition(const TextRun & run,float x,bool includePartialGlyphs) const230 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
231 {
232 #if ENABLE(SVG_FONTS)
233     if (primaryFont()->isSVGFont())
234         return offsetForPositionForTextUsingSVGFont(run, x, includePartialGlyphs);
235 #endif
236 
237     if (codePath(run) != Complex)
238         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
239 
240     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
241 }
242 
243 #if ENABLE(SVG_FONTS)
isSVGFont() const244 bool Font::isSVGFont() const
245 {
246     return primaryFont()->isSVGFont();
247 }
248 #endif
249 
normalizeSpaces(const UChar * characters,unsigned length)250 String Font::normalizeSpaces(const UChar* characters, unsigned length)
251 {
252     UChar* buffer;
253     String normalized = String::createUninitialized(length, buffer);
254 
255     for (unsigned i = 0; i < length; ++i)
256         buffer[i] = normalizeSpaces(characters[i]);
257 
258     return normalized;
259 }
260 
261 static bool shouldUseFontSmoothing = true;
262 
setShouldUseSmoothing(bool shouldUseSmoothing)263 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
264 {
265     ASSERT(isMainThread());
266     shouldUseFontSmoothing = shouldUseSmoothing;
267 }
268 
shouldUseSmoothing()269 bool Font::shouldUseSmoothing()
270 {
271     return shouldUseFontSmoothing;
272 }
273 
setCodePath(CodePath p)274 void Font::setCodePath(CodePath p)
275 {
276     s_codePath = p;
277 }
278 
codePath()279 Font::CodePath Font::codePath()
280 {
281     return s_codePath;
282 }
283 
codePath(const TextRun & run) const284 Font::CodePath Font::codePath(const TextRun& run) const
285 {
286     if (s_codePath != Auto)
287         return s_codePath;
288 
289 #if PLATFORM(QT) && !HAVE(QRAWFONT)
290     if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing())
291         return Complex;
292 #endif
293 
294     CodePath result = Simple;
295 
296     // Start from 0 since drawing and highlighting also measure the characters before run->from
297     // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we
298     // can't simply use UnicodeCharacter Property/class because some characters
299     // are not 'combining', but still need to go to the complex path.
300     // Alternatively, we may as well consider binary search over a sorted
301     // list of ranges.
302     for (int i = 0; i < run.length(); i++) {
303         const UChar c = run[i];
304         if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
305             continue;
306         if (c <= 0x2E9)
307             return Complex;
308 
309         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
310             continue;
311         if (c <= 0x36F)
312             return Complex;
313 
314         if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
315             continue;
316         if (c <= 0x05CF)
317             return Complex;
318 
319         // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
320         // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
321         // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
322         if (c < 0x0600)
323             continue;
324         if (c <= 0x109F)
325             return Complex;
326 
327         // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
328         // Modern Korean will be precomposed as a result of step A)
329         if (c < 0x1100)
330             continue;
331         if (c <= 0x11FF)
332             return Complex;
333 
334         if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
335             continue;
336         if (c <= 0x135F)
337             return Complex;
338 
339         if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
340             continue;
341         if (c <= 0x18AF)
342             return Complex;
343 
344         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
345             continue;
346         if (c <= 0x194F)
347             return Complex;
348 
349         if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
350             continue;
351         if (c <= 0x19DF)
352             return Complex;
353 
354         if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
355             continue;
356         if (c <= 0x1CFF)
357             return Complex;
358 
359         if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
360             continue;
361         if (c <= 0x1DFF)
362             return Complex;
363 
364         // U+1E00 through U+2000 characters with diacritics and stacked diacritics
365         if (c <= 0x2000) {
366             result = SimpleWithGlyphOverflow;
367             continue;
368         }
369 
370         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
371             continue;
372         if (c <= 0x20FF)
373             return Complex;
374 
375         if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
376             continue;
377         if (c <= 0x2CF1)
378             return Complex;
379 
380         if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
381             continue;
382         if (c <= 0x302F)
383             return Complex;
384 
385         if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
386             continue;
387         if (c <= 0xA67D)
388             return Complex;
389 
390         if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
391             continue;
392         if (c <= 0xA6F1)
393             return Complex;
394 
395        // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
396        // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
397         if (c < 0xA800)
398             continue;
399         if (c <= 0xABFF)
400             return Complex;
401 
402         if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
403             continue;
404         if (c <= 0xD7FF)
405             return Complex;
406 
407         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
408             continue;
409         if (c <= 0xFE2F)
410             return Complex;
411 
412         // FIXME: Make this loop UTF-16-aware and check for Brahmi (U+11000 block)
413         // Kaithi (U+11080 block) and other complex scripts in plane 1 or higher.
414     }
415 
416     if (typesettingFeatures())
417         return Complex;
418 
419     return result;
420 }
421 
isCJKIdeograph(UChar32 c)422 bool Font::isCJKIdeograph(UChar32 c)
423 {
424     // The basic CJK Unified Ideographs block.
425     if (c >= 0x4E00 && c <= 0x9FFF)
426         return true;
427 
428     // CJK Unified Ideographs Extension A.
429     if (c >= 0x3400 && c <= 0x4DBF)
430         return true;
431 
432     // CJK Radicals Supplement.
433     if (c >= 0x2E80 && c <= 0x2EFF)
434         return true;
435 
436     // Kangxi Radicals.
437     if (c >= 0x2F00 && c <= 0x2FDF)
438         return true;
439 
440     // CJK Strokes.
441     if (c >= 0x31C0 && c <= 0x31EF)
442         return true;
443 
444     // CJK Compatibility Ideographs.
445     if (c >= 0xF900 && c <= 0xFAFF)
446         return true;
447 
448     // CJK Unified Ideographs Extension B.
449     if (c >= 0x20000 && c <= 0x2A6DF)
450         return true;
451 
452     // CJK Unified Ideographs Extension C.
453     if (c >= 0x2A700 && c <= 0x2B73F)
454         return true;
455 
456     // CJK Unified Ideographs Extension D.
457     if (c >= 0x2B740 && c <= 0x2B81F)
458         return true;
459 
460     // CJK Compatibility Ideographs Supplement.
461     if (c >= 0x2F800 && c <= 0x2FA1F)
462         return true;
463 
464     return false;
465 }
466 
isCJKIdeographOrSymbol(UChar32 c)467 bool Font::isCJKIdeographOrSymbol(UChar32 c)
468 {
469     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
470     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
471     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
472     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
473     if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
474         return true;
475 
476     // Ideographic Description Characters.
477     if (c >= 0x2FF0 && c <= 0x2FFF)
478         return true;
479 
480     // CJK Symbols and Punctuation.
481     if (c >= 0x3000 && c <= 0x303F)
482         return true;
483 
484     // Hiragana
485     if (c >= 0x3040 && c <= 0x309F)
486         return true;
487 
488     // Katakana
489     if (c >= 0x30A0 && c <= 0x30FF)
490         return true;
491 
492     // Bopomofo
493     if (c >= 0x3100 && c <= 0x312F)
494         return true;
495 
496     // Bopomofo Extended
497     if (c >= 0x31A0 && c <= 0x31BF)
498         return true;
499 
500     // Enclosed CJK Letters and Months.
501     if (c >= 0x3200 && c <= 0x32FF)
502         return true;
503 
504     // CJK Compatibility.
505     if (c >= 0x3300 && c <= 0x33FF)
506         return true;
507 
508     // CJK Compatibility Forms.
509     if (c >= 0xFE30 && c <= 0xFE4F)
510         return true;
511 
512     // Halfwidth and Fullwidth Forms
513     // Usually only used in CJK
514     if (c >= 0xFF00 && c <= 0xFFEF)
515         return true;
516 
517     // Emoji.
518     if (c >= 0x1F200 && c <= 0x1F6F)
519         return true;
520 
521     return isCJKIdeograph(c);
522 }
523 
expansionOpportunityCount(const UChar * characters,size_t length,TextDirection direction,bool & isAfterExpansion)524 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
525 {
526     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
527     unsigned count = 0;
528     if (direction == LTR) {
529         for (size_t i = 0; i < length; ++i) {
530             UChar32 character = characters[i];
531             if (treatAsSpace(character)) {
532                 count++;
533                 isAfterExpansion = true;
534                 continue;
535             }
536             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
537                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
538                 i++;
539             }
540             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
541                 if (!isAfterExpansion)
542                     count++;
543                 count++;
544                 isAfterExpansion = true;
545                 continue;
546             }
547             isAfterExpansion = false;
548         }
549     } else {
550         for (size_t i = length; i > 0; --i) {
551             UChar32 character = characters[i - 1];
552             if (treatAsSpace(character)) {
553                 count++;
554                 isAfterExpansion = true;
555                 continue;
556             }
557             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
558                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
559                 i--;
560             }
561             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
562                 if (!isAfterExpansion)
563                     count++;
564                 count++;
565                 isAfterExpansion = true;
566                 continue;
567             }
568             isAfterExpansion = false;
569         }
570     }
571     return count;
572 }
573 
canReceiveTextEmphasis(UChar32 c)574 bool Font::canReceiveTextEmphasis(UChar32 c)
575 {
576     CharCategory category = Unicode::category(c);
577     if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
578         return false;
579 
580     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
581     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
582         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
583         return false;
584 
585     return true;
586 }
587 
588 }
589