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