| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> | |
| 3 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. | |
| 4 * | |
| 5 * This library is free software; you can redistribute it and/or | |
| 6 * modify it under the terms of the GNU Library General Public | |
| 7 * License as published by the Free Software Foundation; either | |
| 8 * version 2 of the License, or (at your option) any later version. | |
| 9 * | |
| 10 * This library is distributed in the hope that it will be useful, | |
| 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 13 * Library General Public License for more details. | |
| 14 * | |
| 15 * You should have received a copy of the GNU Library General Public License | |
| 16 * along with this library; see the file COPYING.LIB. If not, write to | |
| 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 18 * Boston, MA 02110-1301, USA. | |
| 19 */ | |
| 20 | |
| 21 #include "config.h" | |
| 22 | |
| 23 #if ENABLE(SVG_FONTS) | |
| 24 #include "core/rendering/svg/SVGTextRunRenderingContext.h" | |
| 25 | |
| 26 #include "core/rendering/RenderObject.h" | |
| 27 #include "core/svg/SVGFontData.h" | |
| 28 #include "core/svg/SVGFontElement.h" | |
| 29 #include "core/svg/SVGFontFaceElement.h" | |
| 30 #include "core/svg/SVGGlyphElement.h" | |
| 31 #include "platform/fonts/GlyphBuffer.h" | |
| 32 #include "platform/fonts/shaping/SimpleShaper.h" | |
| 33 #include "platform/graphics/GraphicsContext.h" | |
| 34 | |
| 35 namespace blink { | |
| 36 | |
| 37 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const Simp
leFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font) | |
| 38 { | |
| 39 ASSERT(fontData); | |
| 40 ASSERT(fontData->isCustomFont()); | |
| 41 ASSERT(fontData->isSVGFont()); | |
| 42 | |
| 43 RefPtr<CustomFontData> customFontData = fontData->customFontData(); | |
| 44 const SVGFontData* svgFontData = toSVGFontData(customFontData); | |
| 45 | |
| 46 // FIXME crbug.com/359380 : The current editing impl references the font aft
er the svg font nodes are removed. | |
| 47 if (svgFontData->shouldSkipDrawing()) | |
| 48 return 0; | |
| 49 | |
| 50 fontFace = svgFontData->svgFontFaceElement(); | |
| 51 ASSERT(fontFace); | |
| 52 | |
| 53 font = fontFace->associatedFontElement(); | |
| 54 return svgFontData; | |
| 55 } | |
| 56 | |
| 57 static inline RenderObject* firstParentRendererForNonTextNode(RenderObject* rend
erer) | |
| 58 { | |
| 59 ASSERT(renderer); | |
| 60 return renderer->isText() ? renderer->parent() : renderer; | |
| 61 } | |
| 62 | |
| 63 static inline RenderObject* renderObjectFromRun(const TextRun& run) | |
| 64 { | |
| 65 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) | |
| 66 return static_cast<SVGTextRunRenderingContext*>(renderingContext)->rende
rer(); | |
| 67 return 0; | |
| 68 } | |
| 69 | |
| 70 float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const
TextRun& run, int& charsConsumed, Glyph& glyphId) const | |
| 71 { | |
| 72 SimpleShaper it(&font, run); | |
| 73 GlyphBuffer glyphBuffer; | |
| 74 charsConsumed += it.advance(run.length(), &glyphBuffer); | |
| 75 glyphId = !glyphBuffer.isEmpty() ? glyphBuffer.glyphAt(0) : 0; | |
| 76 return it.runWidthSoFar(); | |
| 77 } | |
| 78 | |
| 79 void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const T
extRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int
from, int numGlyphs, const FloatPoint& point) const | |
| 80 { | |
| 81 SVGFontElement* fontElement = 0; | |
| 82 SVGFontFaceElement* fontFaceElement = 0; | |
| 83 | |
| 84 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontDa
ta, fontFaceElement, fontElement); | |
| 85 if (!fontElement || !fontFaceElement) | |
| 86 return; | |
| 87 | |
| 88 // We can only paint SVGFonts if a context is available. | |
| 89 RenderObject* renderObject = renderObjectFromRun(run); | |
| 90 ASSERT(renderObject); | |
| 91 | |
| 92 bool isVerticalText = false; | |
| 93 if (RenderObject* parentRenderObject = firstParentRendererForNonTextNode(ren
derObject)) { | |
| 94 RenderStyle* parentRenderObjectStyle = parentRenderObject->style(); | |
| 95 ASSERT(parentRenderObjectStyle); | |
| 96 isVerticalText = parentRenderObjectStyle->svgStyle().isVerticalWritingMo
de(); | |
| 97 } | |
| 98 | |
| 99 float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElemen
t->unitsPerEm()); | |
| 100 | |
| 101 FloatPoint glyphOrigin; | |
| 102 glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); | |
| 103 glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); | |
| 104 | |
| 105 FloatPoint currentPoint = point; | |
| 106 for (int i = 0; i < numGlyphs; ++i) { | |
| 107 Glyph glyph = glyphBuffer.glyphAt(from + i); | |
| 108 if (!glyph) | |
| 109 continue; | |
| 110 | |
| 111 float advance = glyphBuffer.advanceAt(from + i); | |
| 112 SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); | |
| 113 ASSERT(!svgGlyph.isPartOfLigature); | |
| 114 ASSERT(svgGlyph.tableEntry == glyph); | |
| 115 | |
| 116 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); | |
| 117 | |
| 118 // FIXME: Support arbitary SVG content as glyph (currently limited to <g
lyph d="..."> situations). | |
| 119 if (svgGlyph.pathData.isEmpty()) { | |
| 120 if (isVerticalText) | |
| 121 currentPoint.move(0, advance); | |
| 122 else | |
| 123 currentPoint.move(advance, 0); | |
| 124 continue; | |
| 125 } | |
| 126 | |
| 127 if (isVerticalText) { | |
| 128 glyphOrigin.setX(svgGlyph.verticalOriginX * scale); | |
| 129 glyphOrigin.setY(svgGlyph.verticalOriginY * scale); | |
| 130 } | |
| 131 | |
| 132 AffineTransform glyphPathTransform; | |
| 133 glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), current
Point.y() + glyphOrigin.y()); | |
| 134 glyphPathTransform.scale(scale, -scale); | |
| 135 | |
| 136 Path glyphPath = svgGlyph.pathData; | |
| 137 glyphPath.transform(glyphPathTransform); | |
| 138 | |
| 139 if (context->textDrawingMode() == TextModeStroke) | |
| 140 context->strokePath(glyphPath); | |
| 141 else | |
| 142 context->fillPath(glyphPath); | |
| 143 | |
| 144 if (isVerticalText) | |
| 145 currentPoint.move(0, advance); | |
| 146 else | |
| 147 currentPoint.move(advance, 0); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co
nst TextRun& run, SimpleShaper& iterator, UChar32 character, bool mirror, int cu
rrentCharacter, unsigned& advanceLength) | |
| 152 { | |
| 153 const SimpleFontData* primaryFont = font.primaryFont(); | |
| 154 ASSERT(primaryFont); | |
| 155 | |
| 156 pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(charact
er, mirror); | |
| 157 GlyphData glyphData = pair.first; | |
| 158 | |
| 159 // Check if we have the missing glyph data, in which case we can just return
. | |
| 160 GlyphData missingGlyphData = primaryFont->missingGlyphData(); | |
| 161 if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missi
ngGlyphData.fontData) { | |
| 162 ASSERT(glyphData.fontData); | |
| 163 return glyphData; | |
| 164 } | |
| 165 | |
| 166 // Save data fromt he font fallback list because we may modify it later. Do
this before the | |
| 167 // potential change to glyphData.fontData below. | |
| 168 FontFallbackList* fontList = font.fontList(); | |
| 169 ASSERT(fontList); | |
| 170 FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList); | |
| 171 | |
| 172 // Characters enclosed by an <altGlyph> element, may not be registered in th
e GlyphPage. | |
| 173 const SimpleFontData* originalFontData = glyphData.fontData; | |
| 174 if (originalFontData && !originalFontData->isSVGFont()) { | |
| 175 if (TextRun::RenderingContext* renderingContext = run.renderingContext()
) { | |
| 176 RenderObject* renderObject = static_cast<SVGTextRunRenderingContext*
>(renderingContext)->renderer(); | |
| 177 RenderObject* parentRenderObject = renderObject->isText() ? renderOb
ject->parent() : renderObject; | |
| 178 ASSERT(parentRenderObject); | |
| 179 if (Element* parentRenderObjectElement = toElement(parentRenderObjec
t->node())) { | |
| 180 if (isSVGAltGlyphElement(*parentRenderObjectElement)) | |
| 181 glyphData.fontData = primaryFont; | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 const SimpleFontData* fontData = glyphData.fontData; | |
| 187 if (fontData) { | |
| 188 if (!fontData->isSVGFont()) | |
| 189 return glyphData; | |
| 190 | |
| 191 SVGFontElement* fontElement = 0; | |
| 192 SVGFontFaceElement* fontFaceElement = 0; | |
| 193 | |
| 194 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fo
ntData, fontFaceElement, fontElement); | |
| 195 if (!fontElement || !fontFaceElement) | |
| 196 return glyphData; | |
| 197 | |
| 198 // If we got here, we're dealing with a glyph defined in a SVG Font. | |
| 199 // The returned glyph by glyphDataAndPageForCharacter() is a glyph store
d in the SVG Font glyph table. | |
| 200 // This doesn't necessarily mean the glyph is suitable for rendering/mea
suring in this context, its | |
| 201 // arabic-form/orientation/... may not match, we have to apply SVG Glyph
selection to discover that. | |
| 202 if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, cur
rentCharacter, advanceLength)) | |
| 203 return glyphData; | |
| 204 } | |
| 205 | |
| 206 GlyphPage* page = pair.second; | |
| 207 ASSERT(page); | |
| 208 | |
| 209 // No suitable glyph found that is compatible with the requirments (same lan
guage, arabic-form, orientation etc.) | |
| 210 // Even though our GlyphPage contains an entry for eg. glyph "a", it's not c
ompatible. So we have to temporarily | |
| 211 // remove the glyph data information from the GlyphPage, and retry the looku
p, which handles font fallbacks correctly. | |
| 212 page->setGlyphDataForCharacter(character, 0, 0); | |
| 213 | |
| 214 // Assure that the font fallback glyph selection worked, aka. the fallbackGl
yphData font data is not the same as before. | |
| 215 GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror); | |
| 216 ASSERT(fallbackGlyphData.fontData != fontData); | |
| 217 | |
| 218 // Restore original state of the SVG Font glyph table and the current font f
allback list, | |
| 219 // to assure the next lookup of the same glyph won't immediately return the
fallback glyph. | |
| 220 page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData)
; | |
| 221 ASSERT(fallbackGlyphData.fontData); | |
| 222 return fallbackGlyphData; | |
| 223 } | |
| 224 | |
| 225 } | |
| 226 | |
| 227 #endif | |
| OLD | NEW |