WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Initial patch
SVGTextPrepare.patch (text/plain), 50.58 KB, created by
Nikolas Zimmermann
on 2010-06-16 07:06:01 PDT
(
hide
)
Description:
Initial patch
Filename:
MIME Type:
Creator:
Nikolas Zimmermann
Created:
2010-06-16 07:06:01 PDT
Size:
50.58 KB
patch
obsolete
>Index: WebCore/ChangeLog >=================================================================== >--- WebCore/ChangeLog (revision 61253) >+++ WebCore/ChangeLog (working copy) >@@ -1,3 +1,70 @@ >+2010-06-16 Nikolas Zimmermann <nzimmermann@rim.com> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add new files, needed in SVG Text rewrite >+ https://bugs.webkit.org/show_bug.cgi?id=40676 >+ >+ Land SVGTextChunkLayoutInfo.cpp and SVGTextQuery.(cpp|h), both with an "#if 0" on top, as they will be needed >+ in a later patch, completing the SVG Text rewrite, that will enable them. >+ >+ Doesn't affect any code for now, it should just reduce the review amount. >+ >+ * Android.mk: >+ * CMakeLists.txt: >+ * GNUmakefile.am: >+ * WebCore.gypi: >+ * WebCore.pro: >+ * WebCore.vcproj/WebCore.vcproj: >+ * WebCore.xcodeproj/project.pbxproj: >+ * rendering/SVGTextChunkLayoutInfo.cpp: Added. >+ (WebCore::cummulatedWidthOrHeightOfTextChunk): >+ (WebCore::cummulatedWidthOfTextChunk): >+ (WebCore::cummulatedHeightOfTextChunk): >+ (WebCore::calculateTextAnchorShiftForTextChunk): >+ (WebCore::applyTextAnchorToTextChunk): >+ (WebCore::calculateTextLengthCorrectionForTextChunk): >+ (WebCore::applyTextLengthCorrectionToTextChunk): >+ (WebCore::SVGTextChunkLayoutInfo::startTextChunk): >+ (WebCore::SVGTextChunkLayoutInfo::closeTextChunk): >+ (WebCore::SVGTextChunkLayoutInfo::buildTextChunks): >+ (WebCore::SVGTextChunkLayoutInfo::recursiveBuildTextChunks): >+ (WebCore::SVGTextChunkLayoutInfo::layoutTextChunks): >+ * rendering/SVGTextQuery.cpp: Added. >+ (WebCore::SVGTextQuery::Data::Data): >+ (WebCore::flowBoxForRenderer): >+ (WebCore::mapLengthThroughChunkTransformation): >+ (WebCore::SVGTextQuery::SVGTextQuery): >+ (WebCore::SVGTextQuery::collectTextBoxesInFlowBox): >+ (WebCore::SVGTextQuery::executeQuery): >+ (WebCore::SVGTextQuery::mapStartAndLengthIntoChunkPartCoordinates): >+ (WebCore::SVGTextQuery::measureCharacterRange): >+ (WebCore::NumberOfCharactersData::NumberOfCharactersData): >+ (WebCore::SVGTextQuery::numberOfCharactersCallback): >+ (WebCore::SVGTextQuery::numberOfCharacters): >+ (WebCore::TextLengthData::TextLengthData): >+ (WebCore::SVGTextQuery::textLengthCallback): >+ (WebCore::SVGTextQuery::textLength): >+ (WebCore::SubStringLengthData::SubStringLengthData): >+ (WebCore::SVGTextQuery::subStringLengthCallback): >+ (WebCore::SVGTextQuery::subStringLength): >+ (WebCore::StartPositionOfCharacterData::StartPositionOfCharacterData): >+ (WebCore::SVGTextQuery::startPositionOfCharacterCallback): >+ (WebCore::SVGTextQuery::startPositionOfCharacter): >+ (WebCore::EndPositionOfCharacterData::EndPositionOfCharacterData): >+ (WebCore::SVGTextQuery::endPositionOfCharacterCallback): >+ (WebCore::SVGTextQuery::endPositionOfCharacter): >+ (WebCore::RotationOfCharacterData::RotationOfCharacterData): >+ (WebCore::SVGTextQuery::rotationOfCharacterCallback): >+ (WebCore::SVGTextQuery::rotationOfCharacter): >+ (WebCore::ExtentOfCharacterData::ExtentOfCharacterData): >+ (WebCore::SVGTextQuery::extentOfCharacterCallback): >+ (WebCore::SVGTextQuery::extentOfCharacter): >+ (WebCore::CharacterNumberAtPositionData::CharacterNumberAtPositionData): >+ (WebCore::SVGTextQuery::characterNumberAtPositionCallback): >+ (WebCore::SVGTextQuery::characterNumberAtPosition): >+ * rendering/SVGTextQuery.h: Added. >+ > 2010-06-16 Nikolas Zimmermann <nzimmermann@rim.com> > > Reviewed by Dirk Schulze. >Index: WebCore/Android.mk >=================================================================== >--- WebCore/Android.mk (revision 61253) >+++ WebCore/Android.mk (working copy) >@@ -669,7 +669,9 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ > rendering/SVGRenderTreeAsText.cpp \ > rendering/SVGRootInlineBox.cpp \ > rendering/SVGShadowTreeElements.cpp \ >- rendering/SVGTextLayoutUtilities.cpp >+ rendering/SVGTextChunkLayoutInfo.cpp \ >+ rendering/SVGTextLayoutUtilities.cpp \ >+ rendering/SVGTextQuery.cpp > endif > > LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ >Index: WebCore/CMakeLists.txt >=================================================================== >--- WebCore/CMakeLists.txt (revision 61253) >+++ WebCore/CMakeLists.txt (working copy) >@@ -1498,7 +1498,9 @@ IF (ENABLE_SVG) > rendering/SVGRenderTreeAsText.cpp > rendering/SVGRootInlineBox.cpp > rendering/SVGShadowTreeElements.cpp >+ rendering/SVGTextChunkLayoutInfo.cpp > rendering/SVGTextLayoutUtilities.cpp >+ rendering/SVGTextQuery.cpp > rendering/style/SVGRenderStyle.cpp > rendering/style/SVGRenderStyleDefs.cpp > svg/ColorDistance.cpp >Index: WebCore/GNUmakefile.am >=================================================================== >--- WebCore/GNUmakefile.am (revision 61253) >+++ WebCore/GNUmakefile.am (working copy) >@@ -3331,9 +3331,12 @@ webcore_sources += \ > WebCore/rendering/SVGRootInlineBox.h \ > WebCore/rendering/SVGShadowTreeElements.cpp \ > WebCore/rendering/SVGShadowTreeElements.h \ >+ WebCore/rendering/SVGTextChunkLayoutInfo.cpp \ > WebCore/rendering/SVGTextChunkLayoutInfo.h \ > WebCore/rendering/SVGTextLayoutUtilities.cpp \ > WebCore/rendering/SVGTextLayoutUtilities.h \ >+ WebCore/rendering/SVGTextQuery.cpp \ >+ WebCore/rendering/SVGTextQuery.h \ > WebCore/rendering/style/SVGRenderStyle.cpp \ > WebCore/rendering/style/SVGRenderStyle.h \ > WebCore/rendering/style/SVGRenderStyleDefs.cpp \ >Index: WebCore/WebCore.gypi >=================================================================== >--- WebCore/WebCore.gypi (revision 61253) >+++ WebCore/WebCore.gypi (working copy) >@@ -3330,9 +3330,12 @@ > 'rendering/SVGRootInlineBox.h', > 'rendering/SVGShadowTreeElements.cpp', > 'rendering/SVGShadowTreeElements.h', >+ 'rendering/SVGTextChunkLayoutInfo.cpp', > 'rendering/SVGTextChunkLayoutInfo.h', > 'rendering/SVGTextLayoutUtilities.cpp', > 'rendering/SVGTextLayoutUtilities.h', >+ 'rendering/SVGTextQuery.cpp', >+ 'rendering/SVGTextQuery.h', > 'rendering/TableLayout.h', > 'rendering/TextControlInnerElements.cpp', > 'rendering/TextControlInnerElements.h', >Index: WebCore/WebCore.pro >=================================================================== >--- WebCore/WebCore.pro (revision 61253) >+++ WebCore/WebCore.pro (working copy) >@@ -1838,6 +1838,7 @@ HEADERS += \ > rendering/SVGShadowTreeElements.h \ > rendering/SVGTextChunkLayoutInfo.h \ > rendering/SVGTextLayoutUtilities.h \ >+ rendering/SVGTextQuery.h \ > rendering/TextControlInnerElements.h \ > rendering/TransformState.h \ > svg/animation/SMILTimeContainer.h \ >@@ -2845,7 +2846,9 @@ contains(DEFINES, ENABLE_SVG=1) { > rendering/SVGRenderSupport.cpp \ > rendering/SVGRootInlineBox.cpp \ > rendering/SVGShadowTreeElements.cpp \ >- rendering/SVGTextLayoutUtilities.cpp >+ rendering/SVGTextChunkLayoutInfo.cpp \ >+ rendering/SVGTextLayoutUtilities.cpp \ >+ rendering/SVGTextQuery.cpp > } > > contains(DEFINES, ENABLE_JAVASCRIPT_DEBUGGER=1) { >Index: WebCore/WebCore.vcproj/WebCore.vcproj >=================================================================== >--- WebCore/WebCore.vcproj/WebCore.vcproj (revision 61253) >+++ WebCore/WebCore.vcproj/WebCore.vcproj (working copy) >@@ -28939,6 +28939,10 @@ > > > </File> > <File >+ RelativePath="..\rendering\SVGTextChunkLayoutInfo.cpp" >+ > >+ </File> >+ <File > RelativePath="..\rendering\SVGTextChunkLayoutInfo.h" > > > </File> >@@ -28950,6 +28954,14 @@ > RelativePath="..\rendering\SVGTextLayoutUtilities.h" > > > </File> >+ <File >+ RelativePath="..\rendering\SVGTextQuery.cpp" >+ > >+ </File> >+ <File >+ RelativePath="..\rendering\SVGTextQuery.h" >+ > >+ </File> > <File > RelativePath="..\rendering\TableLayout.h" > > >Index: WebCore/WebCore.xcodeproj/project.pbxproj >=================================================================== >--- WebCore/WebCore.xcodeproj/project.pbxproj (revision 61253) >+++ WebCore/WebCore.xcodeproj/project.pbxproj (working copy) >@@ -90,6 +90,9 @@ > 084D2834110A7FCB0038239A /* SVGAnimatedPropertyTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 084D2832110A7FCB0038239A /* SVGAnimatedPropertyTraits.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 084DBAA10ED39D360038C226 /* WMLVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 084DBA9D0ED39D350038C226 /* WMLVariables.cpp */; }; > 084DBAA20ED39D360038C226 /* WMLVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = 084DBA9E0ED39D360038C226 /* WMLVariables.h */; }; >+ 0853D73211C9109000B2FD42 /* SVGTextChunkLayoutInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0853D72F11C9108F00B2FD42 /* SVGTextChunkLayoutInfo.cpp */; }; >+ 0853D73311C9109000B2FD42 /* SVGTextQuery.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0853D73011C9109000B2FD42 /* SVGTextQuery.cpp */; }; >+ 0853D73411C9109000B2FD42 /* SVGTextQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = 0853D73111C9109000B2FD42 /* SVGTextQuery.h */; }; > 08563BB4117861780012B578 /* RenderSVGResourcePattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08563BB2117861770012B578 /* RenderSVGResourcePattern.cpp */; }; > 08563BB5117861780012B578 /* RenderSVGResourcePattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 08563BB3117861770012B578 /* RenderSVGResourcePattern.h */; }; > 08563BD0117865F50012B578 /* RenderSVGResource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 08563BCF117865F50012B578 /* RenderSVGResource.cpp */; }; >@@ -5605,6 +5608,9 @@ > 084D2832110A7FCB0038239A /* SVGAnimatedPropertyTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedPropertyTraits.h; sourceTree = "<group>"; }; > 084DBA9D0ED39D350038C226 /* WMLVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WMLVariables.cpp; sourceTree = "<group>"; }; > 084DBA9E0ED39D360038C226 /* WMLVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WMLVariables.h; sourceTree = "<group>"; }; >+ 0853D72F11C9108F00B2FD42 /* SVGTextChunkLayoutInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGTextChunkLayoutInfo.cpp; sourceTree = "<group>"; }; >+ 0853D73011C9109000B2FD42 /* SVGTextQuery.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGTextQuery.cpp; sourceTree = "<group>"; }; >+ 0853D73111C9109000B2FD42 /* SVGTextQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGTextQuery.h; sourceTree = "<group>"; }; > 08563BB2117861770012B578 /* RenderSVGResourcePattern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGResourcePattern.cpp; sourceTree = "<group>"; }; > 08563BB3117861770012B578 /* RenderSVGResourcePattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGResourcePattern.h; sourceTree = "<group>"; }; > 08563BCF117865F50012B578 /* RenderSVGResource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGResource.cpp; sourceTree = "<group>"; }; >@@ -16506,9 +16512,12 @@ > 853CA9E50AEEC608002372DC /* SVGRootInlineBox.h */, > 08DAB9C01103D9C1003E7ABA /* SVGShadowTreeElements.cpp */, > 08DAB9C11103D9C1003E7ABA /* SVGShadowTreeElements.h */, >+ 0853D72F11C9108F00B2FD42 /* SVGTextChunkLayoutInfo.cpp */, > 0842BC801190147200C7D08F /* SVGTextChunkLayoutInfo.h */, > 083F529711957FBE00653EBE /* SVGTextLayoutUtilities.cpp */, > 083F529811957FBE00653EBE /* SVGTextLayoutUtilities.h */, >+ 0853D73011C9109000B2FD42 /* SVGTextQuery.cpp */, >+ 0853D73111C9109000B2FD42 /* SVGTextQuery.h */, > A8CFF04C0A154F09000A4234 /* TableLayout.h */, > AB014DE10E689A4300E10445 /* TextControlInnerElements.cpp */, > AB014DE20E689A4300E10445 /* TextControlInnerElements.h */, >@@ -19415,6 +19424,7 @@ > B6B0540A11B68F10002564C5 /* IDBObjectStoreImpl.h in Headers */, > 816C806911BE887E009A45E9 /* IDBKeyRange.h in Headers */, > 816C80AF11BE990D009A45E9 /* JSIDBKeyRange.h in Headers */, >+ 0853D73411C9109000B2FD42 /* SVGTextQuery.h in Headers */, > ); > runOnlyForDeploymentPostprocessing = 0; > }; >@@ -21720,6 +21730,8 @@ > B6B0540911B68F10002564C5 /* IDBObjectStoreImpl.cpp in Sources */, > 816C806811BE887E009A45E9 /* IDBKeyRange.cpp in Sources */, > 816C80B111BE9934009A45E9 /* JSIDBKeyRange.cpp in Sources */, >+ 0853D73211C9109000B2FD42 /* SVGTextChunkLayoutInfo.cpp in Sources */, >+ 0853D73311C9109000B2FD42 /* SVGTextQuery.cpp in Sources */, > ); > runOnlyForDeploymentPostprocessing = 0; > }; >Index: WebCore/rendering/SVGTextChunkLayoutInfo.cpp >=================================================================== >--- WebCore/rendering/SVGTextChunkLayoutInfo.cpp (revision 0) >+++ WebCore/rendering/SVGTextChunkLayoutInfo.cpp (revision 0) >@@ -0,0 +1,495 @@ >+/* >+ * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> >+ * 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. >+ * >+ */ >+ >+#include "config.h" >+#include "SVGTextChunkLayoutInfo.h" >+ >+// FIXME: This code is currently deactivated, until the SVG Text rewrite patch lands. >+#if ENABLE(SVG) && 0 >+#include "InlineFlowBox.h" >+#include "SVGInlineTextBox.h" >+#include "SVGRenderStyle.h" >+ >+// Text chunk creation is complex and the whole process >+// can easily be traced by setting this variable > 0. >+#define DEBUG_CHUNK_BUILDING 0 >+ >+namespace WebCore { >+ >+static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWidthOnly) >+{ >+ float length = 0.0f; >+ Vector<SVGChar>::iterator charIt = chunk.start; >+ >+ Vector<SVGInlineBoxCharacterRange>::iterator it = chunk.boxes.begin(); >+ Vector<SVGInlineBoxCharacterRange>::iterator end = chunk.boxes.end(); >+ >+ for (; it != end; ++it) { >+ SVGInlineBoxCharacterRange& range = *it; >+ >+ SVGInlineTextBox* box = static_cast<SVGInlineTextBox*>(range.box); >+ RenderStyle* style = box->renderer()->style(); >+ >+ for (int i = range.startOffset; i < range.endOffset; ++i) { >+ ASSERT(charIt <= chunk.end); >+ >+ // Determine how many characters - starting from the current - can be measured at once. >+ // Important for non-absolute positioned non-latin1 text (ie. Arabic) where ie. the width >+ // of a string is not the sum of the boundaries of all contained glyphs. >+ Vector<SVGChar>::iterator itSearch = charIt + 1; >+ Vector<SVGChar>::iterator endSearch = charIt + range.endOffset - i; >+ while (itSearch != endSearch) { >+ // No need to check for 'isHidden()' here as this function is not called for text paths. >+ if (itSearch->drawnSeperated) >+ break; >+ >+ itSearch++; >+ } >+ >+ unsigned int positionOffset = itSearch - charIt; >+ >+ // Calculate width/height of subrange >+ SVGInlineBoxCharacterRange subRange; >+ subRange.box = range.box; >+ subRange.startOffset = i; >+ subRange.endOffset = i + positionOffset; >+ >+ if (calcWidthOnly) >+ length += cummulatedWidthOfInlineBoxCharacterRange(subRange); >+ else >+ length += cummulatedHeightOfInlineBoxCharacterRange(subRange); >+ >+ // Calculate gap between the previous & current range >+ // <text x="10 50 70">ABCD</text> - we need to take the gaps between A & B into account >+ // so add "40" as width, and analogous for B & C, add "20" as width. >+ if (itSearch > chunk.start && itSearch < chunk.end) { >+ SVGChar& lastCharacter = *(itSearch - 1); >+ SVGChar& currentCharacter = *itSearch; >+ >+ int charsConsumed = 0; >+ float glyphWidth = 0.0f; >+ float glyphHeight = 0.0f; >+ String glyphName; >+ String unicodeString; >+ box->measureCharacter(style, i + positionOffset - 1, charsConsumed, glyphName, unicodeString, glyphWidth, glyphHeight); >+ >+ if (calcWidthOnly) >+ length += currentCharacter.x - lastCharacter.x - glyphWidth; >+ else >+ length += currentCharacter.y - lastCharacter.y - glyphHeight; >+ } >+ >+ // Advance processed characters >+ i += positionOffset - 1; >+ charIt = itSearch; >+ } >+ } >+ >+ ASSERT(charIt == chunk.end); >+ return length; >+} >+ >+static float cummulatedWidthOfTextChunk(SVGTextChunk& chunk) >+{ >+ return cummulatedWidthOrHeightOfTextChunk(chunk, true); >+} >+ >+static float cummulatedHeightOfTextChunk(SVGTextChunk& chunk) >+{ >+ return cummulatedWidthOrHeightOfTextChunk(chunk, false); >+} >+ >+float calculateTextAnchorShiftForTextChunk(SVGTextChunk& chunk, ETextAnchor anchor) >+{ >+ float shift = 0.0f; >+ >+ if (chunk.isVerticalText) >+ shift = cummulatedHeightOfTextChunk(chunk); >+ else >+ shift = cummulatedWidthOfTextChunk(chunk); >+ >+ if (anchor == TA_MIDDLE) >+ shift *= -0.5f; >+ else >+ shift *= -1.0f; >+ >+ return shift; >+} >+ >+static void applyTextAnchorToTextChunk(SVGTextChunk& chunk) >+{ >+ // This method is not called for chunks containing chars aligned on a path. >+ // -> all characters are visible, no need to check for "isHidden()" anywhere. >+ >+ if (chunk.anchor == TA_START) >+ return; >+ >+ float shift = calculateTextAnchorShiftForTextChunk(chunk, chunk.anchor); >+ >+ // Apply correction to chunk >+ Vector<SVGChar>::iterator chunkIt = chunk.start; >+ for (; chunkIt != chunk.end; ++chunkIt) { >+ SVGChar& curChar = *chunkIt; >+ >+ if (chunk.isVerticalText) >+ curChar.y += shift; >+ else >+ curChar.x += shift; >+ } >+ >+ // Move inline boxes >+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin(); >+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end(); >+ >+ for (; boxIt != boxEnd; ++boxIt) { >+ SVGInlineBoxCharacterRange& range = *boxIt; >+ >+ InlineBox* curBox = range.box; >+ ASSERT(curBox->isSVGInlineTextBox()); >+ >+ // Move target box >+ if (chunk.isVerticalText) >+ curBox->setY(curBox->y() + static_cast<int>(shift)); >+ else >+ curBox->setX(curBox->x() + static_cast<int>(shift)); >+ } >+} >+ >+float calculateTextLengthCorrectionForTextChunk(SVGTextChunk& chunk, ELengthAdjust lengthAdjust, float& computedLength) >+{ >+ if (chunk.textLength <= 0.0f) >+ return 0.0f; >+ >+ computedLength = 0.0f; >+ >+ float computedWidth = cummulatedWidthOfTextChunk(chunk); >+ float computedHeight = cummulatedHeightOfTextChunk(chunk); >+ if ((computedWidth <= 0.0f && !chunk.isVerticalText) >+ || (computedHeight <= 0.0f && chunk.isVerticalText)) >+ return 0.0f; >+ >+ computedLength = chunk.isVerticalText ? computedHeight : computedWidth; >+ if (lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) { >+ if (chunk.isVerticalText) >+ chunk.ctm.scaleNonUniform(1.0f, chunk.textLength / computedLength); >+ else >+ chunk.ctm.scaleNonUniform(chunk.textLength / computedLength, 1.0f); >+ >+ return 0.0f; >+ } >+ >+ return (chunk.textLength - computedLength) / float(chunk.end - chunk.start); >+} >+ >+static void applyTextLengthCorrectionToTextChunk(SVGTextChunk& chunk) >+{ >+ // This method is not called for chunks containing chars aligned on a path. >+ // -> all characters are visible, no need to check for "isHidden()" anywhere. >+ >+ // lengthAdjust="spacingAndGlyphs" is handled by setting a scale factor for the whole chunk >+ float textLength = 0.0f; >+ float spacingToApply = calculateTextLengthCorrectionForTextChunk(chunk, chunk.lengthAdjust, textLength); >+ >+ if (!chunk.ctm.isIdentity() && chunk.lengthAdjust == SVGTextContentElement::LENGTHADJUST_SPACINGANDGLYPHS) { >+ SVGChar& firstChar = *(chunk.start); >+ >+ // Assure we apply the chunk scaling in the right origin >+ AffineTransform newChunkCtm(chunk.ctm); >+ newChunkCtm.translateRight(firstChar.x, firstChar.y); >+ newChunkCtm.translate(-firstChar.x, -firstChar.y); >+ >+ chunk.ctm = newChunkCtm; >+ } >+ >+ // Apply correction to chunk >+ if (spacingToApply != 0.0f) { >+ Vector<SVGChar>::iterator chunkIt = chunk.start; >+ for (; chunkIt != chunk.end; ++chunkIt) { >+ SVGChar& curChar = *chunkIt; >+ curChar.drawnSeperated = true; >+ >+ if (chunk.isVerticalText) >+ curChar.y += (chunkIt - chunk.start) * spacingToApply; >+ else >+ curChar.x += (chunkIt - chunk.start) * spacingToApply; >+ } >+ } >+} >+ >+void SVGTextChunkLayoutInfo::startTextChunk() >+{ >+ m_chunk.boxes.clear(); >+ m_chunk.boxes.append(SVGInlineBoxCharacterRange()); >+ >+ m_chunk.start = m_charsIt; >+ m_assignChunkProperties = true; >+} >+ >+void SVGTextChunkLayoutInfo::closeTextChunk() >+{ >+ ASSERT(!m_chunk.boxes.last().isOpen()); >+ ASSERT(m_chunk.boxes.last().isClosed()); >+ >+ m_chunk.end = m_charsIt; >+ ASSERT(m_chunk.end >= m_chunk.start); >+ >+ m_svgTextChunks.append(m_chunk); >+} >+ >+void SVGTextChunkLayoutInfo::buildTextChunks(Vector<SVGChar>::iterator begin, Vector<SVGChar>::iterator end, InlineFlowBox* start) >+{ >+ m_charsBegin = begin; >+ m_charsEnd = end; >+ >+ m_charsIt = begin; >+ m_chunk = SVGTextChunk(begin); >+ >+ recursiveBuildTextChunks(start); >+ ASSERT(m_charsIt == m_charsEnd); >+} >+ >+void SVGTextChunkLayoutInfo::recursiveBuildTextChunks(InlineFlowBox* start) >+{ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> buildTextChunks(start=%p)\n", start); >+#endif >+ >+ for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { >+ if (curr->renderer()->isText()) { >+ InlineTextBox* textBox = static_cast<InlineTextBox*>(curr); >+ >+ unsigned length = textBox->len(); >+ if (!length) >+ continue; >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Handle inline text box (%p) with %i characters (start: %i, end: %i), handlingTextPath=%i\n", >+ textBox, length, textBox->start(), textBox->end(), (int) m_handlingTextPath); >+#endif >+ >+ RenderText* text = textBox->textRenderer(); >+ ASSERT(text); >+ ASSERT(text->node()); >+ >+ SVGTextContentElement* textContent = 0; >+ Node* node = text->node()->parent(); >+ while (node && node->isSVGElement() && !textContent) { >+ if (static_cast<SVGElement*>(node)->isTextContent()) >+ textContent = static_cast<SVGTextContentElement*>(node); >+ else >+ node = node->parentNode(); >+ } >+ ASSERT(textContent); >+ >+ // Start new character range for the first chunk >+ bool isFirstCharacter = m_svgTextChunks.isEmpty() && m_chunk.start == m_charsIt && m_chunk.start == m_chunk.end; >+ if (isFirstCharacter) { >+ ASSERT(m_chunk.boxes.isEmpty()); >+ m_chunk.boxes.append(SVGInlineBoxCharacterRange()); >+ } else >+ ASSERT(!m_chunk.boxes.isEmpty()); >+ >+ // Walk string to find out new chunk positions, if existent >+ for (unsigned i = 0; i < length; ++i) { >+ ASSERT(m_charsIt != m_charsEnd); >+ >+ SVGInlineBoxCharacterRange& range = m_chunk.boxes.last(); >+ if (range.isOpen()) { >+ range.box = curr; >+ range.startOffset = !i ? 0 : i - 1; >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset); >+#endif >+ } >+ >+ // If a new (or the first) chunk has been started, record it's text-anchor and writing mode. >+ if (m_assignChunkProperties) { >+ m_assignChunkProperties = false; >+ >+ m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); >+ m_chunk.isTextPath = m_handlingTextPath; >+ m_chunk.anchor = text->style()->svgStyle()->textAnchor(); >+ m_chunk.textLength = textContent->textLength().value(textContent); >+ m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " | -> Assign chunk properties, isVerticalText=%i, anchor=%i\n", m_chunk.isVerticalText, m_chunk.anchor); >+#endif >+ } >+ >+ if (i > 0 && !isFirstCharacter && m_charsIt->newTextChunk) { >+ // Close mid chunk & character range >+ ASSERT(!range.isOpen()); >+ ASSERT(!range.isClosed()); >+ >+ range.endOffset = i; >+ closeTextChunk(); >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " | -> Close mid-text chunk, at endOffset: %i and starting new mid chunk!\n", range.endOffset); >+#endif >+ >+ // Prepare for next chunk, if we're not at the end >+ startTextChunk(); >+ if (i + 1 == length) { >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " | -> Record last chunk of inline text box!\n"); >+#endif >+ >+ startTextChunk(); >+ SVGInlineBoxCharacterRange& range = m_chunk.boxes.last(); >+ >+ m_assignChunkProperties = false; >+ m_chunk.isVerticalText = isVerticalWritingMode(text->style()->svgStyle()); >+ m_chunk.isTextPath = m_handlingTextPath; >+ m_chunk.anchor = text->style()->svgStyle()->textAnchor(); >+ m_chunk.textLength = textContent->textLength().value(textContent); >+ m_chunk.lengthAdjust = (ELengthAdjust) textContent->lengthAdjust(); >+ >+ range.box = curr; >+ range.startOffset = i; >+ >+ ASSERT(!range.isOpen()); >+ ASSERT(!range.isClosed()); >+ } >+ } >+ >+ // This should only hold true for the first character of the first chunk >+ if (isFirstCharacter) >+ isFirstCharacter = false; >+ >+ ++m_charsIt; >+ } >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Finished inline text box!\n"); >+#endif >+ >+ SVGInlineBoxCharacterRange& range = m_chunk.boxes.last(); >+ if (!range.isOpen() && !range.isClosed()) { >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Last range not closed - closing with endOffset: %i\n", length); >+#endif >+ >+ // Current text chunk is not yet closed. Finish the current range, but don't start a new chunk. >+ range.endOffset = length; >+ >+ if (m_charsIt != m_charsEnd) { >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Not at last character yet!\n"); >+#endif >+ >+ // If we're not at the end of the last box to be processed, and if the next >+ // character starts a new chunk, then close the current chunk and start a new one. >+ if (m_charsIt->newTextChunk) { >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Next character starts new chunk! Closing current chunk, and starting a new one...\n"); >+#endif >+ >+ closeTextChunk(); >+ startTextChunk(); >+ } else { >+ // Just start a new character range >+ m_chunk.boxes.append(SVGInlineBoxCharacterRange()); >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Next character does NOT start a new chunk! Starting new character range...\n"); >+#endif >+ } >+ } else { >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Closing final chunk! Finished processing!\n"); >+#endif >+ >+ // Close final chunk, once we're at the end of the last box >+ closeTextChunk(); >+ } >+ } >+ } else { >+ ASSERT(curr->isInlineFlowBox()); >+ InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); >+ >+ // Skip generated content. >+ if (!flowBox->renderer()->node()) >+ continue; >+ >+ bool isTextPath = flowBox->renderer()->node()->hasTagName(SVGNames::textPathTag); >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " -> Handle inline flow box (%p), isTextPath=%i\n", flowBox, (int) isTextPath); >+#endif >+ >+ if (isTextPath) >+ m_handlingTextPath = true; >+ >+ recursiveBuildTextChunks(flowBox); >+ >+ if (isTextPath) >+ m_handlingTextPath = false; >+ } >+ } >+ >+#if DEBUG_CHUNK_BUILDING > 1 >+ fprintf(stderr, " <- buildTextChunks(start=%p)\n", start); >+#endif >+} >+ >+void SVGTextChunkLayoutInfo::layoutTextChunks() >+{ >+ Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin(); >+ Vector<SVGTextChunk>::iterator end = m_svgTextChunks.end(); >+ >+ for (; it != end; ++it) { >+ SVGTextChunk& chunk = *it; >+ >+#if DEBUG_CHUNK_BUILDING > 0 >+ { >+ fprintf(stderr, "Handle TEXT CHUNK! anchor=%i, textLength=%f, lengthAdjust=%i, isVerticalText=%i, isTextPath=%i start=%p, end=%p -> dist: %i\n", >+ (int) chunk.anchor, chunk.textLength, (int) chunk.lengthAdjust, (int) chunk.isVerticalText, >+ (int) chunk.isTextPath, chunk.start, chunk.end, (unsigned int) (chunk.end - chunk.start)); >+ >+ Vector<SVGInlineBoxCharacterRange>::iterator boxIt = chunk.boxes.begin(); >+ Vector<SVGInlineBoxCharacterRange>::iterator boxEnd = chunk.boxes.end(); >+ >+ unsigned int i = 0; >+ for (; boxIt != boxEnd; ++boxIt) { >+ SVGInlineBoxCharacterRange& range = *boxIt; >+ ++i; >+ fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box); >+ } >+ } >+#endif >+ >+ if (chunk.isTextPath) >+ continue; >+ >+ // text-path & textLength, with lengthAdjust="spacing" is already handled for textPath layouts. >+ applyTextLengthCorrectionToTextChunk(chunk); >+ >+ // text-anchor is already handled for textPath layouts. >+ applyTextAnchorToTextChunk(chunk); >+ } >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(SVG) >Index: WebCore/rendering/SVGTextQuery.cpp >=================================================================== >--- WebCore/rendering/SVGTextQuery.cpp (revision 0) >+++ WebCore/rendering/SVGTextQuery.cpp (revision 0) >@@ -0,0 +1,468 @@ >+/* >+ 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. >+*/ >+ >+#include "config.h" >+#include "SVGTextQuery.h" >+ >+// FIXME: This code is currently deactivated, until the SVG Text rewrite patch lands. >+#if ENABLE(SVG) && 0 >+#include "FloatConversion.h" >+#include "InlineFlowBox.h" >+#include "RenderBlock.h" >+#include "RenderInline.h" >+#include "SVGInlineTextBox.h" >+#include "VisiblePosition.h" >+ >+namespace WebCore { >+ >+// Base structure for callback user data >+struct SVGTextQuery::Data { >+ Data() >+ : processedChunkCharacters(0) >+ { >+ } >+ >+ unsigned processedChunkCharacters; >+}; >+ >+static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) >+{ >+ if (!renderer) >+ return 0; >+ >+ if (renderer->isRenderBlock()) { >+ // If we're given a block element, it has to be a RenderSVGText. >+ ASSERT(renderer->isSVGText()); >+ RenderBlock* renderBlock = toRenderBlock(renderer); >+ >+ // RenderSVGText only ever contains a single line box. >+ InlineFlowBox* flowBox = renderBlock->firstLineBox(); >+ ASSERT(flowBox == renderBlock->lastLineBox()); >+ return flowBox; >+ } >+ >+ if (renderer->isRenderInline()) { >+ // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath) >+ RenderInline* renderInline = toRenderInline(renderer); >+ >+ // RenderSVGInline only ever contains a single line box. >+ InlineFlowBox* flowBox = renderInline->firstLineBox(); >+ ASSERT(flowBox == renderInline->lastLineBox()); >+ return flowBox; >+ } >+ >+ ASSERT_NOT_REACHED(); >+ return 0; >+} >+ >+static inline float mapLengthThroughChunkTransformation(const SVGInlineTextBox* textBox, bool isVerticalText, float length) >+{ >+ const AffineTransform& transform = textBox->chunkTransformation(); >+ if (transform.isIdentity()) >+ return length; >+ >+ return narrowPrecisionToFloat(static_cast<double>(length) * (isVerticalText ? transform.d() : transform.a())); >+} >+ >+SVGTextQuery::SVGTextQuery(RenderObject* renderer) >+{ >+ collectTextBoxesInFlowBox(flowBoxForRenderer(renderer)); >+} >+ >+void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) >+{ >+ if (!flowBox) >+ return; >+ >+ for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { >+ if (child->isInlineFlowBox()) { >+ // Skip generated content. >+ if (!child->renderer()->node()) >+ continue; >+ >+ collectTextBoxesInFlowBox(static_cast<InlineFlowBox*>(child)); >+ continue; >+ } >+ >+ ASSERT(child->isSVGInlineTextBox()); >+ m_textBoxes.append(static_cast<SVGInlineTextBox*>(child)); >+ } >+} >+ >+bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextChunkPartCallback chunkPartCallback) const >+{ >+ ASSERT(!m_textBoxes.isEmpty()); >+ bool finished = false; >+ >+ // Loop over all text boxes >+ const Vector<SVGInlineTextBox*>::const_iterator end = m_textBoxes.end(); >+ for (Vector<SVGInlineTextBox*>::const_iterator it = m_textBoxes.begin(); it != end; ++it) { >+ const SVGInlineTextBox* textBox = *it; >+ const Vector<SVGTextChunkPart>& parts = textBox->svgTextChunkParts(); >+ >+ int processedCharacters = 0; >+ >+ // Loop over all text chunk parts in this text box, firing a callback for each chunk part. >+ const Vector<SVGTextChunkPart>::const_iterator partEnd = parts.end(); >+ for (Vector<SVGTextChunkPart>::const_iterator partIt = parts.begin(); partIt != partEnd; ++partIt) { >+ if ((this->*chunkPartCallback)(queryData, textBox, *partIt)) { >+ finished = true; >+ break; >+ } >+ >+ processedCharacters += partIt->length; >+ } >+ >+ if (finished) >+ break; >+ >+ queryData->processedChunkCharacters += processedCharacters; >+ } >+ >+ return finished; >+} >+ >+bool SVGTextQuery::mapStartAndLengthIntoChunkPartCoordinates(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part, int& startPosition, int& endPosition) const >+{ >+ // Reuse the same logic used for text selection & painting, to map our query start/length into start/endPositions of the current text chunk part. >+ startPosition -= queryData->processedChunkCharacters; >+ endPosition -= queryData->processedChunkCharacters; >+ textBox->mapStartEndPositionsIntoChunkPartCoordinates(startPosition, endPosition, part); >+ >+ // If startPosition < endPosition, then the position we're supposed to measure lies in this chunk part. >+ return startPosition < endPosition; >+} >+ >+float SVGTextQuery::measureCharacterRange(const SVGInlineTextBox* textBox, RenderStyle* style, bool isVerticalText, int startPosition, int length) const >+{ >+ // FIXME: Vertical writing mode needs to be handled more accurate. >+ if (isVerticalText) >+ return length * style->font().height(); >+ >+ const UChar* startCharacter = textBox->textRenderer()->characters() + textBox->start() + startPosition; >+ return style->font().floatWidth(svgTextRunForInlineTextBox(startCharacter, length, style, textBox)); >+} >+ >+// numberOfCharacters() implementation >+struct NumberOfCharactersData : SVGTextQuery::Data { >+ NumberOfCharactersData() >+ : characters(0) >+ { >+ } >+ >+ unsigned characters; >+}; >+ >+bool SVGTextQuery::numberOfCharactersCallback(Data* queryData, const SVGInlineTextBox*, const SVGTextChunkPart& part) const >+{ >+ NumberOfCharactersData* data = static_cast<NumberOfCharactersData*>(queryData); >+ data->characters += part.length; >+ return false; >+} >+ >+unsigned SVGTextQuery::numberOfCharacters() const >+{ >+ if (m_textBoxes.isEmpty()) >+ return 0; >+ >+ NumberOfCharactersData data; >+ executeQuery(&data, &SVGTextQuery::numberOfCharactersCallback); >+ return data.characters; >+} >+ >+// textLength() implementation >+struct TextLengthData : SVGTextQuery::Data { >+ TextLengthData() >+ : textLength(0.0f) >+ { >+ } >+ >+ float textLength; >+}; >+ >+bool SVGTextQuery::textLengthCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ TextLengthData* data = static_cast<TextLengthData*>(queryData); >+ >+ RenderStyle* style = textBox->textRenderer()->style(); >+ ASSERT(style); >+ >+ bool isVerticalText = isVerticalWritingMode(style->svgStyle()); >+ float partLength = isVerticalText ? part.height : part.width; >+ >+ data->textLength += mapLengthThroughChunkTransformation(textBox, isVerticalText, partLength); >+ return false; >+} >+ >+float SVGTextQuery::textLength() const >+{ >+ if (m_textBoxes.isEmpty()) >+ return 0.0f; >+ >+ TextLengthData data; >+ executeQuery(&data, &SVGTextQuery::textLengthCallback); >+ return data.textLength; >+} >+ >+// subStringLength() implementation >+struct SubStringLengthData : SVGTextQuery::Data { >+ SubStringLengthData(unsigned queryStartPosition, unsigned queryLength) >+ : startPosition(queryStartPosition) >+ , length(queryLength) >+ , subStringLength(0.0f) >+ { >+ } >+ >+ unsigned startPosition; >+ unsigned length; >+ >+ float subStringLength; >+}; >+ >+bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData); >+ >+ int startPosition = data->startPosition; >+ int endPosition = startPosition + data->length; >+ if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition)) >+ return false; >+ >+ RenderStyle* style = textBox->textRenderer()->style(); >+ ASSERT(style); >+ >+ bool isVerticalText = isVerticalWritingMode(style->svgStyle()); >+ float partLength = measureCharacterRange(textBox, style, isVerticalWritingMode(style->svgStyle()), part.offset + startPosition, endPosition - startPosition); >+ >+ data->subStringLength += mapLengthThroughChunkTransformation(textBox, isVerticalText, partLength); >+ return false; >+} >+ >+float SVGTextQuery::subStringLength(unsigned startPosition, unsigned length) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return 0.0f; >+ >+ SubStringLengthData data(startPosition, length); >+ executeQuery(&data, &SVGTextQuery::subStringLengthCallback); >+ return data.subStringLength; >+} >+ >+// startPositionOfCharacter() implementation >+struct StartPositionOfCharacterData : SVGTextQuery::Data { >+ StartPositionOfCharacterData(unsigned queryPosition) >+ : position(queryPosition) >+ { >+ } >+ >+ unsigned position; >+ FloatPoint startPosition; >+}; >+ >+bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterData*>(queryData); >+ >+ int startPosition = data->position; >+ int endPosition = startPosition + 1; >+ if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition)) >+ return false; >+ >+ const SVGChar& character = *(part.firstCharacter + startPosition); >+ data->startPosition = textBox->chunkTransformation().mapPoint(FloatPoint(character.x, character.y)); >+ return true; >+} >+ >+FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return FloatPoint(); >+ >+ StartPositionOfCharacterData data(position); >+ executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback); >+ return data.startPosition; >+} >+ >+// endPositionOfCharacter() implementation >+struct EndPositionOfCharacterData : SVGTextQuery::Data { >+ EndPositionOfCharacterData(unsigned queryPosition) >+ : position(queryPosition) >+ { >+ } >+ >+ unsigned position; >+ FloatPoint endPosition; >+}; >+ >+bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData); >+ >+ int startPosition = data->position; >+ int endPosition = startPosition + 1; >+ if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition)) >+ return false; >+ >+ const SVGChar& character = *(part.firstCharacter + startPosition); >+ data->endPosition = FloatPoint(character.x, character.y); >+ >+ RenderStyle* style = textBox->textRenderer()->style(); >+ ASSERT(style); >+ >+ bool isVerticalText = isVerticalWritingMode(style->svgStyle()); >+ float glyphAdvance = measureCharacterRange(textBox, style, isVerticalText, part.offset + startPosition, 1); >+ >+ if (isVerticalText) >+ data->endPosition.move(0.0f, glyphAdvance); >+ else >+ data->endPosition.move(glyphAdvance, 0.0f); >+ >+ data->endPosition = textBox->chunkTransformation().mapPoint(data->endPosition); >+ return true; >+} >+ >+FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return FloatPoint(); >+ >+ EndPositionOfCharacterData data(position); >+ executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback); >+ return data.endPosition; >+} >+ >+// rotationOfCharacter() implementation >+struct RotationOfCharacterData : SVGTextQuery::Data { >+ RotationOfCharacterData(unsigned queryPosition) >+ : position(queryPosition) >+ , rotation(0.0f) >+ { >+ } >+ >+ unsigned position; >+ float rotation; >+}; >+ >+bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); >+ >+ int startPosition = data->position; >+ int endPosition = startPosition + 1; >+ if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition)) >+ return false; >+ >+ const SVGChar& character = *(part.firstCharacter + startPosition); >+ data->rotation = character.angle; >+ return true; >+} >+ >+float SVGTextQuery::rotationOfCharacter(unsigned position) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return 0.0f; >+ >+ RotationOfCharacterData data(position); >+ executeQuery(&data, &SVGTextQuery::rotationOfCharacterCallback); >+ return data.rotation; >+} >+ >+// extentOfCharacter() implementation >+struct ExtentOfCharacterData : SVGTextQuery::Data { >+ ExtentOfCharacterData(unsigned queryPosition) >+ : position(queryPosition) >+ { >+ } >+ >+ unsigned position; >+ FloatRect extent; >+}; >+ >+bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData); >+ >+ int startPosition = data->position; >+ int endPosition = startPosition + 1; >+ if (!mapStartAndLengthIntoChunkPartCoordinates(queryData, textBox, part, startPosition, endPosition)) >+ return false; >+ >+ RenderStyle* style = textBox->textRenderer()->style(); >+ ASSERT(style); >+ >+ const SVGChar& character = *(part.firstCharacter + startPosition); >+ data->extent = textBox->calculateGlyphBoundaries(style, part.offset + startPosition, character); >+ return true; >+} >+ >+FloatRect SVGTextQuery::extentOfCharacter(unsigned position) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return FloatRect(); >+ >+ ExtentOfCharacterData data(position); >+ executeQuery(&data, &SVGTextQuery::extentOfCharacterCallback); >+ return data.extent; >+} >+ >+// characterNumberAtPosition() implementation >+struct CharacterNumberAtPositionData : SVGTextQuery::Data { >+ CharacterNumberAtPositionData(const FloatPoint& queryPosition) >+ : characterNumber(0) >+ , position(queryPosition) >+ { >+ } >+ >+ unsigned characterNumber; >+ FloatPoint position; >+}; >+ >+bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGInlineTextBox* textBox, const SVGTextChunkPart& part) const >+{ >+ CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionData*>(queryData); >+ >+ RenderStyle* style = textBox->textRenderer()->style(); >+ ASSERT(style); >+ >+ for (int i = 0; i < part.length; ++i) { >+ FloatRect extent(textBox->calculateGlyphBoundaries(style, part.offset + i, *(part.firstCharacter + i))); >+ if (extent.contains(data->position)) >+ return true; >+ >+ ++data->characterNumber; >+ } >+ >+ return false; >+} >+ >+int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const >+{ >+ if (m_textBoxes.isEmpty()) >+ return -1; >+ >+ CharacterNumberAtPositionData data(position); >+ if (!executeQuery(&data, &SVGTextQuery::characterNumberAtPositionCallback)) >+ return -1; >+ >+ return data.characterNumber; >+} >+ >+} >+ >+#endif >Index: WebCore/rendering/SVGTextQuery.h >=================================================================== >--- WebCore/rendering/SVGTextQuery.h (revision 0) >+++ WebCore/rendering/SVGTextQuery.h (revision 0) >@@ -0,0 +1,77 @@ >+/* >+ 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 SVGTextQuery_h >+#define SVGTextQuery_h >+ >+// FIXME: This code is currently deactivated, until the SVG Text rewrite patch lands. >+#if ENABLE(SVG) && 0 >+#include "FloatRect.h" >+#include <wtf/Vector.h> >+ >+namespace WebCore { >+ >+class InlineFlowBox; >+class RenderObject; >+class RenderStyle; >+class SVGInlineTextBox; >+struct SVGTextChunkPart; >+ >+class SVGTextQuery { >+public: >+ SVGTextQuery(RenderObject*); >+ >+ unsigned numberOfCharacters() const; >+ float textLength() const; >+ float subStringLength(unsigned startPosition, unsigned length) const; >+ FloatPoint startPositionOfCharacter(unsigned position) const; >+ FloatPoint endPositionOfCharacter(unsigned position) const; >+ float rotationOfCharacter(unsigned position) const; >+ FloatRect extentOfCharacter(unsigned position) const; >+ int characterNumberAtPosition(const FloatPoint&) const; >+ >+ // Public helper struct. Private classes in SVGTextQuery inherit from it. >+ struct Data; >+ >+private: >+ typedef bool (SVGTextQuery::*ProcessTextChunkPartCallback)(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool executeQuery(Data*, ProcessTextChunkPartCallback) const; >+ >+ void collectTextBoxesInFlowBox(InlineFlowBox*); >+ float measureCharacterRange(const SVGInlineTextBox*, RenderStyle*, bool isVerticalText, int startPosition, int length) const; >+ bool mapStartAndLengthIntoChunkPartCoordinates(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&, int& startPosition, int& endPosition) const; >+ >+private: >+ bool numberOfCharactersCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool textLengthCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool subStringLengthCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool startPositionOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool endPositionOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool rotationOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool extentOfCharacterCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ bool characterNumberAtPositionCallback(Data*, const SVGInlineTextBox*, const SVGTextChunkPart&) const; >+ >+private: >+ Vector<SVGInlineTextBox*> m_textBoxes; >+}; >+ >+} >+ >+#endif >+#endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 40676
:
58891
|
58892