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 44 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 183 void Font::setCodePath(CodePath p) 184 { 185 s_codePath = p; 186 } 187 188 Font::CodePath Font::codePath() 189 { 190 return s_codePath; 191 } 192 193 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 255 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 290 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 317 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 324 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 342 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