diff -r 000000000000 -r 4f2f89ce4247 WebCore/rendering/SVGTextChunkLayoutInfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/rendering/SVGTextChunkLayoutInfo.h Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,198 @@ +/* + * 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