Changeset 157349 in webkit


Ignore:
Timestamp:
Oct 12, 2013, 3:33:53 PM (12 years ago)
Author:
Antti Koivisto
Message:

Move positionForPoint to RenderTextLineBoxes
https://bugs.webkit.org/show_bug.cgi?id=122703

Reviewed by Andreas Kling.

Location:
trunk/Source/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r157348 r157349  
     12013-10-12  Antti Koivisto  <antti@apple.com>
     2
     3        Move positionForPoint to RenderTextLineBoxes
     4        https://bugs.webkit.org/show_bug.cgi?id=122703
     5
     6        Reviewed by Andreas Kling.
     7
    182013-10-12  Andreas Kling  <akling@apple.com>
    29
  • trunk/Source/WebCore/rendering/RenderObject.cpp

    r157222 r157349  
    24982498}
    24992499
    2500 VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
     2500VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity) const
    25012501{
    25022502    // If this is a non-anonymous renderer in an editable area, then it's simple.
     
    25222522
    25232523    // Find a nearby non-anonymous renderer.
    2524     RenderObject* child = this;
    2525     while (RenderObject* parent = child->parent()) {
     2524    const RenderObject* child = this;
     2525    while (const RenderElement* parent = child->parent()) {
    25262526        // Find non-anonymous content after.
    2527         RenderObject* renderer = child;
     2527        const RenderObject* renderer = child;
    25282528        while ((renderer = renderer->nextInPreOrder(parent))) {
    25292529            if (Node* node = renderer->nonPseudoNode())
     
    25412541
    25422542        // Use the parent itself unless it too is anonymous.
    2543         if (Node* node = parent->nonPseudoNode())
    2544             return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
     2543        if (Element* element = parent->nonPseudoElement())
     2544            return VisiblePosition(firstPositionInOrBeforeNode(element), DOWNSTREAM);
    25452545
    25462546        // Repeat at the next level up.
     
    25522552}
    25532553
    2554 VisiblePosition RenderObject::createVisiblePosition(const Position& position)
     2554VisiblePosition RenderObject::createVisiblePosition(const Position& position) const
    25552555{
    25562556    if (position.isNotNull())
  • trunk/Source/WebCore/rendering/RenderObject.h

    r157222 r157349  
    670670
    671671    virtual VisiblePosition positionForPoint(const LayoutPoint&);
    672     VisiblePosition createVisiblePosition(int offset, EAffinity);
    673     VisiblePosition createVisiblePosition(const Position&);
     672    VisiblePosition createVisiblePosition(int offset, EAffinity) const;
     673    VisiblePosition createVisiblePosition(const Position&) const;
    674674
    675675    // returns the containing block level element for this element.
  • trunk/Source/WebCore/rendering/RenderText.cpp

    r157346 r157349  
    404404}
    405405
    406 enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
    407 
    408 static bool lineDirectionPointFitsInBox(int pointLineDirection, InlineTextBox* box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
    409 {
    410     shouldAffinityBeDownstream = AlwaysDownstream;
    411 
    412     // the x coordinate is equal to the left edge of this box
    413     // the affinity must be downstream so the position doesn't jump back to the previous line
    414     // except when box is the first box in the line
    415     if (pointLineDirection <= box->logicalLeft()) {
    416         shouldAffinityBeDownstream = !box->prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
    417         return true;
    418     }
    419 
    420     // and the x coordinate is to the left of the right edge of this box
    421     // check to see if position goes in this box
    422     if (pointLineDirection < box->logicalRight()) {
    423         shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
    424         return true;
    425     }
    426 
    427     // box is first on line
    428     // and the x coordinate is to the left of the first text box left edge
    429     if (!box->prevLeafChildIgnoringLineBreak() && pointLineDirection < box->logicalLeft())
    430         return true;
    431 
    432     if (!box->nextLeafChildIgnoringLineBreak()) {
    433         // box is last on line
    434         // and the x coordinate is to the right of the last text box right edge
    435         // generate VisiblePosition, use UPSTREAM affinity if possible
    436         shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
    437         return true;
    438     }
    439 
    440     return false;
    441 }
    442 
    443 static VisiblePosition createVisiblePositionForBox(const InlineBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
    444 {
    445     EAffinity affinity = VP_DEFAULT_AFFINITY;
    446     switch (shouldAffinityBeDownstream) {
    447     case AlwaysDownstream:
    448         affinity = DOWNSTREAM;
    449         break;
    450     case AlwaysUpstream:
    451         affinity = VP_UPSTREAM_IF_POSSIBLE;
    452         break;
    453     case UpstreamIfPositionIsNotAtStart:
    454         affinity = offset > box->caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
    455         break;
    456     }
    457     return box->renderer().createVisiblePosition(offset, affinity);
    458 }
    459 
    460 static VisiblePosition createVisiblePositionAfterAdjustingOffsetForBiDi(const InlineTextBox* box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
    461 {
    462     ASSERT(box);
    463     ASSERT(offset >= 0);
    464 
    465     if (offset && static_cast<unsigned>(offset) < box->len())
    466         return createVisiblePositionForBox(box, box->start() + offset, shouldAffinityBeDownstream);
    467 
    468     bool positionIsAtStartOfBox = !offset;
    469     if (positionIsAtStartOfBox == box->isLeftToRightDirection()) {
    470         // offset is on the left edge
    471 
    472         const InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
    473         if ((prevBox && prevBox->bidiLevel() == box->bidiLevel())
    474             || box->renderer().containingBlock()->style()->direction() == box->direction()) // FIXME: left on 12CBA
    475             return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
    476 
    477         if (prevBox && prevBox->bidiLevel() > box->bidiLevel()) {
    478             // e.g. left of B in aDC12BAb
    479             const InlineBox* leftmostBox;
    480             do {
    481                 leftmostBox = prevBox;
    482                 prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
    483             } while (prevBox && prevBox->bidiLevel() > box->bidiLevel());
    484             return createVisiblePositionForBox(leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
    485         }
    486 
    487         if (!prevBox || prevBox->bidiLevel() < box->bidiLevel()) {
    488             // e.g. left of D in aDC12BAb
    489             const InlineBox* rightmostBox;
    490             const InlineBox* nextBox = box;
    491             do {
    492                 rightmostBox = nextBox;
    493                 nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
    494             } while (nextBox && nextBox->bidiLevel() >= box->bidiLevel());
    495             return createVisiblePositionForBox(rightmostBox,
    496                 box->isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
    497         }
    498 
    499         return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
    500     }
    501 
    502     const InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
    503     if ((nextBox && nextBox->bidiLevel() == box->bidiLevel())
    504         || box->renderer().containingBlock()->style()->direction() == box->direction())
    505         return createVisiblePositionForBox(box, box->caretRightmostOffset(), shouldAffinityBeDownstream);
    506 
    507     // offset is on the right edge
    508     if (nextBox && nextBox->bidiLevel() > box->bidiLevel()) {
    509         // e.g. right of C in aDC12BAb
    510         const InlineBox* rightmostBox;
    511         do {
    512             rightmostBox = nextBox;
    513             nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
    514         } while (nextBox && nextBox->bidiLevel() > box->bidiLevel());
    515         return createVisiblePositionForBox(rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
    516     }
    517 
    518     if (!nextBox || nextBox->bidiLevel() < box->bidiLevel()) {
    519         // e.g. right of A in aDC12BAb
    520         const InlineBox* leftmostBox;
    521         const InlineBox* prevBox = box;
    522         do {
    523             leftmostBox = prevBox;
    524             prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
    525         } while (prevBox && prevBox->bidiLevel() >= box->bidiLevel());
    526         return createVisiblePositionForBox(leftmostBox,
    527             box->isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
    528     }
    529 
    530     return createVisiblePositionForBox(box, box->caretLeftmostOffset(), shouldAffinityBeDownstream);
    531 }
    532 
    533406VisiblePosition RenderText::positionForPoint(const LayoutPoint& point)
    534407{
    535     if (!firstTextBox() || textLength() == 0)
    536         return createVisiblePosition(0, DOWNSTREAM);
    537 
    538     LayoutUnit pointLineDirection = firstTextBox()->isHorizontal() ? point.x() : point.y();
    539     LayoutUnit pointBlockDirection = firstTextBox()->isHorizontal() ? point.y() : point.x();
    540     bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
    541 
    542     InlineTextBox* lastBox = 0;
    543     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
    544         if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
    545             box = box->nextTextBox();
    546 
    547         const RootInlineBox& rootBox = box->root();
    548         LayoutUnit top = min(rootBox.selectionTop(), rootBox.lineTop());
    549         if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
    550             LayoutUnit bottom = rootBox.selectionBottom();
    551             if (rootBox.nextRootBox())
    552                 bottom = min(bottom, rootBox.nextRootBox()->lineTop());
    553 
    554             if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
    555                 ShouldAffinityBeDownstream shouldAffinityBeDownstream;
    556                 if (lineDirectionPointFitsInBox(pointLineDirection, box, shouldAffinityBeDownstream))
    557                     return createVisiblePositionAfterAdjustingOffsetForBiDi(box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
    558             }
    559         }
    560         lastBox = box;
    561     }
    562 
    563     if (lastBox) {
    564         ShouldAffinityBeDownstream shouldAffinityBeDownstream;
    565         lineDirectionPointFitsInBox(pointLineDirection, lastBox, shouldAffinityBeDownstream);
    566         return createVisiblePositionAfterAdjustingOffsetForBiDi(lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
    567     }
    568     return createVisiblePosition(0, DOWNSTREAM);
     408    return m_lineBoxes.positionForPoint(*this, point);
    569409}
    570410
  • trunk/Source/WebCore/rendering/RenderTextLineBoxes.cpp

    r157346 r157349  
    2828
    2929#include "InlineTextBox.h"
     30#include "RenderBlock.h"
    3031#include "RenderStyle.h"
    3132#include "RootInlineBox.h"
     
    223224        maxOffset = std::max<int>(maxOffset, box->start() + box->len());
    224225    return maxOffset;
     226}
     227
     228enum ShouldAffinityBeDownstream { AlwaysDownstream, AlwaysUpstream, UpstreamIfPositionIsNotAtStart };
     229
     230static bool lineDirectionPointFitsInBox(int pointLineDirection, const InlineTextBox& box, ShouldAffinityBeDownstream& shouldAffinityBeDownstream)
     231{
     232    shouldAffinityBeDownstream = AlwaysDownstream;
     233
     234    // the x coordinate is equal to the left edge of this box
     235    // the affinity must be downstream so the position doesn't jump back to the previous line
     236    // except when box is the first box in the line
     237    if (pointLineDirection <= box.logicalLeft()) {
     238        shouldAffinityBeDownstream = !box.prevLeafChild() ? UpstreamIfPositionIsNotAtStart : AlwaysDownstream;
     239        return true;
     240    }
     241
     242    // and the x coordinate is to the left of the right edge of this box
     243    // check to see if position goes in this box
     244    if (pointLineDirection < box.logicalRight()) {
     245        shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
     246        return true;
     247    }
     248
     249    // box is first on line
     250    // and the x coordinate is to the left of the first text box left edge
     251    if (!box.prevLeafChildIgnoringLineBreak() && pointLineDirection < box.logicalLeft())
     252        return true;
     253
     254    if (!box.nextLeafChildIgnoringLineBreak()) {
     255        // box is last on line
     256        // and the x coordinate is to the right of the last text box right edge
     257        // generate VisiblePosition, use UPSTREAM affinity if possible
     258        shouldAffinityBeDownstream = UpstreamIfPositionIsNotAtStart;
     259        return true;
     260    }
     261
     262    return false;
     263}
     264
     265static VisiblePosition createVisiblePositionForBox(const InlineBox& box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
     266{
     267    EAffinity affinity = VP_DEFAULT_AFFINITY;
     268    switch (shouldAffinityBeDownstream) {
     269    case AlwaysDownstream:
     270        affinity = DOWNSTREAM;
     271        break;
     272    case AlwaysUpstream:
     273        affinity = VP_UPSTREAM_IF_POSSIBLE;
     274        break;
     275    case UpstreamIfPositionIsNotAtStart:
     276        affinity = offset > box.caretMinOffset() ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM;
     277        break;
     278    }
     279    return box.renderer().createVisiblePosition(offset, affinity);
     280}
     281
     282static VisiblePosition createVisiblePositionAfterAdjustingOffsetForBiDi(const InlineTextBox& box, int offset, ShouldAffinityBeDownstream shouldAffinityBeDownstream)
     283{
     284    ASSERT(offset >= 0);
     285
     286    if (offset && static_cast<unsigned>(offset) < box.len())
     287        return createVisiblePositionForBox(box, box.start() + offset, shouldAffinityBeDownstream);
     288
     289    bool positionIsAtStartOfBox = !offset;
     290    if (positionIsAtStartOfBox == box.isLeftToRightDirection()) {
     291        // offset is on the left edge
     292
     293        const InlineBox* prevBox = box.prevLeafChildIgnoringLineBreak();
     294        if ((prevBox && prevBox->bidiLevel() == box.bidiLevel())
     295            || box.renderer().containingBlock()->style()->direction() == box.direction()) // FIXME: left on 12CBA
     296            return createVisiblePositionForBox(box, box.caretLeftmostOffset(), shouldAffinityBeDownstream);
     297
     298        if (prevBox && prevBox->bidiLevel() > box.bidiLevel()) {
     299            // e.g. left of B in aDC12BAb
     300            const InlineBox* leftmostBox;
     301            do {
     302                leftmostBox = prevBox;
     303                prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
     304            } while (prevBox && prevBox->bidiLevel() > box.bidiLevel());
     305            return createVisiblePositionForBox(*leftmostBox, leftmostBox->caretRightmostOffset(), shouldAffinityBeDownstream);
     306        }
     307
     308        if (!prevBox || prevBox->bidiLevel() < box.bidiLevel()) {
     309            // e.g. left of D in aDC12BAb
     310            const InlineBox* rightmostBox;
     311            const InlineBox* nextBox = &box;
     312            do {
     313                rightmostBox = nextBox;
     314                nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
     315            } while (nextBox && nextBox->bidiLevel() >= box.bidiLevel());
     316            return createVisiblePositionForBox(*rightmostBox,
     317                box.isLeftToRightDirection() ? rightmostBox->caretMaxOffset() : rightmostBox->caretMinOffset(), shouldAffinityBeDownstream);
     318        }
     319
     320        return createVisiblePositionForBox(box, box.caretRightmostOffset(), shouldAffinityBeDownstream);
     321    }
     322
     323    const InlineBox* nextBox = box.nextLeafChildIgnoringLineBreak();
     324    if ((nextBox && nextBox->bidiLevel() == box.bidiLevel())
     325        || box.renderer().containingBlock()->style()->direction() == box.direction())
     326        return createVisiblePositionForBox(box, box.caretRightmostOffset(), shouldAffinityBeDownstream);
     327
     328    // offset is on the right edge
     329    if (nextBox && nextBox->bidiLevel() > box.bidiLevel()) {
     330        // e.g. right of C in aDC12BAb
     331        const InlineBox* rightmostBox;
     332        do {
     333            rightmostBox = nextBox;
     334            nextBox = rightmostBox->nextLeafChildIgnoringLineBreak();
     335        } while (nextBox && nextBox->bidiLevel() > box.bidiLevel());
     336        return createVisiblePositionForBox(*rightmostBox, rightmostBox->caretLeftmostOffset(), shouldAffinityBeDownstream);
     337    }
     338
     339    if (!nextBox || nextBox->bidiLevel() < box.bidiLevel()) {
     340        // e.g. right of A in aDC12BAb
     341        const InlineBox* leftmostBox;
     342        const InlineBox* prevBox = &box;
     343        do {
     344            leftmostBox = prevBox;
     345            prevBox = leftmostBox->prevLeafChildIgnoringLineBreak();
     346        } while (prevBox && prevBox->bidiLevel() >= box.bidiLevel());
     347        return createVisiblePositionForBox(*leftmostBox,
     348            box.isLeftToRightDirection() ? leftmostBox->caretMinOffset() : leftmostBox->caretMaxOffset(), shouldAffinityBeDownstream);
     349    }
     350
     351    return createVisiblePositionForBox(box, box.caretLeftmostOffset(), shouldAffinityBeDownstream);
     352}
     353
     354VisiblePosition RenderTextLineBoxes::positionForPoint(const RenderText& renderer, const LayoutPoint& point) const
     355{
     356    if (!m_first || !renderer.textLength())
     357        return renderer.createVisiblePosition(0, DOWNSTREAM);
     358
     359    LayoutUnit pointLineDirection = m_first->isHorizontal() ? point.x() : point.y();
     360    LayoutUnit pointBlockDirection = m_first->isHorizontal() ? point.y() : point.x();
     361    bool blocksAreFlipped = renderer.style()->isFlippedBlocksWritingMode();
     362
     363    InlineTextBox* lastBox = nullptr;
     364    for (auto box = m_first; box; box = box->nextTextBox()) {
     365        if (box->isLineBreak() && !box->prevLeafChild() && box->nextLeafChild() && !box->nextLeafChild()->isLineBreak())
     366            box = box->nextTextBox();
     367
     368        auto& rootBox = box->root();
     369        LayoutUnit top = std::min(rootBox.selectionTop(), rootBox.lineTop());
     370        if (pointBlockDirection > top || (!blocksAreFlipped && pointBlockDirection == top)) {
     371            LayoutUnit bottom = rootBox.selectionBottom();
     372            if (rootBox.nextRootBox())
     373                bottom = std::min(bottom, rootBox.nextRootBox()->lineTop());
     374
     375            if (pointBlockDirection < bottom || (blocksAreFlipped && pointBlockDirection == bottom)) {
     376                ShouldAffinityBeDownstream shouldAffinityBeDownstream;
     377                if (lineDirectionPointFitsInBox(pointLineDirection, *box, shouldAffinityBeDownstream))
     378                    return createVisiblePositionAfterAdjustingOffsetForBiDi(*box, box->offsetForPosition(pointLineDirection), shouldAffinityBeDownstream);
     379            }
     380        }
     381        lastBox = box;
     382    }
     383
     384    if (lastBox) {
     385        ShouldAffinityBeDownstream shouldAffinityBeDownstream;
     386        lineDirectionPointFitsInBox(pointLineDirection, *lastBox, shouldAffinityBeDownstream);
     387        return createVisiblePositionAfterAdjustingOffsetForBiDi(*lastBox, lastBox->offsetForPosition(pointLineDirection) + lastBox->start(), shouldAffinityBeDownstream);
     388    }
     389    return renderer.createVisiblePosition(0, DOWNSTREAM);
    225390}
    226391
     
    306471}
    307472
     473inline void RenderTextLineBoxes::checkConsistency() const
     474{
    308475#if !ASSERT_DISABLED
    309 RenderTextLineBoxes::~RenderTextLineBoxes()
    310 {
    311     ASSERT(!m_first);
    312     ASSERT(!m_last);
    313 }
    314 
    315 void RenderTextLineBoxes::checkConsistency() const
    316 {
    317476#ifdef CHECK_CONSISTENCY
    318477    const InlineTextBox* prev = nullptr;
     
    324483    ASSERT(prev == m_last);
    325484#endif
    326 }
    327485#endif
    328 
    329 }
     486}
     487
     488#if !ASSERT_DISABLED
     489RenderTextLineBoxes::~RenderTextLineBoxes()
     490{
     491    ASSERT(!m_first);
     492    ASSERT(!m_last);
     493}
     494#endif
     495
     496}
  • trunk/Source/WebCore/rendering/RenderTextLineBoxes.h

    r157346 r157349  
    2828
    2929#include "LayoutRect.h"
     30#include "VisiblePosition.h"
    3031
    3132namespace WebCore {
     
    5758    int caretMaxOffset(const RenderText&) const;
    5859
     60    VisiblePosition positionForPoint(const RenderText&, const LayoutPoint&) const;
     61
    5962    IntRect boundingBox(const RenderText&) const;
    6063    LayoutRect visualOverflowBoundingBox(const RenderText&) const;
     
    6871
    6972private:
    70 #if !ASSERT_DISABLED
    7173    void checkConsistency() const;
    72 #else
    73     void checkConsistency() const { }
    74 #endif
    7574
    7675    InlineTextBox* m_first;
     
    8079}
    8180
    82 
    8381#endif
Note: See TracChangeset for help on using the changeset viewer.