Index: Source/core/svg/SVGFontData.cpp |
diff --git a/Source/core/svg/SVGFontData.cpp b/Source/core/svg/SVGFontData.cpp |
deleted file mode 100644 |
index 4d0bb2777515a4024da6d89daf7d25ebe798f2c6..0000000000000000000000000000000000000000 |
--- a/Source/core/svg/SVGFontData.cpp |
+++ /dev/null |
@@ -1,339 +0,0 @@ |
-/* |
- * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> |
- * |
- * This library is free software; you can redistribute it and/or |
- * modify it under the terms of the GNU Library General Public |
- * License as published by the Free Software Foundation; either |
- * version 2 of the License, or (at your option) any later version. |
- * |
- * This library is distributed in the hope that it will be useful, |
- * but WITHOUT ANY WARRANTY; without even the implied warranty of |
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
- * Library General Public License for more details. |
- * |
- * You should have received a copy of the GNU Library General Public License |
- * along with this library; see the file COPYING.LIB. If not, write to |
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
- * Boston, MA 02110-1301, USA. |
- */ |
- |
-#include "config.h" |
- |
-#if ENABLE(SVG_FONTS) |
-#include "core/svg/SVGFontData.h" |
- |
-#include "core/SVGNames.h" |
-#include "core/XMLNames.h" |
-#include "core/rendering/RenderObject.h" |
-#include "core/rendering/svg/SVGTextRunRenderingContext.h" |
-#include "core/svg/SVGAltGlyphElement.h" |
-#include "core/svg/SVGFontElement.h" |
-#include "core/svg/SVGFontFaceElement.h" |
-#include "core/svg/SVGGlyphElement.h" |
-#include "platform/fonts/Character.h" |
-#include "platform/fonts/SVGGlyph.h" |
-#include "platform/fonts/SimpleFontData.h" |
-#include "platform/fonts/shaping/SimpleShaper.h" |
-#include "platform/text/TextRun.h" |
-#include "wtf/text/StringBuilder.h" |
-#include "wtf/unicode/CharacterNames.h" |
-#include "wtf/unicode/Unicode.h" |
- |
-using namespace WTF; |
-using namespace Unicode; |
- |
-namespace blink { |
- |
-SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement) |
- : CustomFontData() |
- , m_svgFontFaceElement(fontFaceElement->createWeakRef()) |
- , m_horizontalOriginX(fontFaceElement->horizontalOriginX()) |
- , m_horizontalOriginY(fontFaceElement->horizontalOriginY()) |
- , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX()) |
- , m_verticalOriginX(fontFaceElement->verticalOriginX()) |
- , m_verticalOriginY(fontFaceElement->verticalOriginY()) |
- , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY()) |
-{ |
- ASSERT_ARG(fontFaceElement, fontFaceElement); |
-} |
- |
-SVGFontData::~SVGFontData() |
-{ |
-} |
- |
-void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize) |
-{ |
- ASSERT(fontData); |
- |
- SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); |
- |
- SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement(); |
- ASSERT(svgFontElement); |
- GlyphData missingGlyphData; |
- missingGlyphData.fontData = fontData; |
- missingGlyphData.glyph = svgFontElement->missingGlyph(); |
- fontData->setMissingGlyphData(missingGlyphData); |
- |
- fontData->setZeroWidthSpaceGlyph(0); |
- fontData->determinePitch(); |
- |
- unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); |
- float scale = scaleEmToUnits(fontSize, unitsPerEm); |
- float xHeight = svgFontFaceElement->xHeight() * scale; |
- float ascent = svgFontFaceElement->ascent() * scale; |
- float descent = svgFontFaceElement->descent() * scale; |
- float lineGap = 0.1f * fontSize; |
- |
- GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page(); |
- |
- if (!xHeight && glyphPageZero) { |
- // Fallback if x_heightAttr is not specified for the font element. |
- Glyph letterXGlyph = glyphPageZero->glyphForCharacter('x'); |
- xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3; |
- } |
- |
- FontMetrics& fontMetrics = fontData->fontMetrics(); |
- fontMetrics.setUnitsPerEm(unitsPerEm); |
- fontMetrics.setAscent(ascent); |
- fontMetrics.setDescent(descent); |
- fontMetrics.setLineGap(lineGap); |
- fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); |
- fontMetrics.setXHeight(xHeight); |
- |
- if (!glyphPageZero) { |
- fontData->setSpaceGlyph(0); |
- fontData->setSpaceWidth(0); |
- fontData->setAvgCharWidth(0); |
- fontData->setMaxCharWidth(ascent); |
- return; |
- } |
- |
- // Calculate space width. |
- Glyph spaceGlyph = glyphPageZero->glyphForCharacter(' '); |
- fontData->setSpaceGlyph(spaceGlyph); |
- fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph)); |
- |
- // Estimate average character width. |
- Glyph numeralZeroGlyph = glyphPageZero->glyphForCharacter('0'); |
- fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth()); |
- |
- // Estimate maximum character width. |
- Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W'); |
- fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent); |
-} |
- |
-float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const |
-{ |
- // FIXME: (http://crbug.com/359380) Width calculation may be triggered after removeNode from the current editing impl. |
- // The retrieved width is not being used, so here we return a dummy value. |
- if (shouldSkipDrawing()) |
- return 0.0; |
- |
- SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); |
- |
- // RenderView::clearSelection is invoked while removing some element, e.g. |
- // Document::nodeWillBeRemoved => FrameSelection::nodeWillBeRemoved => RenderView::clearSelection. |
- // Since recalc style has not been executed yet, RenderStyle might have some reference to |
- // SVGFontFaceElement which was also removed. |
- // In this case, use default horizontalAdvanceX instead of associatedFontElement's one. |
- if (!svgFontFaceElement->inDocument()) |
- return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm()); |
- |
- SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); |
- ASSERT(associatedFontElement); |
- |
- SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph); |
- SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this); |
- return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm()); |
-} |
- |
-bool SVGFontData::applySVGGlyphSelection(SimpleShaper& shaper, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const |
-{ |
- const TextRun& run = shaper.run(); |
- Vector<SVGGlyph::ArabicForm>& arabicForms = shaper.arabicForms(); |
- ASSERT(int(run.charactersLength()) >= currentCharacter); |
- |
- // Associate text with arabic forms, if needed. |
- String remainingTextInRun; |
- |
- if (run.is8Bit()) { |
- remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter); |
- remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length()); |
- } else { |
- remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter); |
- remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length()); |
- } |
- |
- if (mirror) |
- remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun); |
- if (!currentCharacter && arabicForms.isEmpty()) |
- arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); |
- |
- SVGFontFaceElement* svgFontFaceElement = this->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<AtomicString> altGlyphNames; |
- |
- if (renderObject) { |
- RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; |
- ASSERT(parentRenderObject); |
- |
- isVerticalText = parentRenderObject->style()->svgStyle().isVerticalWritingMode(); |
- if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { |
- language = parentRenderObjectElement->getAttribute(XMLNames::langAttr); |
- |
- if (isSVGAltGlyphElement(*parentRenderObjectElement)) { |
- if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGlyphElements(altGlyphNames)) |
- altGlyphNames.clear(); |
- } |
- } |
- } |
- |
- Vector<SVGGlyph> glyphs; |
- size_t altGlyphNamesSize = altGlyphNames.size(); |
- if (altGlyphNamesSize) { |
- for (size_t index = 0; index < altGlyphNamesSize; ++index) |
- associatedFontElement->collectGlyphsForAltGlyphReference(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]; |
- 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; |
- glyphData.glyph = svgGlyph.tableEntry; |
- advanceLength = svgGlyph.unicodeStringLength; |
- return true; |
- } |
- |
- return false; |
-} |
- |
-bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const |
-{ |
- ASSERT(fontData->isCustomFont()); |
- ASSERT(fontData->isSVGFont()); |
- |
- SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement(); |
- SVGFontElement* fontElement = fontFaceElement->associatedFontElement(); |
- ASSERT(fontElement); |
- |
- if (bufferLength == length) |
- return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); |
- |
- ASSERT(bufferLength == 2 * length); |
- return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); |
-} |
- |
-bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const |
-{ |
- bool haveGlyphs = false; |
- Vector<SVGGlyph> glyphs; |
- for (unsigned i = 0; i < length; ++i) { |
- String lookupString(buffer + i, 1); |
- fontElement->collectGlyphsForString(lookupString, glyphs); |
- if (glyphs.isEmpty()) |
- continue; |
- |
- // Associate entry in glyph page with first valid SVGGlyph. |
- // If there are multiple valid ones, just take the first one. SimpleShaper will take |
- // care of matching to the correct glyph, if multiple ones are available, as that's |
- // only possible within the context of a string (eg. arabic form matching). |
- haveGlyphs = true; |
- pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData); |
- glyphs.clear(); |
- } |
- |
- return haveGlyphs; |
-} |
- |
-bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const |
-{ |
- bool haveGlyphs = false; |
- Vector<SVGGlyph> glyphs; |
- for (unsigned i = 0; i < length; ++i) { |
- // Each character here consists of a surrogate pair |
- String lookupString(buffer + i * 2, 2); |
- fontElement->collectGlyphsForString(lookupString, glyphs); |
- if (glyphs.isEmpty()) |
- continue; |
- |
- // Associate entry in glyph page with first valid SVGGlyph. |
- // If there are multiple valid ones, just take the first one. SimpleShaper will take |
- // care of matching to the correct glyph, if multiple ones are available, as that's |
- // only possible within the context of a string (eg. arabic form matching). |
- haveGlyphs = true; |
- pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData); |
- glyphs.clear(); |
- } |
- |
- return haveGlyphs; |
-} |
- |
-String SVGFontData::createStringWithMirroredCharacters(const String& string) const |
-{ |
- if (string.isEmpty()) |
- return emptyString(); |
- |
- unsigned length = string.length(); |
- |
- StringBuilder mirroredCharacters; |
- mirroredCharacters.reserveCapacity(length); |
- |
- if (string.is8Bit()) { |
- const LChar* characters = string.characters8(); |
- for (unsigned i = 0; i < length; ++i) |
- mirroredCharacters.append(mirroredChar(characters[i])); |
- } else { |
- const UChar* characters = string.characters16(); |
- unsigned i = 0; |
- while (i < length) { |
- UChar32 character; |
- U16_NEXT(characters, i, length, character); |
- mirroredCharacters.append(mirroredChar(character)); |
- } |
- } |
- |
- return mirroredCharacters.toString(); |
-} |
- |
-SVGFontFaceElement* SVGFontData::svgFontFaceElement() const |
-{ |
- // FIXME: SVGFontData should be only used from the document with the SVGFontFaceElement. |
- RELEASE_ASSERT(m_svgFontFaceElement && m_svgFontFaceElement->inDocument()); |
- return m_svgFontFaceElement.get(); |
-} |
- |
-bool SVGFontData::shouldSkipDrawing() const |
-{ |
- // FIXME: (http://crbug.com/359380) Glyph may be referenced after removeNode from the current editing impl. |
- return !m_svgFontFaceElement || !m_svgFontFaceElement->inDocument(); |
-} |
- |
-} // namespace blink |
- |
-#endif |