Font::CodePath Font::codePath(const TextRun& run) const { if (s_codePath != Auto) return s_codePath; #if ENABLE(SVG_FONTS) if (run.renderingContext()) return Simple; #endif if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0) return Complex; if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this)) return Complex; if (!run.characterScanForCodePath()) return Simple; if (run.is8Bit()) return Simple; // Start from 0 since drawing and highlighting also measure the characters before run->from. return characterRangeCodePath(run.characters16(), run.length()); }
void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun) { releasePaintingResource(context, /* path */0); #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = textRun.renderingContext(); if (renderingContext) static_cast<SVGTextRunRenderingContext*>(renderingContext)->setActivePaintingResource(0); #endif }
float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const { #if ENABLE(SVG_FONTS) if (TextRun::RenderingContext* renderingContext = run.renderingContext()) return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName); #endif charsConsumed = run.length(); glyphName = ""; return width(run); }
void Font::drawGlyphBuffer(GraphicsContext* context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const { #if !ENABLE(SVG_FONTS) UNUSED_PARAM(run); #endif // Draw each contiguous run of glyphs that use the same font data. const SimpleFontData* fontData = glyphBuffer.fontDataAt(0); FloatSize offset = glyphBuffer.offsetAt(0); FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height()); float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width(); float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height(); int lastFrom = 0; int nextGlyph = 1; #if ENABLE(SVG_FONTS) TextRun::RenderingContext* renderingContext = run.renderingContext(); #endif while (nextGlyph < glyphBuffer.size()) { const SimpleFontData* nextFontData = glyphBuffer.fontDataAt(nextGlyph); FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph); if (nextFontData != fontData || nextOffset != offset) { #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); lastFrom = nextGlyph; fontData = nextFontData; offset = nextOffset; startPoint.setX(nextX); startPoint.setY(nextY); } nextX += glyphBuffer.advanceAt(nextGlyph).width(); nextY += glyphBuffer.advanceAt(nextGlyph).height(); nextGlyph++; } #if ENABLE(SVG_FONTS) if (renderingContext && fontData->isSVGFont()) renderingContext->drawSVGGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); else { #endif drawGlyphs(context, fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint); point.setX(nextX); #if ENABLE(SVG_FONTS) } #endif }
bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) { bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); if (!acquiredResource) return false; #if ENABLE(SVG_FONTS) // SVG Fonts need access to the painting resource used to draw the current text chunk. TextRun::RenderingContext* renderingContext = textRun.renderingContext(); if (renderingContext) static_cast<SVGTextRunRenderingContext*>(renderingContext)->setActivePaintingResource(m_paintingResource); #endif return true; }
GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, const TextRun& run, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) { const SimpleFontData* primaryFont = font.primaryFont(); ASSERT(primaryFont); pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror); GlyphData glyphData = pair.first; // Check if we have the missing glyph data, in which case we can just return. GlyphData missingGlyphData = primaryFont->missingGlyphData(); if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missingGlyphData.fontData) { ASSERT(glyphData.fontData); return glyphData; } // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage. const SimpleFontData* originalFontData = glyphData.fontData; if (glyphData.fontData && !glyphData.fontData->isSVGFont()) { if (TextRun::RenderingContext* renderingContext = run.renderingContext()) { RenderObject* renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; ASSERT(parentRenderObject); if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) glyphData.fontData = primaryFont; } } } const SimpleFontData* fontData = glyphData.fontData; if (fontData) { if (!fontData->isSVGFont()) return glyphData; SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); if (!fontElement || !fontFaceElement) return glyphData; // If we got here, we're dealing with a glyph defined in a SVG Font. // The returned glyph by glyphDataAndPageForCharacter() is a glyph stored in the SVG Font glyph table. // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that. if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength)) return glyphData; } GlyphPage* page = pair.second; ASSERT(page); FontFallbackList* fontList = font.fontList(); ASSERT(fontList); // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.) // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly. GlyphPageTreeNode* originalGlyphPageZero = fontList->glyphPageZero(); const FontFallbackList::GlyphPages& originalGlyphPages = fontList->glyphPages(); page->setGlyphDataForCharacter(character, glyphData.glyph, 0); // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before. GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror); ASSERT(fallbackGlyphData.fontData != fontData); // Restore original state of the SVG Font glyph table and the current font fallback list, // to assure the next lookup of the same glyph won't immediately return the fallback glyph. page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData); fontList->setGlyphPageZero(originalGlyphPageZero); fontList->setGlyphPages(originalGlyphPages); ASSERT(fallbackGlyphData.fontData); return fallbackGlyphData; }
Font::CodePath Font::codePath(const TextRun& run) const { if (s_codePath != Auto) return s_codePath; #if ENABLE(SVG_FONTS) if (run.renderingContext()) return Simple; #endif #if PLATFORM(QT) && !HAVE(QRAWFONT) if (run.expansion() || run.rtl() || isSmallCaps() || wordSpacing() || letterSpacing()) return Complex; #endif if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0) return Complex; CodePath result = Simple; // Start from 0 since drawing and highlighting also measure the characters before run->from // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we // can't simply use UnicodeCharacter Property/class because some characters // are not 'combining', but still need to go to the complex path. // Alternatively, we may as well consider binary search over a sorted // list of ranges. for (int i = 0; i < run.length(); i++) { const UChar c = run[i]; if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters) continue; if (c <= 0x2E9) return Complex; if (c < 0x300) // U+0300 through U+036F Combining diacritical marks continue; if (c <= 0x36F) return Complex; if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha continue; if (c <= 0x05CF) return Complex; // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic, // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar if (c < 0x0600) continue; if (c <= 0x109F) return Complex; // 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) if (c < 0x1100) continue; if (c <= 0x11FF) return Complex; if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks continue; if (c <= 0x135F) return Complex; if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian continue; if (c <= 0x18AF) return Complex; if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0) continue; if (c <= 0x194F) return Complex; if (c < 0x1980) // U+1980 through U+19DF New Tai Lue continue; if (c <= 0x19DF) return Complex; if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic continue; if (c <= 0x1CFF) return Complex; if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement continue; if (c <= 0x1DFF) return Complex; // U+1E00 through U+2000 characters with diacritics and stacked diacritics if (c <= 0x2000) { result = SimpleWithGlyphOverflow; continue; } if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols continue; if (c <= 0x20FF) return Complex; if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic continue; if (c <= 0x2CF1) return Complex; if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks continue; if (c <= 0x302F) return Complex; if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic continue; if (c <= 0xA67D) return Complex; if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum continue; if (c <= 0xA6F1) return Complex; // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended, // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek, if (c < 0xA800) continue; if (c <= 0xABFF) return Complex; if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B continue; if (c <= 0xD7FF) return Complex; if (c <= 0xDBFF) { // High surrogate if (i == run.length() - 1) continue; UChar next = run[++i]; if (!U16_IS_TRAIL(next)) continue; UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next); if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols continue; if (supplementaryCharacter <= 0x1F1FF) return Complex; if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors. continue; if (supplementaryCharacter <= 0xE01EF) return Complex; // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts // in plane 1 or higher. continue; } if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors continue; if (c <= 0xFE0F) return Complex; if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks continue; if (c <= 0xFE2F) return Complex; } if (run.length() > 1 && typesettingFeatures()) return Complex; return result; }