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