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 codeUnits[0] = Font::normalizeSpaces(c);
139 codeUnitsLength = 1;
140 } else {
141 codeUnits[0] = U16_LEAD(c);
142 codeUnits[1] = U16_TRAIL(c);
143 codeUnitsLength = 2;
144 }
145 const SimpleFontData* characterFontData = fontCache()->getFontDataForCharacters(*this, codeUnits, codeUnitsLength);
146 if (useSmallCapsFont && characterFontData)
147 characterFontData = characterFontData->smallCapsFontData(m_fontDescription);
148 if (characterFontData) {
149 // Got the fallback glyph and font.
150 GlyphPage* fallbackPage = GlyphPageTreeNode::getRootChild(characterFontData, pageNumber)->page();
151 GlyphData data = fallbackPage && fallbackPage->fontDataForCharacter(c) ? fallbackPage->glyphDataForCharacter(c) : characterFontData->missingGlyphData();
152 // Cache it so we don't have to do system fallback again next time.
153 if (!useSmallCapsFont) {
154 #if OS(WINCE)
155 // missingGlyphData returns a null character, which is not suitable for GDI to display.
156 // Also, sometimes we cannot map a font for the character on WINCE, but GDI can still
157 // display the character, probably because the font package is not installed correctly.
158 // So we just always set the glyph to be same as the character, and let GDI solve it.
159 page->setGlyphDataForCharacter(c, c, characterFontData);
160 return page->glyphDataForCharacter(c);
161 #else
162 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
163 #endif
164 }
165 return data;
166 }
167
168 // Even system fallback can fail; use the missing glyph in that case.
169 // FIXME: It would be nicer to use the missing glyph from the last resort font instead.
170 GlyphData data = primaryFont()->missingGlyphData();
171 if (!useSmallCapsFont) {
172 #if OS(WINCE)
173 // See comment about WINCE GDI handling near setGlyphDataForCharacter above.
174 page->setGlyphDataForCharacter(c, c, data.fontData);
175 return page->glyphDataForCharacter(c);
176 #else
177 page->setGlyphDataForCharacter(c, data.glyph, data.fontData);
178 #endif
179 }
180 return data;
181 }
182
setCodePath(CodePath p)183 void Font::setCodePath(CodePath p)
184 {
185 s_codePath = p;
186 }
187
codePath()188 Font::CodePath Font::codePath()
189 {
190 return s_codePath;
191 }
192
canUseGlyphCache(const TextRun & run) const193 bool Font::canUseGlyphCache(const TextRun& run) const
194 {
195 switch (s_codePath) {
196 case Auto:
197 break;
198 case Simple:
199 return true;
200 case Complex:
201 return false;
202 }
203
204 // Start from 0 since drawing and highlighting also measure the characters before run->from
205 for (int i = 0; i < run.length(); i++) {
206 const UChar c = run[i];
207 if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
208 continue;
209 if (c <= 0x36F)
210 return false;
211
212 if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
213 continue;
214 if (c <= 0x05CF)
215 return false;
216
217 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
218 continue;
219 if (c <= 0x1059)
220 return false;
221
222 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)
223 continue;
224 if (c <= 0x11FF)
225 return false;
226
227 if (c < 0x1780) // U+1780 through U+18AF Khmer, Mongolian
228 continue;
229 if (c <= 0x18AF)
230 return false;
231
232 if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
233 continue;
234 if (c <= 0x194F)
235 return false;
236
237 if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
238 continue;
239 if (c <= 0x20FF)
240 return false;
241
242 if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
243 continue;
244 if (c <= 0xFE2F)
245 return false;
246 }
247
248 if (typesettingFeatures())
249 return false;
250
251 return true;
252
253 }
254
drawSimpleText(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const255 void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
256 {
257 // This glyph buffer holds our glyphs+advances+font data for each glyph.
258 GlyphBuffer glyphBuffer;
259
260 float startX = point.x();
261 WidthIterator it(this, run);
262 it.advance(from);
263 float beforeWidth = it.m_runWidthSoFar;
264 it.advance(to, &glyphBuffer);
265
266 // We couldn't generate any glyphs for the run. Give up.
267 if (glyphBuffer.isEmpty())
268 return;
269
270 float afterWidth = it.m_runWidthSoFar;
271
272 if (run.rtl()) {
273 float finalRoundingWidth = it.m_finalRoundingWidth;
274 it.advance(run.length());
275 startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
276 } else
277 startX += beforeWidth;
278
279 // Swap the order of the glyphs if right-to-left.
280 if (run.rtl())
281 for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
282 glyphBuffer.swap(i, end);
283
284 // Calculate the starting point of the glyphs to be displayed by adding
285 // all the advances up to the first glyph.
286 FloatPoint startPoint(startX, point.y());
287 drawGlyphBuffer(context, glyphBuffer, run, startPoint);
288 }
289
drawGlyphBuffer(GraphicsContext * context,const GlyphBuffer & glyphBuffer,const TextRun &,const FloatPoint & point) const290 void Font::drawGlyphBuffer(GraphicsContext* context, const GlyphBuffer& glyphBuffer, const TextRun&, const FloatPoint& point) const
291 {
292 // Draw each contiguous run of glyphs that use the same font data.
293 const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
294 FloatSize offset = glyphBuffer.offsetAt(0);
295 FloatPoint startPoint(point);
296 float nextX = startPoint.x();
297 int lastFrom = 0;
298 int nextGlyph = 0;
299 while (nextGlyph < glyphBuffer.size()) {
300 const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph);
301 FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
302 if (nextFontData != fontData || nextOffset != offset) {
303 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
304
305 lastFrom = nextGlyph;
306 fontData = nextFontData;
307 offset = nextOffset;
308 startPoint.setX(nextX);
309 }
310 nextX += glyphBuffer.advanceAt(nextGlyph);
311 nextGlyph++;
312 }
313
314 drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
315 }
316
floatWidthForSimpleText(const TextRun & run,GlyphBuffer * glyphBuffer,HashSet<const SimpleFontData * > * fallbackFonts) const317 float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts) const
318 {
319 WidthIterator it(this, run, fallbackFonts);
320 it.advance(run.length(), glyphBuffer);
321 return it.m_runWidthSoFar;
322 }
323
selectionRectForSimpleText(const TextRun & run,const IntPoint & point,int h,int from,int to) const324 FloatRect Font::selectionRectForSimpleText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
325 {
326 WidthIterator it(this, run);
327 it.advance(from);
328 float beforeWidth = it.m_runWidthSoFar;
329 it.advance(to);
330 float afterWidth = it.m_runWidthSoFar;
331
332 // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
333 if (run.rtl()) {
334 it.advance(run.length());
335 float totalWidth = it.m_runWidthSoFar;
336 return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
337 } else {
338 return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
339 }
340 }
341
offsetForPositionForSimpleText(const TextRun & run,int x,bool includePartialGlyphs) const342 int Font::offsetForPositionForSimpleText(const TextRun& run, int x, bool includePartialGlyphs) const
343 {
344 float delta = (float)x;
345
346 WidthIterator it(this, run);
347 GlyphBuffer localGlyphBuffer;
348 unsigned offset;
349 if (run.rtl()) {
350 delta -= floatWidthForSimpleText(run, 0);
351 while (1) {
352 offset = it.m_currentCharacter;
353 float w;
354 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
355 break;
356 delta += w;
357 if (includePartialGlyphs) {
358 if (delta - w / 2 >= 0)
359 break;
360 } else {
361 if (delta >= 0)
362 break;
363 }
364 }
365 } else {
366 while (1) {
367 offset = it.m_currentCharacter;
368 float w;
369 if (!it.advanceOneCharacter(w, &localGlyphBuffer))
370 break;
371 delta -= w;
372 if (includePartialGlyphs) {
373 if (delta + w / 2 <= 0)
374 break;
375 } else {
376 if (delta <= 0)
377 break;
378 }
379 }
380 }
381
382 return offset;
383 }
384
385 }
386