1 /* 2 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) 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/rendering/svg/RenderSVGInlineText.h" 28 #include "core/rendering/svg/RenderSVGResourceSolidColor.h" 29 #include "core/rendering/svg/SVGRenderSupport.h" 30 #include "core/svg/SVGFontData.h" 31 #include "core/svg/SVGFontElement.h" 32 #include "core/svg/SVGFontFaceElement.h" 33 #include "core/svg/SVGGlyphElement.h" 34 #include "platform/fonts/GlyphBuffer.h" 35 #include "platform/fonts/WidthIterator.h" 36 #include "platform/graphics/GraphicsContext.h" 37 38 namespace blink { 39 40 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font) 41 { 42 ASSERT(fontData); 43 ASSERT(fontData->isCustomFont()); 44 ASSERT(fontData->isSVGFont()); 45 46 RefPtr<CustomFontData> customFontData = fontData->customFontData(); 47 const SVGFontData* svgFontData = toSVGFontData(customFontData); 48 49 // FIXME crbug.com/359380 : The current editing impl references the font after the svg font nodes are removed. 50 if (svgFontData->shouldSkipDrawing()) 51 return 0; 52 53 fontFace = svgFontData->svgFontFaceElement(); 54 ASSERT(fontFace); 55 56 font = fontFace->associatedFontElement(); 57 return svgFontData; 58 } 59 60 static inline RenderObject* firstParentRendererForNonTextNode(RenderObject* renderer) 61 { 62 ASSERT(renderer); 63 return renderer->isText() ? renderer->parent() : renderer; 64 } 65 66 static inline RenderObject* renderObjectFromRun(const TextRun& run) 67 { 68 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) 69 return static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); 70 return 0; 71 } 72 73 float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, Glyph& glyphId) const 74 { 75 WidthIterator it(&font, run); 76 GlyphBuffer glyphBuffer; 77 charsConsumed += it.advance(run.length(), &glyphBuffer); 78 glyphId = !glyphBuffer.isEmpty() ? glyphBuffer.glyphAt(0) : 0; 79 return it.runWidthSoFar(); 80 } 81 82 void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const 83 { 84 SVGFontElement* fontElement = 0; 85 SVGFontFaceElement* fontFaceElement = 0; 86 87 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); 88 if (!fontElement || !fontFaceElement) 89 return; 90 91 // We can only paint SVGFonts if a context is available. 92 RenderObject* renderObject = renderObjectFromRun(run); 93 ASSERT(renderObject); 94 95 bool isVerticalText = false; 96 if (RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject)) { 97 RenderStyle* parentRenderObjectStyle = parentRenderObject->style(); 98 ASSERT(parentRenderObjectStyle); 99 isVerticalText = parentRenderObjectStyle->svgStyle().isVerticalWritingMode(); 100 } 101 102 float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); 103 104 FloatPoint glyphOrigin; 105 glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); 106 glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); 107 108 unsigned short resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; 109 110 FloatPoint currentPoint = point; 111 for (int i = 0; i < numGlyphs; ++i) { 112 Glyph glyph = glyphBuffer.glyphAt(from + i); 113 if (!glyph) 114 continue; 115 116 float advance = glyphBuffer.advanceAt(from + i).width(); 117 SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); 118 ASSERT(!svgGlyph.isPartOfLigature); 119 ASSERT(svgGlyph.tableEntry == glyph); 120 121 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); 122 123 // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). 124 if (svgGlyph.pathData.isEmpty()) { 125 if (isVerticalText) 126 currentPoint.move(0, advance); 127 else 128 currentPoint.move(advance, 0); 129 continue; 130 } 131 132 if (isVerticalText) { 133 glyphOrigin.setX(svgGlyph.verticalOriginX * scale); 134 glyphOrigin.setY(svgGlyph.verticalOriginY * scale); 135 } 136 137 AffineTransform glyphPathTransform; 138 glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); 139 glyphPathTransform.scale(scale, -scale); 140 141 Path glyphPath = svgGlyph.pathData; 142 glyphPath.transform(glyphPathTransform); 143 144 SVGRenderSupport::fillOrStrokePath(context, resourceMode, glyphPath); 145 146 if (isVerticalText) 147 currentPoint.move(0, advance); 148 else 149 currentPoint.move(advance, 0); 150 } 151 } 152 153 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, const TextRun& run, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) 154 { 155 const SimpleFontData* primaryFont = font.primaryFont(); 156 ASSERT(primaryFont); 157 158 pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror); 159 GlyphData glyphData = pair.first; 160 161 // Check if we have the missing glyph data, in which case we can just return. 162 GlyphData missingGlyphData = primaryFont->missingGlyphData(); 163 if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missingGlyphData.fontData) { 164 ASSERT(glyphData.fontData); 165 return glyphData; 166 } 167 168 // Save data fromt he font fallback list because we may modify it later. Do this before the 169 // potential change to glyphData.fontData below. 170 FontFallbackList* fontList = font.fontList(); 171 ASSERT(fontList); 172 FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList); 173 174 // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage. 175 const SimpleFontData* originalFontData = glyphData.fontData; 176 if (originalFontData && !originalFontData->isSVGFont()) { 177 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) { 178 RenderObject* renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); 179 RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; 180 ASSERT(parentRenderObject); 181 if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { 182 if (isSVGAltGlyphElement(*parentRenderObjectElement)) 183 glyphData.fontData = primaryFont; 184 } 185 } 186 } 187 188 const SimpleFontData* fontData = glyphData.fontData; 189 if (fontData) { 190 if (!fontData->isSVGFont()) 191 return glyphData; 192 193 SVGFontElement* fontElement = 0; 194 SVGFontFaceElement* fontFaceElement = 0; 195 196 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); 197 if (!fontElement || !fontFaceElement) 198 return glyphData; 199 200 // If we got here, we're dealing with a glyph defined in a SVG Font. 201 // The returned glyph by glyphDataAndPageForCharacter() is a glyph stored in the SVG Font glyph table. 202 // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its 203 // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that. 204 if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength)) 205 return glyphData; 206 } 207 208 GlyphPage* page = pair.second; 209 ASSERT(page); 210 211 // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.) 212 // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily 213 // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly. 214 page->setGlyphDataForCharacter(character, 0, 0); 215 216 // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before. 217 GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror); 218 ASSERT(fallbackGlyphData.fontData != fontData); 219 220 // Restore original state of the SVG Font glyph table and the current font fallback list, 221 // to assure the next lookup of the same glyph won't immediately return the fallback glyph. 222 page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData); 223 ASSERT(fallbackGlyphData.fontData); 224 return fallbackGlyphData; 225 } 226 227 } 228 229 #endif 230