1/*
2 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21
22#if ENABLE(SVG_FONTS)
23#include "core/svg/SVGFontData.h"
24
25#include "core/SVGNames.h"
26#include "core/XMLNames.h"
27#include "core/rendering/RenderObject.h"
28#include "core/rendering/svg/SVGTextRunRenderingContext.h"
29#include "core/svg/SVGAltGlyphElement.h"
30#include "core/svg/SVGFontElement.h"
31#include "core/svg/SVGFontFaceElement.h"
32#include "core/svg/SVGGlyphElement.h"
33#include "platform/fonts/Character.h"
34#include "platform/fonts/SVGGlyph.h"
35#include "platform/fonts/SimpleFontData.h"
36#include "platform/fonts/WidthIterator.h"
37#include "platform/text/TextRun.h"
38#include "wtf/text/StringBuilder.h"
39#include "wtf/unicode/CharacterNames.h"
40#include "wtf/unicode/Unicode.h"
41
42using namespace WTF;
43using namespace Unicode;
44
45namespace WebCore {
46
47SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
48    : CustomFontData()
49    , m_svgFontFaceElement(fontFaceElement->createWeakRef())
50    , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
51    , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
52    , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
53    , m_verticalOriginX(fontFaceElement->verticalOriginX())
54    , m_verticalOriginY(fontFaceElement->verticalOriginY())
55    , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
56{
57    ASSERT_ARG(fontFaceElement, fontFaceElement);
58}
59
60SVGFontData::~SVGFontData()
61{
62}
63
64void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
65{
66    ASSERT(fontData);
67
68    SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
69
70    SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
71    ASSERT(svgFontElement);
72    GlyphData missingGlyphData;
73    missingGlyphData.fontData = fontData;
74    missingGlyphData.glyph = svgFontElement->missingGlyph();
75    fontData->setMissingGlyphData(missingGlyphData);
76
77    fontData->setZeroWidthSpaceGlyph(0);
78    fontData->determinePitch();
79
80    unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
81    float scale = scaleEmToUnits(fontSize, unitsPerEm);
82    float xHeight = svgFontFaceElement->xHeight() * scale;
83    float ascent = svgFontFaceElement->ascent() * scale;
84    float descent = svgFontFaceElement->descent() * scale;
85    float lineGap = 0.1f * fontSize;
86
87    GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
88
89    if (!xHeight && glyphPageZero) {
90        // Fallback if x_heightAttr is not specified for the font element.
91        Glyph letterXGlyph = glyphPageZero->glyphForCharacter('x');
92        xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
93    }
94
95    FontMetrics& fontMetrics = fontData->fontMetrics();
96    fontMetrics.setUnitsPerEm(unitsPerEm);
97    fontMetrics.setAscent(ascent);
98    fontMetrics.setDescent(descent);
99    fontMetrics.setLineGap(lineGap);
100    fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
101    fontMetrics.setXHeight(xHeight);
102
103    if (!glyphPageZero) {
104        fontData->setSpaceGlyph(0);
105        fontData->setSpaceWidth(0);
106        fontData->setAvgCharWidth(0);
107        fontData->setMaxCharWidth(ascent);
108        return;
109    }
110
111    // Calculate space width.
112    Glyph spaceGlyph = glyphPageZero->glyphForCharacter(' ');
113    fontData->setSpaceGlyph(spaceGlyph);
114    fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
115
116    // Estimate average character width.
117    Glyph numeralZeroGlyph = glyphPageZero->glyphForCharacter('0');
118    fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
119
120    // Estimate maximum character width.
121    Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W');
122    fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
123}
124
125float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
126{
127    // FIXME: (http://crbug.com/359380) Width calculation may be triggered after removeNode from the current editing impl.
128    // The retrieved width is not being used, so here we return a dummy value.
129    if (shouldSkipDrawing())
130        return 0.0;
131
132    SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
133
134    // RenderView::clearSelection is invoked while removing some element, e.g.
135    // Document::nodeWillBeRemoved => FrameSelection::nodeWillBeRemoved => RenderView::clearSelection.
136    // Since recalc style has not been executed yet, RenderStyle might have some reference to
137    // SVGFontFaceElement which was also removed.
138    // In this case, use default horizontalAdvanceX instead of associatedFontElement's one.
139    if (!svgFontFaceElement->inDocument())
140        return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
141
142    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
143    ASSERT(associatedFontElement);
144
145    SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
146    SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
147    return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
148}
149
150bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
151{
152    const TextRun& run = iterator.run();
153    Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
154    ASSERT(int(run.charactersLength()) >= currentCharacter);
155
156    // Associate text with arabic forms, if needed.
157    String remainingTextInRun;
158
159    if (run.is8Bit()) {
160        remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
161        remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
162    } else {
163        remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
164        remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
165    }
166
167    if (mirror)
168        remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
169    if (!currentCharacter && arabicForms.isEmpty())
170        arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
171
172    SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
173    SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
174    ASSERT(associatedFontElement);
175
176    RenderObject* renderObject = 0;
177    if (TextRun::RenderingContext* renderingContext = run.renderingContext())
178        renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
179
180    String language;
181    bool isVerticalText = false;
182    Vector<AtomicString> altGlyphNames;
183
184    if (renderObject) {
185        RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
186        ASSERT(parentRenderObject);
187
188        isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode();
189        if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
190            language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
191
192            if (isSVGAltGlyphElement(*parentRenderObjectElement)) {
193                if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGlyphElements(altGlyphNames))
194                    altGlyphNames.clear();
195            }
196        }
197    }
198
199    Vector<SVGGlyph> glyphs;
200    size_t altGlyphNamesSize = altGlyphNames.size();
201    if (altGlyphNamesSize) {
202        for (size_t index = 0; index < altGlyphNamesSize; ++index)
203            associatedFontElement->collectGlyphsForAltGlyphReference(altGlyphNames[index], glyphs);
204
205        // Assign the unicodeStringLength now that its known.
206        size_t glyphsSize = glyphs.size();
207        for (size_t i = 0; i < glyphsSize; ++i)
208            glyphs[i].unicodeStringLength = run.length();
209
210        // Do not check alt glyphs for compatibility. Just return the first one.
211        // Later code will fail if we do not do this and the glyph is incompatible.
212        if (glyphsSize) {
213            SVGGlyph& svgGlyph = glyphs[0];
214            glyphData.glyph = svgGlyph.tableEntry;
215            advanceLength = svgGlyph.unicodeStringLength;
216            return true;
217        }
218    } else
219        associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
220
221    size_t glyphsSize = glyphs.size();
222    for (size_t i = 0; i < glyphsSize; ++i) {
223        SVGGlyph& svgGlyph = glyphs[i];
224        if (svgGlyph.isPartOfLigature)
225            continue;
226        if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
227            continue;
228        glyphData.glyph = svgGlyph.tableEntry;
229        advanceLength = svgGlyph.unicodeStringLength;
230        return true;
231    }
232
233    return false;
234}
235
236bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
237{
238    ASSERT(fontData->isCustomFont());
239    ASSERT(fontData->isSVGFont());
240
241    SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
242    SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
243    ASSERT(fontElement);
244
245    if (bufferLength == length)
246        return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
247
248    ASSERT(bufferLength == 2 * length);
249    return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
250}
251
252bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
253{
254    bool haveGlyphs = false;
255    Vector<SVGGlyph> glyphs;
256    for (unsigned i = 0; i < length; ++i) {
257        String lookupString(buffer + i, 1);
258        fontElement->collectGlyphsForString(lookupString, glyphs);
259        if (glyphs.isEmpty())
260            continue;
261
262        // Associate entry in glyph page with first valid SVGGlyph.
263        // If there are multiple valid ones, just take the first one. WidthIterator will take
264        // care of matching to the correct glyph, if multiple ones are available, as that's
265        // only possible within the context of a string (eg. arabic form matching).
266        haveGlyphs = true;
267        pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
268        glyphs.clear();
269    }
270
271    return haveGlyphs;
272}
273
274bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
275{
276    bool haveGlyphs = false;
277    Vector<SVGGlyph> glyphs;
278    for (unsigned i = 0; i < length; ++i) {
279        // Each character here consists of a surrogate pair
280        String lookupString(buffer + i * 2, 2);
281        fontElement->collectGlyphsForString(lookupString, glyphs);
282        if (glyphs.isEmpty())
283            continue;
284
285        // Associate entry in glyph page with first valid SVGGlyph.
286        // If there are multiple valid ones, just take the first one. WidthIterator will take
287        // care of matching to the correct glyph, if multiple ones are available, as that's
288        // only possible within the context of a string (eg. arabic form matching).
289        haveGlyphs = true;
290        pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
291        glyphs.clear();
292    }
293
294    return haveGlyphs;
295}
296
297String SVGFontData::createStringWithMirroredCharacters(const String& string) const
298{
299    if (string.isEmpty())
300        return emptyString();
301
302    unsigned length = string.length();
303
304    StringBuilder mirroredCharacters;
305    mirroredCharacters.reserveCapacity(length);
306
307    if (string.is8Bit()) {
308        const LChar* characters = string.characters8();
309        for (unsigned i = 0; i < length; ++i)
310            mirroredCharacters.append(mirroredChar(characters[i]));
311    } else {
312        const UChar* characters = string.characters16();
313        unsigned i = 0;
314        while (i < length) {
315            UChar32 character;
316            U16_NEXT(characters, i, length, character);
317            mirroredCharacters.append(mirroredChar(character));
318        }
319    }
320
321    return mirroredCharacters.toString();
322}
323
324SVGFontFaceElement* SVGFontData::svgFontFaceElement() const
325{
326    // FIXME: SVGFontData should be only used from the document with the SVGFontFaceElement.
327    RELEASE_ASSERT(m_svgFontFaceElement && m_svgFontFaceElement->inDocument());
328    return m_svgFontFaceElement.get();
329}
330
331bool SVGFontData::shouldSkipDrawing() const
332{
333    // FIXME: (http://crbug.com/359380) Glyph may be referenced after removeNode from the current editing impl.
334    return !m_svgFontFaceElement || !m_svgFontFaceElement->inDocument();
335}
336
337} // namespace WebCore
338
339#endif
340