Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(357)

Side by Side Diff: third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp

Issue 1816073002: Optimize the characterNumberAtPositionCallback text query (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@svg-textquery--cleanup-2
Patch Set: Tidy up comment. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 struct StartPositionOfCharacterData : QueryData { 286 struct StartPositionOfCharacterData : QueryData {
287 StartPositionOfCharacterData(unsigned queryPosition) 287 StartPositionOfCharacterData(unsigned queryPosition)
288 : position(queryPosition) 288 : position(queryPosition)
289 { 289 {
290 } 290 }
291 291
292 unsigned position; 292 unsigned position;
293 FloatPoint startPosition; 293 FloatPoint startPosition;
294 }; 294 };
295 295
296 static FloatPoint calculateGlyphPositionWithoutTransform(const QueryData* queryD ata, const SVGTextFragment& fragment, unsigned offsetInFragment) 296 static FloatPoint logicalGlyphPositionToPhysical(const QueryData* queryData, con st SVGTextFragment& fragment, float logicalGlyphOffset)
297 { 297 {
298 float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, o ffsetInFragment); 298 float physicalGlyphOffset = logicalGlyphOffset;
299
300 if (!queryData->textBox->isLeftToRightDirection()) { 299 if (!queryData->textBox->isLeftToRightDirection()) {
301 float fragmentExtent = queryData->isVerticalText ? fragment.height : fra gment.width; 300 float fragmentExtent = queryData->isVerticalText ? fragment.height : fra gment.width;
302 glyphOffsetInDirection = fragmentExtent - glyphOffsetInDirection; 301 physicalGlyphOffset = fragmentExtent - logicalGlyphOffset;
303 } 302 }
304 303
305 FloatPoint glyphPosition(fragment.x, fragment.y); 304 FloatPoint glyphPosition(fragment.x, fragment.y);
306 if (queryData->isVerticalText) 305 if (queryData->isVerticalText)
307 glyphPosition.move(0, glyphOffsetInDirection); 306 glyphPosition.move(0, physicalGlyphOffset);
308 else 307 else
309 glyphPosition.move(glyphOffsetInDirection, 0); 308 glyphPosition.move(physicalGlyphOffset, 0);
310 309
311 return glyphPosition; 310 return glyphPosition;
312 } 311 }
313 312
314 static FloatPoint calculateGlyphPosition(const QueryData* queryData, const SVGTe xtFragment& fragment, unsigned offsetInFragment) 313 static FloatPoint calculateGlyphPosition(const QueryData* queryData, const SVGTe xtFragment& fragment, unsigned offsetInFragment)
315 { 314 {
316 FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, offsetInFragment); 315 float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, o ffsetInFragment);
316 FloatPoint glyphPosition = logicalGlyphPositionToPhysical(queryData, fragmen t, glyphOffsetInDirection);
317 if (fragment.isTransformed()) { 317 if (fragment.isTransformed()) {
318 AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGT extFragment::TransformIgnoringTextLength); 318 AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGT extFragment::TransformIgnoringTextLength);
319 glyphPosition = fragmentTransform.mapPoint(glyphPosition); 319 glyphPosition = fragmentTransform.mapPoint(glyphPosition);
320 } 320 }
321 return glyphPosition; 321 return glyphPosition;
322 } 322 }
323 323
324 static bool startPositionOfCharacterCallback(QueryData* queryData, const SVGText Fragment& fragment) 324 static bool startPositionOfCharacterCallback(QueryData* queryData, const SVGText Fragment& fragment)
325 { 325 {
326 StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterDat a*>(queryData); 326 StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterDat a*>(queryData);
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
414 struct ExtentOfCharacterData : QueryData { 414 struct ExtentOfCharacterData : QueryData {
415 ExtentOfCharacterData(unsigned queryPosition) 415 ExtentOfCharacterData(unsigned queryPosition)
416 : position(queryPosition) 416 : position(queryPosition)
417 { 417 {
418 } 418 }
419 419
420 unsigned position; 420 unsigned position;
421 FloatRect extent; 421 FloatRect extent;
422 }; 422 };
423 423
424 static inline FloatRect calculateGlyphBoundaries(const QueryData* queryData, con st SVGTextFragment& fragment, int startPosition) 424 static FloatRect physicalGlyphExtents(const QueryData* queryData, const SVGTextM etrics& metrics, const FloatPoint& glyphPosition)
425 { 425 {
426 float scalingFactor = queryData->textLineLayout.scalingFactor();
427 ASSERT(scalingFactor);
428
429 FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, startPosition);
430 glyphPosition.move(0, -queryData->textLineLayout.scaledFont().getFontMetrics ().floatAscent() / scalingFactor);
431
432 // Use the SVGTextMetrics computed by SVGTextMetricsBuilder (which spends
433 // time attempting to compute more correct glyph bounds already, handling
434 // cursive scripts to some degree.)
435 const MetricsList& textMetricsValues = queryData->textLineLayout.layoutAttri butes()->textMetricsValues();
436 auto metrics = findMetricsForCharacter(textMetricsValues, fragment, startPos ition);
437
438 // TODO(fs): Negative glyph extents seems kind of weird to have, but 426 // TODO(fs): Negative glyph extents seems kind of weird to have, but
439 // presently it can occur in some cases (like Arabic.) 427 // presently it can occur in some cases (like Arabic.)
440 FloatSize glyphSize(std::max<float>(metrics->width(), 0), std::max<float>(me trics->height(), 0)); 428 FloatRect glyphExtents(
429 glyphPosition,
430 FloatSize(std::max<float>(metrics.width(), 0), std::max<float>(metrics.h eight(), 0)));
441 431
442 // If RTL, adjust the starting point to align with the LHS of the glyph boun ding box. 432 // If RTL, adjust the starting point to align with the LHS of the glyph boun ding box.
443 if (!queryData->textBox->isLeftToRightDirection()) { 433 if (!queryData->textBox->isLeftToRightDirection()) {
444 if (queryData->isVerticalText) 434 if (queryData->isVerticalText)
445 glyphPosition.move(0, -glyphSize.height()); 435 glyphExtents.move(0, -glyphExtents.height());
446 else 436 else
447 glyphPosition.move(-glyphSize.width(), 0); 437 glyphExtents.move(-glyphExtents.width(), 0);
448 } 438 }
439 return glyphExtents;
440 }
449 441
450 FloatRect extent(glyphPosition, glyphSize); 442 static inline FloatRect calculateGlyphBoundaries(const QueryData* queryData, con st SVGTextFragment& fragment, int startPosition)
443 {
444 const float scalingFactor = queryData->textLineLayout.scalingFactor();
445 ASSERT(scalingFactor);
446 const float baseline = queryData->textLineLayout.scaledFont().getFontMetrics ().floatAscent() / scalingFactor;
447
448 float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, s tartPosition);
449 FloatPoint glyphPosition = logicalGlyphPositionToPhysical(queryData, fragmen t, glyphOffsetInDirection);
450 glyphPosition.move(0, -baseline);
451
452 // Use the SVGTextMetrics computed by SVGTextMetricsBuilder.
453 const MetricsList& metricsList = queryData->textLineLayout.layoutAttributes( )->textMetricsValues();
454 auto metrics = findMetricsForCharacter(metricsList, fragment, startPosition) ;
455
456 FloatRect extent = physicalGlyphExtents(queryData, *metrics, glyphPosition);
451 if (fragment.isTransformed()) { 457 if (fragment.isTransformed()) {
452 AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGT extFragment::TransformIgnoringTextLength); 458 AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGT extFragment::TransformIgnoringTextLength);
453 extent = fragmentTransform.mapRect(extent); 459 extent = fragmentTransform.mapRect(extent);
454 } 460 }
455 return extent; 461 return extent;
456 } 462 }
457 463
458 static inline FloatRect calculateFragmentBoundaries(LineLayoutSVGInlineText text LineLayout, const SVGTextFragment& fragment)
459 {
460 float scalingFactor = textLineLayout.scalingFactor();
461 ASSERT(scalingFactor);
462 float baseline = textLineLayout.scaledFont().getFontMetrics().floatAscent() / scalingFactor;
463 return fragment.boundingBox(baseline);
464 }
465
466 static bool extentOfCharacterCallback(QueryData* queryData, const SVGTextFragmen t& fragment) 464 static bool extentOfCharacterCallback(QueryData* queryData, const SVGTextFragmen t& fragment)
467 { 465 {
468 ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData) ; 466 ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData) ;
469 467
470 int startPosition = data->position; 468 int startPosition = data->position;
471 int endPosition = startPosition + 1; 469 int endPosition = startPosition + 1;
472 if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startP osition, endPosition)) 470 if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startP osition, endPosition))
473 return false; 471 return false;
474 472
475 data->extent = calculateGlyphBoundaries(queryData, fragment, startPosition); 473 data->extent = calculateGlyphBoundaries(queryData, fragment, startPosition);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 --index; 531 --index;
534 offset += textBoxes[index]->len(); 532 offset += textBoxes[index]->len();
535 } 533 }
536 return offset; 534 return offset;
537 } 535 }
538 536
539 static bool characterNumberAtPositionCallback(QueryData* queryData, const SVGTex tFragment& fragment) 537 static bool characterNumberAtPositionCallback(QueryData* queryData, const SVGTex tFragment& fragment)
540 { 538 {
541 CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionD ata*>(queryData); 539 CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionD ata*>(queryData);
542 540
541 const float scalingFactor = data->textLineLayout.scalingFactor();
542 ASSERT(scalingFactor);
543 const float baseline = data->textLineLayout.scaledFont().getFontMetrics().fl oatAscent() / scalingFactor;
544
543 // Test the query point against the bounds of the entire fragment first. 545 // Test the query point against the bounds of the entire fragment first.
544 FloatRect fragmentExtents = calculateFragmentBoundaries(queryData->textLineL ayout, fragment); 546 if (!fragment.boundingBox(baseline).contains(data->position))
545 if (!fragmentExtents.contains(data->position))
546 return false; 547 return false;
547 548
549 AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextF ragment::TransformIgnoringTextLength);
550
548 // Iterate through the glyphs in this fragment, and check if their extents 551 // Iterate through the glyphs in this fragment, and check if their extents
549 // contain the query point. 552 // contain the query point.
550 const Vector<SVGTextMetrics>& textMetrics = queryData->textLineLayout.layout Attributes()->textMetricsValues(); 553 MetricsList::const_iterator metrics =
551 unsigned textMetricsOffset = fragment.metricsListOffset; 554 data->textLineLayout.layoutAttributes()->textMetricsValues().begin() + f ragment.metricsListOffset;
552 unsigned fragmentOffset = 0; 555 unsigned fragmentOffset = 0;
556 float glyphOffset = 0;
553 while (fragmentOffset < fragment.length) { 557 while (fragmentOffset < fragment.length) {
554 FloatRect extent = calculateGlyphBoundaries(queryData, fragment, fragmen tOffset); 558 FloatPoint glyphPosition = logicalGlyphPositionToPhysical(data, fragment , glyphOffset);
559 glyphPosition.move(0, -baseline);
560
561 FloatRect extent = fragmentTransform.mapRect(physicalGlyphExtents(data, *metrics, glyphPosition));
555 if (extent.contains(data->position)) { 562 if (extent.contains(data->position)) {
556 // Compute the character offset of the glyph within the text node. 563 // Compute the character offset of the glyph within the text node.
557 unsigned offsetInBox = fragment.characterOffset - queryData->textBox ->start() + fragmentOffset; 564 unsigned offsetInBox = fragment.characterOffset - queryData->textBox ->start() + fragmentOffset;
558 data->offsetInTextNode = logicalOffsetInTextNode(queryData->textLine Layout, queryData->textBox, offsetInBox); 565 data->offsetInTextNode = logicalOffsetInTextNode(queryData->textLine Layout, queryData->textBox, offsetInBox);
559 data->hitLayoutItem = LineLayoutItem(data->textLineLayout); 566 data->hitLayoutItem = LineLayoutItem(data->textLineLayout);
560 return true; 567 return true;
561 } 568 }
562 fragmentOffset += textMetrics[textMetricsOffset].length(); 569 fragmentOffset += metrics->length();
563 textMetricsOffset++; 570 glyphOffset += data->isVerticalText ? metrics->height() : metrics->width ();
571 ++metrics;
564 } 572 }
565 return false; 573 return false;
566 } 574 }
567 575
568 int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const 576 int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const
569 { 577 {
570 CharacterNumberAtPositionData data(position); 578 CharacterNumberAtPositionData data(position);
571 spatialQuery(m_queryRootLayoutObject, &data, characterNumberAtPositionCallba ck); 579 spatialQuery(m_queryRootLayoutObject, &data, characterNumberAtPositionCallba ck);
572 return data.characterNumberWithin(m_queryRootLayoutObject); 580 return data.characterNumberWithin(m_queryRootLayoutObject);
573 } 581 }
574 582
575 } // namespace blink 583 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698