/* * Copyright (C) 2007 Nikolas Zimmermann * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * 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. * */ #ifndef SVGTextChunkLayoutInfo_h #define SVGTextChunkLayoutInfo_h #if ENABLE(SVG) #include "AffineTransform.h" #include "SVGCharacterData.h" #include "SVGRenderStyle.h" #include "SVGTextContentElement.h" #include #include namespace WebCore { class InlineBox; class InlineFlowBox; class SVGInlineTextBox; // A SVGTextChunk directly corresponds to the definition of a "text chunk" per SVG 1.1 specification // For example, each absolute positioned character starts a text chunk (much more to respect, see spec). // Each SVGTextChunk contains a Vector of SVGInlineBoxCharacterRange, describing how many boxes are spanned // by this chunk. Following two examples should clarify the code a bit: // // 1. ABC - one InlineTextBox is created, three SVGTextChunks each with one SVGInlineBoxCharaterRange // [SVGTextChunk 1] // [SVGInlineBoxCharacterRange 1, startOffset=0, endOffset=1, box=0x1] // [SVGTextChunk 2] // [SVGInlineBoxCharacterRange 1, startOffset=1, endOffset=2, box=0x1] // [SVGTextChunk 3] // [SVGInlineBoxCharacterRange 1, startOffset=2, endOffset=3, box=0x1] // // 2. ABC - three InlineTextBoxs are created, one SVGTextChunk, with three SVGInlineBoxCharacterRanges // [SVGTextChunk 1] // [SVGInlineBoxCharacterRange 1, startOffset=0, endOffset=1, box=0x1] // [SVGInlineBoxCharacterRange 2, startOffset=0, endOffset=1, box=0x2] // [SVGInlineBoxCharacterRange 3, startOffset=0, endOffset=1, box=0x3] // // High level overview of the SVG text layout code: // Step #1) - Build Vector of SVGChar objects starting from root diving into children // Step #2) - Build Vector of SVGTextChunk objects, containing offsets into the InlineTextBoxes and SVGChar vectors // Step #3) - Apply chunk post processing (text-anchor / textLength support, which operate on text chunks!) // Step #4) - Propagate information, how many chunk "parts" are associated with each SVGInlineTextBox (see below) // Step #5) - Layout all InlineBoxes, only by measuring their context rect (x/y/width/height defined through SVGChars and transformations) // Step #6) - Layout SVGRootInlineBox, it's parent RenderSVGText block and fixup child positions, to be relative to the root box // // When painting a range of characters, we have to determine how many can be drawn in a row. Each absolute postioned // character is drawn individually. After step #2) we know all text chunks, and how they span across the SVGInlineTextBoxes. // In step #4) we build a list of text chunk "parts" and store it in each SVGInlineTextBox. A chunk "part" is a part of a // text chunk that lives in a SVGInlineTextBox (consists of a length, width, height and a monotonic offset from the chunk begin) // The SVGTextChunkPart object describes this information. // When painting we can follow the regular InlineBox flow, we start painting the SVGRootInlineBox, which just asks its children // to paint. They can paint on their own because all position information are known. Previously we used to draw _all_ characters // from the SVGRootInlineBox, which violates the whole concept of the multiple InlineBoxes, and made text selection very hard to // implement. struct SVGTextChunkPart { SVGTextChunkPart() : offset(-1) , length(-1) , width(0) , height(0) { } bool isValid() const { return offset != -1 && length != -1 && width && height; } // First character of this text chunk part, defining the origin to be drawn Vector::const_iterator firstCharacter; // Start offset in textRenderer()->characters() buffer. int offset; // length/width/height of chunk part int length; float width; float height; }; struct SVGInlineBoxCharacterRange { SVGInlineBoxCharacterRange() : startOffset(INT_MIN) , endOffset(INT_MIN) , box(0) { } bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); } bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; } int startOffset; int endOffset; InlineBox* box; }; struct SVGChar; // Convenience typedef typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust; struct SVGTextChunk { SVGTextChunk(Vector::iterator it) : anchor(TA_START) , textLength(0.0f) , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING) , isVerticalText(false) , isTextPath(false) , start(it) , end(it) { } // text-anchor support ETextAnchor anchor; // textLength & lengthAdjust support float textLength; ELengthAdjust lengthAdjust; AffineTransform ctm; // status flags bool isVerticalText : 1; bool isTextPath : 1; // main chunk data Vector::iterator start; Vector::iterator end; Vector boxes; }; struct SVGTextChunkLayoutInfo { SVGTextChunkLayoutInfo() : m_assignChunkProperties(true) , m_handlingTextPath(false) , m_charsIt(0) , m_charsBegin(0) , m_charsEnd(0) , m_chunk(0) { } const Vector& textChunks() const { return m_svgTextChunks; } void buildTextChunks(Vector::iterator charsBegin, Vector::iterator charsEnd, InlineFlowBox* start); void layoutTextChunks(); private: void startTextChunk(); void closeTextChunk(); void recursiveBuildTextChunks(InlineFlowBox* start); bool m_assignChunkProperties : 1; bool m_handlingTextPath : 1; Vector::iterator m_charsIt; Vector::iterator m_charsBegin; Vector::iterator m_charsEnd; Vector m_svgTextChunks; SVGTextChunk m_chunk; }; // Helper functions float calculateTextAnchorShiftForTextChunk(SVGTextChunk&, ETextAnchor); float calculateTextLengthCorrectionForTextChunk(SVGTextChunk&, ELengthAdjust, float& computedLength); } // namespace WebCore #endif // ENABLE(SVG) #endif // SVGTextChunkLayoutInfo_h