Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. |
| 3 * | 3 * |
| 4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
| 6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
| 7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 | 21 |
| 22 #include "core/layout/api/LineLayoutSVGInlineText.h" | 22 #include "core/layout/api/LineLayoutSVGInlineText.h" |
| 23 #include "core/layout/svg/LayoutSVGInline.h" | 23 #include "core/layout/svg/LayoutSVGInline.h" |
| 24 #include "core/layout/svg/LayoutSVGInlineText.h" | 24 #include "core/layout/svg/LayoutSVGInlineText.h" |
| 25 #include "core/layout/svg/LayoutSVGText.h" | 25 #include "core/layout/svg/LayoutSVGText.h" |
| 26 #include "core/layout/svg/SVGTextMetrics.h" | 26 #include "core/layout/svg/SVGTextMetrics.h" |
| 27 #include "platform/fonts/CharacterRange.h" | 27 #include "platform/fonts/CharacterRange.h" |
| 28 #include "platform/text/BidiCharacterRun.h" | 28 #include "platform/text/BidiCharacterRun.h" |
| 29 #include "platform/text/BidiResolver.h" | 29 #include "platform/text/BidiResolver.h" |
| 30 #include "platform/text/TextDirection.h" | 30 #include "platform/text/TextDirection.h" |
| 31 #include "platform/text/TextPath.h" | |
| 32 #include "platform/text/TextRun.h" | 31 #include "platform/text/TextRun.h" |
| 33 #include "platform/text/TextRunIterator.h" | 32 #include "platform/text/TextRunIterator.h" |
| 34 #include "wtf/Vector.h" | 33 #include "wtf/Vector.h" |
| 35 | 34 |
| 36 namespace blink { | 35 namespace blink { |
| 37 | 36 |
| 38 class SVGTextMetricsCalculator { | 37 class SVGTextMetricsCalculator { |
| 39 public: | 38 public: |
| 40 SVGTextMetricsCalculator(LayoutSVGInlineText*); | 39 SVGTextMetricsCalculator(LayoutSVGInlineText*); |
| 41 ~SVGTextMetricsCalculator(); | 40 ~SVGTextMetricsCalculator(); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 } | 165 } |
| 167 | 166 |
| 168 SVGTextMetrics SVGTextMetricsCalculator::currentCharacterMetrics() | 167 SVGTextMetrics SVGTextMetricsCalculator::currentCharacterMetrics() |
| 169 { | 168 { |
| 170 unsigned currentSubrunPosition = updateSubrunRangesForCurrentPosition(); | 169 unsigned currentSubrunPosition = updateSubrunRangesForCurrentPosition(); |
| 171 unsigned length = currentCharacterStartsSurrogatePair() ? 2 : 1; | 170 unsigned length = currentCharacterStartsSurrogatePair() ? 2 : 1; |
| 172 float width = m_subrunRanges[currentSubrunPosition].width(); | 171 float width = m_subrunRanges[currentSubrunPosition].width(); |
| 173 return SVGTextMetrics(m_text, length, width); | 172 return SVGTextMetrics(m_text, length, width); |
| 174 } | 173 } |
| 175 | 174 |
| 176 struct MeasureTextData { | 175 struct TreeWalkTextState { |
| 177 MeasureTextData(SVGCharacterDataMap* characterDataMap) | 176 TreeWalkTextState() |
| 178 : allCharactersMap(characterDataMap) | 177 : lastCharacterWasWhiteSpace(true) |
| 179 , lastCharacterWasWhiteSpace(true) | 178 , valueListPosition(0) { } |
| 180 , valueListPosition(0) | |
| 181 { | |
| 182 } | |
| 183 | 179 |
| 184 SVGCharacterDataMap* allCharactersMap; | |
| 185 bool lastCharacterWasWhiteSpace; | 180 bool lastCharacterWasWhiteSpace; |
| 186 unsigned valueListPosition; | 181 unsigned valueListPosition; |
| 187 }; | 182 }; |
| 188 | 183 |
| 189 static void measureTextLayoutObject(LayoutSVGInlineText* text, MeasureTextData* data, bool processLayoutObject) | 184 // Struct for updating SVGTextLayoutAttributes. If an SVGCharacterDataMap is |
| 185 // available, the attribute's character data map will also be updated. | |
|
fs
2016/03/20 23:43:38
Maybe mention the relation to valueListPosition to
pdr.
2016/03/21 18:44:22
Good idea, done.
| |
| 186 struct UpdateAttributes { | |
| 187 UpdateAttributes(SVGTextLayoutAttributes& textAttributes, const SVGCharacter DataMap* allCharacters) | |
| 188 : attributes(textAttributes) | |
| 189 , allCharactersMap(allCharacters) { } | |
| 190 | |
| 191 void clearExistingAttributes() | |
| 192 { | |
| 193 if (allCharactersMap) | |
| 194 attributes.clear(); | |
| 195 else | |
| 196 attributes.textMetricsValues().clear(); | |
| 197 } | |
| 198 | |
| 199 void addMetrics(SVGTextMetrics metrics) | |
| 200 { | |
| 201 attributes.textMetricsValues().append(metrics); | |
| 202 } | |
| 203 | |
| 204 void updateCharacterDataMap(unsigned valueListPosition, unsigned currentText Position) | |
| 205 { | |
| 206 if (!allCharactersMap) | |
| 207 return; | |
| 208 const SVGCharacterDataMap::const_iterator it = allCharactersMap->find(va lueListPosition); | |
| 209 if (it != allCharactersMap->end()) | |
| 210 attributes.characterDataMap().set(currentTextPosition, it->value); | |
| 211 } | |
| 212 | |
| 213 SVGTextLayoutAttributes& attributes; | |
| 214 const SVGCharacterDataMap* allCharactersMap; | |
| 215 }; | |
| 216 | |
| 217 static void walkInlineText(LayoutSVGInlineText* text, TreeWalkTextState& textSta te, UpdateAttributes* attributesToUpdate = nullptr) | |
| 190 { | 218 { |
| 191 ASSERT(text); | 219 if (attributesToUpdate) |
| 192 | 220 attributesToUpdate->clearExistingAttributes(); |
| 193 SVGTextLayoutAttributes* attributes = text->layoutAttributes(); | |
| 194 Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues() ; | |
| 195 if (processLayoutObject) { | |
| 196 if (data->allCharactersMap) | |
| 197 attributes->clear(); | |
| 198 else | |
| 199 textMetricsValues->clear(); | |
| 200 } | |
| 201 | 221 |
| 202 if (!text->textLength()) | 222 if (!text->textLength()) |
| 203 return; | 223 return; |
| 204 | 224 |
| 205 // TODO(pdr): This loop is too tightly coupled to SVGTextMetricsCalculator. | 225 // TODO(pdr): This loop is too tightly coupled to SVGTextMetricsCalculator. |
| 206 // We should refactor SVGTextMetricsCalculator to be a simple bidi run | 226 // We should refactor SVGTextMetricsCalculator to be a simple bidi run |
| 207 // iterator and move all subrun logic to a single function. | 227 // iterator and move all subrun logic to a single function. |
| 208 SVGTextMetricsCalculator calculator(text); | 228 SVGTextMetricsCalculator calculator(text); |
| 209 bool preserveWhiteSpace = text->style()->whiteSpace() == PRE; | 229 bool preserveWhiteSpace = text->style()->whiteSpace() == PRE; |
| 210 unsigned surrogatePairCharacters = 0; | 230 unsigned surrogatePairCharacters = 0; |
| 211 unsigned skippedCharacters = 0; | 231 unsigned skippedWhitespace = 0; |
| 212 do { | 232 do { |
| 213 SVGTextMetrics metrics = calculator.currentCharacterMetrics(); | 233 bool currentCharacterIsWhiteSpace = calculator.currentCharacterIsWhiteSp ace(); |
| 214 if (!metrics.length()) | 234 if (currentCharacterIsWhiteSpace && !preserveWhiteSpace && textState.las tCharacterWasWhiteSpace) { |
| 215 break; | 235 if (attributesToUpdate) |
| 216 | 236 attributesToUpdate->addMetrics(SVGTextMetrics(SVGTextMetrics::Sk ippedSpaceMetrics)); |
| 217 bool characterIsWhiteSpace = calculator.currentCharacterIsWhiteSpace(); | 237 ASSERT(!calculator.currentCharacterStartsSurrogatePair()); |
|
fs
2016/03/20 23:43:38
Maybe just assert calculator.currentCharacterMetri
pdr.
2016/03/21 18:44:22
Done
| |
| 218 if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterW asWhiteSpace) { | 238 ASSERT(textState.lastCharacterWasWhiteSpace); |
|
fs
2016/03/20 23:43:38
This is part of the condition, so maybe a tad over
pdr.
2016/03/21 18:44:22
Done
| |
| 219 if (processLayoutObject) | 239 skippedWhitespace++; |
| 220 textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::Skipped SpaceMetrics)); | |
| 221 if (data->allCharactersMap) | |
| 222 skippedCharacters += metrics.length(); | |
| 223 continue; | 240 continue; |
| 224 } | 241 } |
| 225 | 242 |
| 226 if (processLayoutObject) { | 243 if (attributesToUpdate) { |
| 227 if (data->allCharactersMap) { | 244 attributesToUpdate->updateCharacterDataMap(textState.valueListPositi on - skippedWhitespace - surrogatePairCharacters + calculator.currentPosition() + 1, calculator.currentPosition() + 1); |
| 228 const SVGCharacterDataMap::const_iterator it = data->allCharacte rsMap->find(data->valueListPosition + calculator.currentPosition() - skippedChar acters - surrogatePairCharacters + 1); | 245 attributesToUpdate->addMetrics(calculator.currentCharacterMetrics()) ; |
| 229 if (it != data->allCharactersMap->end()) | |
| 230 attributes->characterDataMap().set(calculator.currentPositio n() + 1, it->value); | |
| 231 } | |
| 232 textMetricsValues->append(metrics); | |
| 233 } | 246 } |
| 234 | 247 |
| 235 if (data->allCharactersMap && calculator.currentCharacterStartsSurrogate Pair()) | 248 if (calculator.currentCharacterStartsSurrogatePair()) |
| 236 surrogatePairCharacters++; | 249 surrogatePairCharacters++; |
| 237 | 250 textState.lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace; |
| 238 data->lastCharacterWasWhiteSpace = characterIsWhiteSpace; | |
| 239 } while (calculator.advancePosition()); | 251 } while (calculator.advancePosition()); |
| 240 | 252 |
| 241 if (!data->allCharactersMap) | 253 textState.valueListPosition += calculator.currentPosition() - skippedWhitesp ace; |
| 242 return; | |
| 243 | |
| 244 data->valueListPosition += calculator.currentPosition() - skippedCharacters; | |
| 245 } | 254 } |
| 246 | 255 |
| 247 static void walkTree(LayoutSVGText* start, LayoutSVGInlineText* stopAtLeaf, Meas ureTextData* data) | 256 static void walkTree(LayoutSVGText* start, LayoutSVGInlineText* stopAtText, SVGC haracterDataMap* allCharactersMap = nullptr) |
| 248 { | 257 { |
| 258 TreeWalkTextState textState; | |
| 249 LayoutObject* child = start->firstChild(); | 259 LayoutObject* child = start->firstChild(); |
| 250 while (child) { | 260 while (child) { |
| 251 if (child->isSVGInlineText()) { | 261 if (child->isSVGInlineText()) { |
| 252 LayoutSVGInlineText* text = toLayoutSVGInlineText(child); | 262 LayoutSVGInlineText* text = toLayoutSVGInlineText(child); |
| 253 measureTextLayoutObject(text, data, !stopAtLeaf || stopAtLeaf == tex t); | 263 OwnPtr<UpdateAttributes> attributesToUpdate = nullptr; |
| 254 if (stopAtLeaf && stopAtLeaf == text) | 264 if (!stopAtText || stopAtText == text) |
| 265 attributesToUpdate = adoptPtr(new UpdateAttributes(*text->layout Attributes(), allCharactersMap)); | |
| 266 walkInlineText(text, textState, attributesToUpdate.get()); | |
| 267 if (stopAtText == text) | |
| 255 return; | 268 return; |
| 256 } else if (child->isSVGInline()) { | 269 } else if (child->isSVGInline()) { |
| 257 // Visit children of text content elements. | 270 // Visit children of text content elements. |
| 258 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild ()) { | 271 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild ()) { |
| 259 child = inlineChild; | 272 child = inlineChild; |
| 260 continue; | 273 continue; |
| 261 } | 274 } |
| 262 } | 275 } |
| 263 child = child->nextInPreOrderAfterChildren(start); | 276 child = child->nextInPreOrderAfterChildren(start); |
| 264 } | 277 } |
| 265 } | 278 } |
| 266 | 279 |
| 267 void SVGTextMetricsBuilder::measureTextLayoutObject(LayoutSVGInlineText* text) | 280 void SVGTextMetricsBuilder::measureTextLayoutObject(LayoutSVGInlineText* text) |
| 268 { | 281 { |
| 269 ASSERT(text); | 282 ASSERT(text); |
| 270 | 283 if (LayoutSVGText* textRoot = LayoutSVGText::locateLayoutSVGTextAncestor(tex t)) |
| 271 LayoutSVGText* textRoot = LayoutSVGText::locateLayoutSVGTextAncestor(text); | 284 walkTree(textRoot, text); |
| 272 if (!textRoot) | |
| 273 return; | |
| 274 | |
| 275 MeasureTextData data(0); | |
| 276 walkTree(textRoot, text, &data); | |
| 277 } | 285 } |
| 278 | 286 |
| 279 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR oot, LayoutSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap) | 287 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) |
| 280 { | 288 { |
| 281 ASSERT(textRoot); | 289 ASSERT(textRoot); |
| 282 MeasureTextData data(&allCharactersMap); | 290 walkTree(textRoot, stopAtText, &allCharactersMap); |
| 283 walkTree(textRoot, stopAtLeaf, &data); | |
| 284 } | 291 } |
| 285 | 292 |
| 286 } // namespace blink | 293 } // namespace blink |
| OLD | NEW |