| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
| 14 * its contributors may be used to endorse or promote products derived | |
| 15 * from this software without specific prior written permission. | |
| 16 * | |
| 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
| 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
| 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
| 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 */ | |
| 28 | |
| 29 #include "platform/fonts/GlyphPageTreeNode.h" | |
| 30 | |
| 31 #include "platform/fonts/SegmentedFontData.h" | |
| 32 #include "platform/fonts/SimpleFontData.h" | |
| 33 #include "platform/fonts/opentype/OpenTypeVerticalData.h" | |
| 34 #include "wtf/PtrUtil.h" | |
| 35 #include "wtf/text/CString.h" | |
| 36 #include "wtf/text/CharacterNames.h" | |
| 37 #include "wtf/text/WTFString.h" | |
| 38 #include <memory> | |
| 39 #include <stdio.h> | |
| 40 | |
| 41 namespace blink { | |
| 42 | |
| 43 using std::max; | |
| 44 using std::min; | |
| 45 | |
| 46 HashMap<int, GlyphPageTreeNode*>* GlyphPageTreeNode::roots = 0; | |
| 47 GlyphPageTreeNode* GlyphPageTreeNode::pageZeroRoot = 0; | |
| 48 | |
| 49 GlyphPageTreeNode* GlyphPageTreeNode::getRoot(unsigned pageNumber) { | |
| 50 static bool initialized; | |
| 51 if (!initialized) { | |
| 52 initialized = true; | |
| 53 roots = new HashMap<int, GlyphPageTreeNode*>; | |
| 54 pageZeroRoot = new GlyphPageTreeNode(); | |
| 55 } | |
| 56 | |
| 57 if (!pageNumber) | |
| 58 return pageZeroRoot; | |
| 59 | |
| 60 if (GlyphPageTreeNode* foundNode = roots->get(pageNumber)) | |
| 61 return foundNode; | |
| 62 | |
| 63 GlyphPageTreeNode* node = new GlyphPageTreeNode(); | |
| 64 #if ENABLE(ASSERT) | |
| 65 node->m_pageNumber = pageNumber; | |
| 66 #endif | |
| 67 roots->set(pageNumber, node); | |
| 68 return node; | |
| 69 } | |
| 70 | |
| 71 size_t GlyphPageTreeNode::treeGlyphPageCount() { | |
| 72 size_t count = 0; | |
| 73 if (roots) { | |
| 74 HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end(); | |
| 75 for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); | |
| 76 it != end; ++it) | |
| 77 count += it->value->pageCount(); | |
| 78 } | |
| 79 | |
| 80 if (pageZeroRoot) | |
| 81 count += pageZeroRoot->pageCount(); | |
| 82 | |
| 83 return count; | |
| 84 } | |
| 85 | |
| 86 size_t GlyphPageTreeNode::pageCount() const { | |
| 87 size_t count = m_page && m_page->owner() == this ? 1 : 0; | |
| 88 | |
| 89 GlyphPageTreeNodeMap::const_iterator end = m_children.end(); | |
| 90 for (GlyphPageTreeNodeMap::const_iterator it = m_children.begin(); it != end; | |
| 91 ++it) | |
| 92 count += it->value->pageCount(); | |
| 93 | |
| 94 if (m_systemFallbackChild) | |
| 95 ++count; | |
| 96 | |
| 97 return count; | |
| 98 } | |
| 99 | |
| 100 void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData* fontData) { | |
| 101 // Enumerate all the roots and prune any tree that contains our custom font | |
| 102 // data. | |
| 103 if (roots) { | |
| 104 HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end(); | |
| 105 for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); | |
| 106 it != end; ++it) | |
| 107 it->value->pruneCustomFontData(fontData); | |
| 108 } | |
| 109 | |
| 110 if (pageZeroRoot) | |
| 111 pageZeroRoot->pruneCustomFontData(fontData); | |
| 112 } | |
| 113 | |
| 114 void GlyphPageTreeNode::pruneTreeFontData(const SimpleFontData* fontData) { | |
| 115 if (roots) { | |
| 116 HashMap<int, GlyphPageTreeNode*>::iterator end = roots->end(); | |
| 117 for (HashMap<int, GlyphPageTreeNode*>::iterator it = roots->begin(); | |
| 118 it != end; ++it) | |
| 119 it->value->pruneFontData(fontData); | |
| 120 } | |
| 121 | |
| 122 if (pageZeroRoot) | |
| 123 pageZeroRoot->pruneFontData(fontData); | |
| 124 } | |
| 125 | |
| 126 static bool fill(GlyphPage* pageToFill, | |
| 127 unsigned offset, | |
| 128 unsigned length, | |
| 129 UChar* buffer, | |
| 130 unsigned bufferLength, | |
| 131 const SimpleFontData* fontData) { | |
| 132 bool hasGlyphs = | |
| 133 fontData->fillGlyphPage(pageToFill, offset, length, buffer, bufferLength); | |
| 134 return hasGlyphs; | |
| 135 } | |
| 136 | |
| 137 void GlyphPageTreeNode::initializePage(const FontData* fontData, | |
| 138 unsigned pageNumber) { | |
| 139 ASSERT(!m_page); | |
| 140 ASSERT(fontData); | |
| 141 | |
| 142 // This function must not be called for the root of the tree, because that | |
| 143 // level does not contain any glyphs. | |
| 144 ASSERT(m_level > 0 && m_parent); | |
| 145 | |
| 146 if (m_level == 1) { | |
| 147 // Children of the root hold pure pages. These will cover only one | |
| 148 // font data's glyphs, and will have glyph index 0 if the font data does not | |
| 149 // contain the glyph. | |
| 150 initializePurePage(fontData, pageNumber); | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 // The parent's page will be 0 if we are level one or the parent's font data | |
| 155 // did not contain any glyphs for that page. | |
| 156 GlyphPage* parentPage = m_parent->page(); | |
| 157 | |
| 158 if (parentPage && parentPage->owner() != m_parent) { | |
| 159 // The page we're overriding may not be owned by our parent node. | |
| 160 // This happens when our parent node provides no useful overrides | |
| 161 // and just copies the pointer to an already-existing page (see | |
| 162 // below). | |
| 163 // | |
| 164 // We want our override to be shared by all nodes that reference | |
| 165 // that page to avoid duplication, and so standardize on having the | |
| 166 // page's owner collect all the overrides. Call getChild on the | |
| 167 // page owner with the desired font data (this will populate | |
| 168 // the page) and then reference it. | |
| 169 m_page = static_cast<GlyphPageTreeNode*>(parentPage->owner()) | |
| 170 ->getNormalChild(fontData, pageNumber) | |
| 171 ->page(); | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 initializeOverridePage(fontData, pageNumber); | |
| 176 } | |
| 177 | |
| 178 void GlyphPageTreeNode::initializePurePage(const FontData* fontData, | |
| 179 unsigned pageNumber) { | |
| 180 ASSERT(m_level == 1); | |
| 181 | |
| 182 unsigned start = pageNumber * GlyphPage::size; | |
| 183 UChar buffer[GlyphPage::size * 2 + 2]; | |
| 184 unsigned bufferLength; | |
| 185 unsigned i; | |
| 186 | |
| 187 // Fill in a buffer with the entire "page" of characters that we want to look | |
| 188 // up glyphs for. | |
| 189 if (start < 0x10000) { | |
| 190 bufferLength = GlyphPage::size; | |
| 191 for (i = 0; i < GlyphPage::size; i++) | |
| 192 buffer[i] = start + i; | |
| 193 | |
| 194 if (start == 0) { | |
| 195 // Control characters must not render at all. | |
| 196 for (i = 0; i < 0x20; ++i) | |
| 197 buffer[i] = zeroWidthSpaceCharacter; | |
| 198 for (i = 0x7F; i < 0xA0; i++) | |
| 199 buffer[i] = zeroWidthSpaceCharacter; | |
| 200 buffer[softHyphenCharacter] = zeroWidthSpaceCharacter; | |
| 201 | |
| 202 // \n and \t must render as a spaceCharacter. | |
| 203 buffer[newlineCharacter] = spaceCharacter; | |
| 204 buffer[tabulationCharacter] = spaceCharacter; | |
| 205 } else if (start == (arabicLetterMarkCharacter & ~(GlyphPage::size - 1))) { | |
| 206 buffer[arabicLetterMarkCharacter - start] = zeroWidthSpaceCharacter; | |
| 207 } else if (start == (leftToRightMarkCharacter & ~(GlyphPage::size - 1))) { | |
| 208 // LRM, RLM, LRE, RLE, ZWNJ, ZWJ, and PDF must not render at all. | |
| 209 buffer[leftToRightMarkCharacter - start] = zeroWidthSpaceCharacter; | |
| 210 buffer[rightToLeftMarkCharacter - start] = zeroWidthSpaceCharacter; | |
| 211 buffer[leftToRightEmbedCharacter - start] = zeroWidthSpaceCharacter; | |
| 212 buffer[rightToLeftEmbedCharacter - start] = zeroWidthSpaceCharacter; | |
| 213 buffer[leftToRightOverrideCharacter - start] = zeroWidthSpaceCharacter; | |
| 214 buffer[rightToLeftOverrideCharacter - start] = zeroWidthSpaceCharacter; | |
| 215 buffer[zeroWidthNonJoinerCharacter - start] = zeroWidthSpaceCharacter; | |
| 216 buffer[zeroWidthJoinerCharacter - start] = zeroWidthSpaceCharacter; | |
| 217 buffer[popDirectionalFormattingCharacter - start] = | |
| 218 zeroWidthSpaceCharacter; | |
| 219 buffer[activateArabicFormShapingCharacter - start] = | |
| 220 zeroWidthSpaceCharacter; | |
| 221 buffer[activateSymmetricSwappingCharacter - start] = | |
| 222 zeroWidthSpaceCharacter; | |
| 223 buffer[firstStrongIsolateCharacter - start] = zeroWidthSpaceCharacter; | |
| 224 buffer[inhibitArabicFormShapingCharacter - start] = | |
| 225 zeroWidthSpaceCharacter; | |
| 226 buffer[inhibitSymmetricSwappingCharacter - start] = | |
| 227 zeroWidthSpaceCharacter; | |
| 228 buffer[leftToRightIsolateCharacter - start] = zeroWidthSpaceCharacter; | |
| 229 buffer[nationalDigitShapesCharacter - start] = zeroWidthSpaceCharacter; | |
| 230 buffer[nominalDigitShapesCharacter - start] = zeroWidthSpaceCharacter; | |
| 231 buffer[popDirectionalIsolateCharacter - start] = zeroWidthSpaceCharacter; | |
| 232 buffer[rightToLeftIsolateCharacter - start] = zeroWidthSpaceCharacter; | |
| 233 } else if (start == (objectReplacementCharacter & ~(GlyphPage::size - 1))) { | |
| 234 // Object replacement character must not render at all. | |
| 235 buffer[objectReplacementCharacter - start] = zeroWidthSpaceCharacter; | |
| 236 } else if (start == | |
| 237 (zeroWidthNoBreakSpaceCharacter & ~(GlyphPage::size - 1))) { | |
| 238 // ZWNBS/BOM must not render at all. | |
| 239 buffer[zeroWidthNoBreakSpaceCharacter - start] = zeroWidthSpaceCharacter; | |
| 240 } | |
| 241 } else { | |
| 242 bufferLength = GlyphPage::size * 2; | |
| 243 for (i = 0; i < GlyphPage::size; i++) { | |
| 244 int c = i + start; | |
| 245 buffer[i * 2] = U16_LEAD(c); | |
| 246 buffer[i * 2 + 1] = U16_TRAIL(c); | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 // Now that we have a buffer full of characters, we want to get back an array | |
| 251 // of glyph indices. This part involves calling into the platform-specific | |
| 252 // routine of our glyph map for actually filling in the page with the glyphs. | |
| 253 // Success is not guaranteed. For example, Times fails to fill page 260, | |
| 254 // giving glyph data for only 128 out of 256 characters. | |
| 255 bool haveGlyphs; | |
| 256 if (!fontData->isSegmented()) { | |
| 257 m_page = | |
| 258 GlyphPage::createForSingleFontData(this, toSimpleFontData(fontData)); | |
| 259 haveGlyphs = fill(m_page.get(), 0, GlyphPage::size, buffer, bufferLength, | |
| 260 toSimpleFontData(fontData)); | |
| 261 } else { | |
| 262 m_page = GlyphPage::createForMixedFontData(this); | |
| 263 haveGlyphs = false; | |
| 264 | |
| 265 const SegmentedFontData* segmentedFontData = toSegmentedFontData(fontData); | |
| 266 for (int i = segmentedFontData->numFaces() - 1; i >= 0; i--) { | |
| 267 RefPtr<FontDataForRangeSet> fontDataForRangeSet = | |
| 268 segmentedFontData->faceAt(i); | |
| 269 RefPtr<UnicodeRangeSet> ranges = fontDataForRangeSet->ranges(); | |
| 270 // If there are no ranges, that means this font should be used for | |
| 271 // the full codepoint range, thus running the loop once over a | |
| 272 // synthetic full UnicodeRange object. Otherwise we use the ranges | |
| 273 // that come from the segmented font. This needs a locally | |
| 274 // initialized size_t variable (or a cast alternatively) as a | |
| 275 // compile fix for Android since size_t differs between platforms. | |
| 276 const size_t oneRoundForZeroRanges = 1u; | |
| 277 for (size_t i = 0; i < max(ranges->size(), oneRoundForZeroRanges); ++i) { | |
| 278 UnicodeRange range(0, kMaxCodepoint); | |
| 279 if (ranges->size()) { | |
| 280 range = ranges->rangeAt(i); | |
| 281 } | |
| 282 // all this casting is to ensure all the parameters to min and max have | |
| 283 // the same type, to avoid ambiguous template parameter errors on | |
| 284 // Windows | |
| 285 int from = | |
| 286 max(0, static_cast<int>(range.from()) - static_cast<int>(start)); | |
| 287 int to = 1 + min(static_cast<int>(range.to()) - static_cast<int>(start), | |
| 288 static_cast<int>(GlyphPage::size) - 1); | |
| 289 if (from >= static_cast<int>(GlyphPage::size) || to <= 0) | |
| 290 continue; | |
| 291 | |
| 292 // If this is a custom font needs to be loaded, do not fill | |
| 293 // the page so that font fallback is used while loading. | |
| 294 RefPtr<CustomFontData> customData = | |
| 295 fontDataForRangeSet->fontData()->customFontData(); | |
| 296 if (customData && customData->isLoadingFallback()) { | |
| 297 for (int j = from; j < to; j++) { | |
| 298 m_page->setCustomFontToLoad(j, customData.get()); | |
| 299 haveGlyphs = true; | |
| 300 } | |
| 301 continue; | |
| 302 } | |
| 303 | |
| 304 haveGlyphs |= fill(m_page.get(), from, to - from, | |
| 305 buffer + from * (start < 0x10000 ? 1 : 2), | |
| 306 (to - from) * (start < 0x10000 ? 1 : 2), | |
| 307 fontDataForRangeSet->fontData()); | |
| 308 } | |
| 309 } | |
| 310 } | |
| 311 | |
| 312 if (!haveGlyphs) | |
| 313 m_page = nullptr; | |
| 314 } | |
| 315 | |
| 316 void GlyphPageTreeNode::initializeOverridePage(const FontData* fontData, | |
| 317 unsigned pageNumber) { | |
| 318 GlyphPage* parentPage = m_parent->page(); | |
| 319 | |
| 320 // Get the pure page for the fallback font (at level 1 with no | |
| 321 // overrides). getRootChild will always create a page if one | |
| 322 // doesn't exist, but the page doesn't necessarily have glyphs | |
| 323 // (this pointer may be 0). | |
| 324 GlyphPage* fallbackPage = getNormalRootChild(fontData, pageNumber)->page(); | |
| 325 if (!parentPage) { | |
| 326 // When the parent has no glyphs for this page, we can easily | |
| 327 // override it just by supplying the glyphs from our font. | |
| 328 m_page = fallbackPage; | |
| 329 return; | |
| 330 } | |
| 331 | |
| 332 if (!fallbackPage) { | |
| 333 // When our font has no glyphs for this page, we can just reference the | |
| 334 // parent page. | |
| 335 m_page = parentPage; | |
| 336 return; | |
| 337 } | |
| 338 | |
| 339 // Combine the parent's glyphs and ours to form a new more complete page. | |
| 340 m_page = GlyphPage::createForMixedFontData(this); | |
| 341 | |
| 342 // Overlay the parent page on the fallback page. Check if the fallback font | |
| 343 // has added anything. | |
| 344 bool newGlyphs = false; | |
| 345 for (unsigned i = 0; i < GlyphPage::size; i++) { | |
| 346 if (parentPage->glyphAt(i)) { | |
| 347 m_page->setGlyphDataForIndex(i, parentPage->glyphDataForIndex(i)); | |
| 348 } else if (fallbackPage->glyphAt(i)) { | |
| 349 m_page->setGlyphDataForIndex(i, fallbackPage->glyphDataForIndex(i)); | |
| 350 newGlyphs = true; | |
| 351 } | |
| 352 | |
| 353 if (parentPage->customFontToLoadAt(i)) { | |
| 354 m_page->setCustomFontToLoad(i, parentPage->customFontToLoadAt(i)); | |
| 355 } else if (fallbackPage->customFontToLoadAt(i) && !parentPage->glyphAt(i)) { | |
| 356 m_page->setCustomFontToLoad(i, fallbackPage->customFontToLoadAt(i)); | |
| 357 newGlyphs = true; | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 if (!newGlyphs) { | |
| 362 // We didn't override anything, so our override is just the parent page. | |
| 363 m_page = parentPage; | |
| 364 } | |
| 365 } | |
| 366 | |
| 367 GlyphPageTreeNode* GlyphPageTreeNode::getNormalChild(const FontData* fontData, | |
| 368 unsigned pageNumber) { | |
| 369 ASSERT(fontData); | |
| 370 ASSERT(pageNumber == m_pageNumber); | |
| 371 | |
| 372 if (GlyphPageTreeNode* foundChild = m_children.get(fontData)) | |
| 373 return foundChild; | |
| 374 | |
| 375 GlyphPageTreeNode* child = new GlyphPageTreeNode(this); | |
| 376 if (fontData->isCustomFont()) { | |
| 377 for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent) | |
| 378 curr->m_customFontCount++; | |
| 379 } | |
| 380 | |
| 381 #if ENABLE(ASSERT) | |
| 382 child->m_pageNumber = m_pageNumber; | |
| 383 #endif | |
| 384 m_children.set(fontData, wrapUnique(child)); | |
| 385 fontData->setMaxGlyphPageTreeLevel( | |
| 386 max(fontData->maxGlyphPageTreeLevel(), child->m_level)); | |
| 387 child->initializePage(fontData, pageNumber); | |
| 388 return child; | |
| 389 } | |
| 390 | |
| 391 SystemFallbackGlyphPageTreeNode* GlyphPageTreeNode::getSystemFallbackChild( | |
| 392 unsigned pageNumber) { | |
| 393 ASSERT(pageNumber == m_pageNumber); | |
| 394 | |
| 395 if (m_systemFallbackChild) | |
| 396 return m_systemFallbackChild.get(); | |
| 397 | |
| 398 SystemFallbackGlyphPageTreeNode* child = | |
| 399 new SystemFallbackGlyphPageTreeNode(this); | |
| 400 m_systemFallbackChild = wrapUnique(child); | |
| 401 #if ENABLE(ASSERT) | |
| 402 child->m_pageNumber = m_pageNumber; | |
| 403 #endif | |
| 404 return child; | |
| 405 } | |
| 406 | |
| 407 void GlyphPageTreeNode::pruneCustomFontData(const FontData* fontData) { | |
| 408 if (!fontData || !m_customFontCount) | |
| 409 return; | |
| 410 | |
| 411 // Prune any branch that contains this FontData. | |
| 412 if (std::unique_ptr<GlyphPageTreeNode> node = m_children.take(fontData)) { | |
| 413 if (unsigned customFontCount = node->m_customFontCount + 1) { | |
| 414 for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent) | |
| 415 curr->m_customFontCount -= customFontCount; | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 // Check any branches that remain that still have custom fonts underneath | |
| 420 // them. | |
| 421 if (!m_customFontCount) | |
| 422 return; | |
| 423 | |
| 424 GlyphPageTreeNodeMap::iterator end = m_children.end(); | |
| 425 for (GlyphPageTreeNodeMap::iterator it = m_children.begin(); it != end; ++it) | |
| 426 it->value->pruneCustomFontData(fontData); | |
| 427 } | |
| 428 | |
| 429 void GlyphPageTreeNode::pruneFontData(const SimpleFontData* fontData, | |
| 430 unsigned level) { | |
| 431 ASSERT(fontData); | |
| 432 | |
| 433 // Prune fall back child (if any) of this font. | |
| 434 if (m_systemFallbackChild) | |
| 435 m_systemFallbackChild->pruneFontData(fontData); | |
| 436 | |
| 437 // Prune from m_page if it's a mixed page. | |
| 438 if (m_page && m_page->hasPerGlyphFontData()) | |
| 439 m_page->removePerGlyphFontData(fontData); | |
| 440 | |
| 441 // Prune any branch that contains this FontData. | |
| 442 if (std::unique_ptr<GlyphPageTreeNode> node = m_children.take(fontData)) { | |
| 443 if (unsigned customFontCount = node->m_customFontCount) { | |
| 444 for (GlyphPageTreeNode* curr = this; curr; curr = curr->m_parent) | |
| 445 curr->m_customFontCount -= customFontCount; | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 level++; | |
| 450 if (level > fontData->maxGlyphPageTreeLevel()) | |
| 451 return; | |
| 452 | |
| 453 GlyphPageTreeNodeMap::iterator end = m_children.end(); | |
| 454 for (GlyphPageTreeNodeMap::iterator it = m_children.begin(); it != end; ++it) | |
| 455 it->value->pruneFontData(fontData, level); | |
| 456 } | |
| 457 | |
| 458 GlyphPage* SystemFallbackGlyphPageTreeNode::page(UScriptCode script) { | |
| 459 PageByScriptMap::iterator it = m_pagesByScript.find(script); | |
| 460 if (it != m_pagesByScript.end()) | |
| 461 return it->value.get(); | |
| 462 | |
| 463 RefPtr<GlyphPage> newPage = initializePage(); | |
| 464 m_pagesByScript.set(script, newPage); | |
| 465 return newPage.get(); | |
| 466 } | |
| 467 | |
| 468 void SystemFallbackGlyphPageTreeNode::pruneFontData( | |
| 469 const SimpleFontData* fontData) { | |
| 470 PageByScriptMap::iterator end = m_pagesByScript.end(); | |
| 471 for (PageByScriptMap::iterator it = m_pagesByScript.begin(); it != end; ++it) | |
| 472 it->value->removePerGlyphFontData(fontData); | |
| 473 } | |
| 474 | |
| 475 PassRefPtr<GlyphPage> SystemFallbackGlyphPageTreeNode::initializePage() { | |
| 476 // System fallback page is initialized with the parent's page, as individual | |
| 477 // entries may use different fonts depending on character. If the Font | |
| 478 // ever finds it needs a glyph out of the system fallback page, it will | |
| 479 // ask the system for the best font to use and fill that glyph in for us. | |
| 480 if (GlyphPage* parentPage = m_parent->page()) | |
| 481 return parentPage->createCopiedSystemFallbackPage(this); | |
| 482 return GlyphPage::createForMixedFontData(this); | |
| 483 } | |
| 484 | |
| 485 } // namespace blink | |
| OLD | NEW |