bool RenderSVGTextPath::isChildAllowed(RenderObject* child, RenderStyle*) const { if (child->isText()) return SVGRenderSupport::isRenderableTextNode(child); #if ENABLE(SVG_FONTS) // 'altGlyph' is supported by the content model for 'textPath', but... ASSERT(child->node()); if (isSVGAltGlyphElement(*child->node())) return false; #endif return child->isSVGInline() && !child->isSVGTextPath(); }
bool SVGTSpanElement::rendererIsNeeded(const RenderStyle& style) { if (parentNode() && (isSVGAElement(*parentNode()) #if ENABLE(SVG_FONTS) || isSVGAltGlyphElement(*parentNode()) #endif || isSVGTextElement(*parentNode()) || isSVGTextPathElement(*parentNode()) || isSVGTSpanElement(*parentNode()))) return Element::rendererIsNeeded(style); return false; }
bool RenderSVGTSpan::isChildAllowed(RenderObject* child, RenderStyle*) const { // Always allow text (except empty textnodes and <br>). if (child->isText()) return SVGRenderSupport::isRenderableTextNode(child); #if ENABLE(SVG_FONTS) // Only allow other types of children if this is not an 'altGlyph'. ASSERT(node()); if (isSVGAltGlyphElement(*node())) return false; #endif return child->isSVGInline() && !child->isSVGTextPath(); }
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; } // Save data fromt he font fallback list because we may modify it later. Do this before the // potential change to glyphData.fontData below. FontFallbackList* fontList = font.fontList(); ASSERT(fontList); FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList); // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage. const SimpleFontData* originalFontData = glyphData.fontData; if (originalFontData && !originalFontData->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 (isSVGAltGlyphElement(*parentRenderObjectElement)) 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); // 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. page->setGlyphDataForCharacter(character, 0, 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); ASSERT(fallbackGlyphData.fontData); return fallbackGlyphData; }
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, unsigned currentCharacter, unsigned& advanceLength) const { const TextRun& run = iterator.run(); Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms(); ASSERT(run.charactersLength() >= currentCharacter); // Associate text with arabic forms, if needed. String remainingTextInRun; if (run.is8Bit()) { remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter); remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length()); } else { remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter); remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length()); } if (mirror) remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun); if (!currentCharacter && arabicForms.isEmpty()) arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(associatedFontElement); RenderObject* renderObject = 0; if (TextRun::RenderingContext* renderingContext = run.renderingContext()) renderObject = &static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); String language; bool isVerticalText = false; Vector<String> altGlyphNames; if (renderObject) { RenderElement* parentRenderer = renderObject->isRenderElement() ? toRenderElement(renderObject) : renderObject->parent(); ASSERT(parentRenderer); isVerticalText = parentRenderer->style().svgStyle().isVerticalWritingMode(); if (Element* parentRendererElement = parentRenderer->element()) { language = parentRendererElement->getAttribute(XMLNames::langAttr); if (isSVGAltGlyphElement(parentRendererElement)) { SVGAltGlyphElement* altGlyph = toSVGAltGlyphElement(parentRendererElement); if (!altGlyph->hasValidGlyphElements(altGlyphNames)) altGlyphNames.clear(); } } } Vector<SVGGlyph> glyphs; size_t altGlyphNamesSize = altGlyphNames.size(); if (altGlyphNamesSize) { for (size_t index = 0; index < altGlyphNamesSize; ++index) associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs); // Assign the unicodeStringLength now that its known. size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) glyphs[i].unicodeStringLength = run.length(); // Do not check alt glyphs for compatibility. Just return the first one. // Later code will fail if we do not do this and the glyph is incompatible. if (glyphsSize) { SVGGlyph& svgGlyph = glyphs[0]; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } } else associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs); size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) { SVGGlyph& svgGlyph = glyphs[i]; if (svgGlyph.isPartOfLigature) continue; if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength)) continue; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } iterator.setLastGlyphName(String()); return false; }