1 /**
2 * Copyright (C) 2003, 2006 Apple Computer, Inc.
3 * Copyright (C) 2008 Holger Hans Peter Freyther
4 * Copyright (C) 2009 Torch Mobile, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "config.h"
24 #include "Font.h"
25
26 #include "CharacterNames.h"
27 #include "FontCache.h"
28 #include "FontFallbackList.h"
29 #include "FloatRect.h"
30 #include "GlyphBuffer.h"
31 #include "GlyphPageTreeNode.h"
32 #include "IntPoint.h"
33 #include "SimpleFontData.h"
34 #include "WidthIterator.h"
35
36 #include <wtf/unicode/Unicode.h>
37 #include <wtf/MathExtras.h>
38
39 using namespace WTF;
40 using namespace Unicode;
41
42 namespace WebCore {
43
glyphDataForCharacter(UChar32 c,bool mirror,bool forceSmallCaps) const44 GlyphData Font::glyphDataForCharacter(UChar32 c, bool mirror, bool forceSmallCaps) const
45 {
46 ASSERT(isMainThread());
47
48 bool useSmallCapsFont = forceSmallCaps;
49 if (m_fontDescription.smallCaps()) {
50 UChar32 upperC = toUpper(c);
51 if (upperC != c) {
52 c = upperC;
53 useSmallCapsFont = true;
54 }
55 }
56
57 if (mirror)
58 c = mirroredChar(c);
59
60 unsigned pageNumber = (c / GlyphPage::size);
61
62 GlyphPageTreeNode* node = pageNumber ? m_fontList->m_pages.get(pageNumber) : m_fontList->m_pageZero;
63 if (!node) {
64 node = GlyphPageTreeNode::getRootChild(fontDataAt(0), pageNumber);
65 if (pageNumber)
66 m_fontList->m_pages.set(pageNumber, node);
67 else
68 m_fontList->m_pageZero = node;
69 }
70
71 GlyphPage* page;
72 if (!useSmallCapsFont) {
73 // Fastest loop, for the common case (not small caps).
74 while (true) {
75 page = node->page();
76 if (page) {
77 GlyphData data = page->glyphDataForCharacter(c);
78 if (data.fontData)
79 return data;
80 if (node->isSystemFallback())
81 break;
82 }
83
84 // Proceed with the fallback list.
85 node = node->getChild(fontDataAt(node->level()), pageNumber);
86 if (pageNumber)
87 m_fontList->m_pages.set(pageNumber, node);
88 else
89 m_fontList->m_pageZero = node;
90 }
91 } else {
92 while (true) {
93 page = node->page();
94 if (page) {
95 GlyphData data = page->glyphDataForCharacter(c);
96 if (data.fontData) {
97 // The smallCapsFontData function should not normally return 0.
98 // But if it does, we will just render the capital letter big.
99 const SimpleFontData* smallCapsFontData = data.fontData->smallCapsFontData(m_fontDescription);
100 if (!smallCapsFontData)
101 return data;
102
103 GlyphPageTreeNode* smallCapsNode = GlyphPageTreeNode::getRootChild(smallCapsFontData, pageNumber);
104 const GlyphPage* smallCapsPage = smallCapsNode->page();
105 if (smallCapsPage) {
106 GlyphData data = smallCapsPage->glyphDataForCharacter(c);
107 if (data.fontData)
108 return data;
109 }
110
111 // Do not attempt system fallback off the smallCapsFontData. This is the very unlikely case that
112 // a font has the lowercase character but the small caps font does not have its uppercase version.
113 return smallCapsFontData->missingGlyphData();
114 }
115
116 if (node->isSystemFallback())
117 break;
118 }
119
120 // Proceed with the fallback list.
121 node = node->getChild(fontDataAt(node->level()), pageNumber);
122 if (pageNumber)
123 m_fontList->m_pages.set(pageNumber, node);
124 else
125 m_fontList->m_pageZero = node;
126 }
127 }
128
129 ASSERT(page);
130 ASSERT(node->isSystemFallback());
131
132 // System fallback is character-dependent. When we get here, we
133 // know that the character in question isn't in the system fallback
134 // font's glyph page. Try to lazily create it here.
135 UChar codeUnits[2];
136 int codeUnitsLength;
137 if (c <= 0xFFFF) {
138 UChar c16 = c;
139 if (Font::treatAsSpace(c16))
140 codeUnits[0] = ' ';
141 else if (Font::treatAsZeroWidthSpace(c16))
142 codeUnits[0] = zeroWidthSpace;
143 else
144 codeUnits[0] = c16;
145 codeUnitsLength = 1;
146 } else {
147 codeUnits[0] = U16_LEAD(c);
148 codeUnits[1] = U16_TRAIL(c);
149 codeUnitsLength = 2;
150 }
151 const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
152 if (useSmallCapsFont && characterFontData)
153 characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
154 if (characterFontData) {
155 // Got the fallback glyph and font.
156 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
157 GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
158 // Cache it so we don't have to do system fallback again next time.
159 if (!useSmallCapsFont) {
160 #if PLATFORM(WINCE)
161 // missingGlyphData returns a null character, which is not suitable for GDI to display.
162 // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
163 // display the character, probably because the font package is not installed correctly.
164 // So we just always set the glyph to be same as the character, and let GDI solve it.
165 page->setGlyphDataForCharacter(c, c, characterFontData);
166 return page->glyphDataForCharacter(c);
167 #else
168 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
169 #endif
170 }
171 return data;
172 }
173
174 // Even system fallback can fail; use the missing glyph in that case.
175 // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
176 GlyphData data = primaryFont()->missingGlyphData();
177 if (!useSmallCapsFont) {
178 #if PLATFORM(WINCE)
179 // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
180 page->setGlyphDataForCharacter(c, c, data.fontData);
181 return page->glyphDataForCharacter(c);
182 #else
183 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
184 #endif
185 }
186 return data;
187 }
188
setCodePath(CodePath p)189 void Font::setCodePath(CodePath p)
190 {
191 s_codePath = p;
192 }
193
codePath()194 Font::CodePath Font::codePath()
195 {
196 return s_codePath;
197 }
198
canUseGlyphCache(const TextRun & run) const199 bool Font::canUseGlyphCache(const TextRun& run) const
200 {
201 switch (s_codePath) {
202 case Auto:
203 break;
204 case Simple:
205 return true;
206 case Complex:
207 return false;
208 }
209
210 // Start from 0 since drawing and highlighting also measure the characters before run->from
211 for (int i = 0; i < run.length(); i++) {
212 const UChar c = run[i];
213 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
214 continue;
215 if (c <= 0x36F)
216 return false;
217
218 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
219 continue;
220 if (c <= 0x05CF)
221 return false;
222
223 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
224 continue;
225 if (c <= 0x1059)
226 return false;
227
228 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)
229 continue;
230 if (c <= 0x11FF)
231 return false;
232
233 if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
234 continue;
235 if (c <= 0x18AF)
236 return false;
237
238 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
239 continue;
240 if (c <= 0x194F)
241 return false;
242
243 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
244 continue;
245 if (c <= 0x20FF)
246 return false;
247
248 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
249 continue;
250 if (c <= 0xFE2F)
251 return false;
252 }
253
254 return true;
255
256 }
257
drawSimpleText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const258 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
259 {
260 // This glyph buffer holds our glyphs+advances+font data for each glyph.
261 GlyphBuffer glyphBuffer;
262
263 float startX = point.x();
264 WidthIterator it(this, run);
265 it.advance(from);
266 float beforeWidth = it.m_runWidthSoFar;
267 it.advance(to, &glyphBuffer);
268
269 // We couldn't generate any glyphs for the run. Give up.
270 if (glyphBuffer.isEmpty())
271 return;
272
273 float afterWidth = it.m_runWidthSoFar;
274
275 if (run.rtl()) {
276 float finalRoundingWidth = it.m_finalRoundingWidth;
277 it.advance(run.length());
278 startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
279 } else
280 startX += beforeWidth;
281
282 // Swap the order of the glyphs if right-to-left.
283 if (run.rtl())
284 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
285 glyphBuffer.swap(i, end);
286
287 // Calculate the starting point of the glyphs to be displayed by adding
288 // all the advances up to the first glyph.
289 FloatPoint startPoint(startX, point.y());
290 drawGlyphBuffer(context, glyphBuffer, run, startPoint);
291 }
292
drawGlyphBuffer(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const TextRun &,const FloatPoint & point) const293 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
294 {
295 // Draw each contiguous run of glyphs that use the same font data.
296 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
297 FloatSize offset = glyphBuffer.offsetAt(0);
298 FloatPoint startPoint(point);
299 float nextX = startPoint.x();
300 int lastFrom = 0;
301 int nextGlyph = 0;
302 while (nextGlyph < glyphBuffer.size()) {
303 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
304 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
305 if (nextFontData != fontData || nextOffset != offset) {
306 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
307
308 lastFrom = nextGlyph;
309 fontData = nextFontData;
310 offset = nextOffset;
311 startPoint.setX(nextX);
312 }
313 nextX += glyphBuffer.advanceAt(nextGlyph);
314 nextGlyph++;
315 }
316
317 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
318 }
319
floatWidthForSimpleText(const TextRun & run,GlyphBuffer * glyphBuffer,HashSet<const SimpleFontData * > * fallbackFonts) const320 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
321 {
322 WidthIterator it(this, run, fallbackFonts);
323 it.advance(run.length(), glyphBuffer);
324 return it.m_runWidthSoFar;
325 }
326
selectionRectForSimpleText(const TextRun & run,const IntPoint & point,int h,int from,int to) const327 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
328 {
329 WidthIterator it(this, run);
330 it.advance(from);
331 float beforeWidth = it.m_runWidthSoFar;
332 it.advance(to);
333 float afterWidth = it.m_runWidthSoFar;
334
335 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
336 if (run.rtl()) {
337 it.advance(run.length());
338 float totalWidth = it.m_runWidthSoFar;
339 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
340 } else {
341 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
342 }
343 }
344
offsetForPositionForSimpleText(const TextRun & run,int x,bool includePartialGlyphs) const345 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
346 {
347 float delta = (float)x;
348
349 WidthIterator it(this, run);
350 GlyphBuffer localGlyphBuffer;
351 unsigned offset;
352 if (run.rtl()) {
353 delta -= floatWidthForSimpleText(run, 0);
354 while (1) {
355 offset = it.m_currentCharacter;
356 float w;
357 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
358 break;
359 delta += w;
360 if (includePartialGlyphs) {
361 if (delta - w / 2 >= 0)
362 break;
363 } else {
364 if (delta >= 0)
365 break;
366 }
367 }
368 } else {
369 while (1) {
370 offset = it.m_currentCharacter;
371 float w;
372 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
373 break;
374 delta -= w;
375 if (includePartialGlyphs) {
376 if (delta + w / 2 <= 0)
377 break;
378 } else {
379 if (delta <= 0)
380 break;
381 }
382 }
383 }
384
385 return offset;
386 }
387
388 }
389