| 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
|
|
|