LayoutIntegrationLineIterator.cpp [plain text]
#include "config.h"
#include "LayoutIntegrationLineIterator.h"
#include "LayoutIntegrationLineLayout.h"
#include "LayoutIntegrationRunIterator.h"
#include "RenderBlockFlow.h"
namespace WebCore {
namespace LayoutIntegration {
LineIterator::LineIterator(PathLine::PathVariant&& pathVariant)
: m_line(WTFMove(pathVariant))
{
}
bool LineIterator::atEnd() const
{
return WTF::switchOn(m_line.m_pathVariant, [](auto& path) {
return path.atEnd();
});
}
LineIterator LineIterator::next() const
{
return LineIterator(*this).traverseNext();
}
LineIterator LineIterator::previous() const
{
return LineIterator(*this).traversePrevious();
}
LineIterator& LineIterator::traverseNext()
{
WTF::switchOn(m_line.m_pathVariant, [](auto& path) {
return path.traverseNext();
});
return *this;
}
LineIterator& LineIterator::traversePrevious()
{
WTF::switchOn(m_line.m_pathVariant, [](auto& path) {
return path.traversePrevious();
});
return *this;
}
bool LineIterator::operator==(const LineIterator& other) const
{
return m_line.m_pathVariant == other.m_line.m_pathVariant;
}
RunIterator LineIterator::firstRun() const
{
return WTF::switchOn(m_line.m_pathVariant, [](auto& path) -> RunIterator {
return { path.firstRun() };
});
}
RunIterator LineIterator::lastRun() const
{
return WTF::switchOn(m_line.m_pathVariant, [](auto& path) -> RunIterator {
return { path.lastRun() };
});
}
RunIterator LineIterator::logicalStartRun() const
{
return WTF::switchOn(m_line.m_pathVariant, [](auto& path) -> RunIterator {
return { path.logicalStartRun() };
});
}
RunIterator LineIterator::logicalEndRun() const
{
return WTF::switchOn(m_line.m_pathVariant, [](auto& path) -> RunIterator {
return { path.logicalEndRun() };
});
}
RunIterator LineIterator::logicalStartRunWithNode() const
{
for (auto run = logicalStartRun(); run; run.traverseNextOnLineInLogicalOrder()) {
if (run->renderer().node())
return run;
}
return { };
}
RunIterator LineIterator::logicalEndRunWithNode() const
{
for (auto run = logicalEndRun(); run; run.traversePreviousOnLineInLogicalOrder()) {
if (run->renderer().node())
return run;
}
return { };
}
LineIterator firstLineFor(const RenderBlockFlow& flow)
{
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
if (auto* lineLayout = flow.modernLineLayout())
return lineLayout->firstLine();
#endif
return { LineIteratorLegacyPath { flow.firstRootBox() } };
}
LineIterator lastLineFor(const RenderBlockFlow& flow)
{
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
if (auto* lineLayout = flow.modernLineLayout())
return lineLayout->lastLine();
#endif
return { LineIteratorLegacyPath { flow.lastRootBox() } };
}
RunIterator LineIterator::closestRunForPoint(const IntPoint& pointInContents, bool editableOnly)
{
if (atEnd())
return { };
return closestRunForLogicalLeftPosition(m_line.isHorizontal() ? pointInContents.x() : pointInContents.y(), editableOnly);
}
RunIterator LineIterator::closestRunForLogicalLeftPosition(int leftPosition, bool editableOnly)
{
auto isEditable = [&](auto run)
{
return run && run->renderer().node() && run->renderer().node()->hasEditableStyle();
};
auto firstRun = this->firstRun();
auto lastRun = this->lastRun();
if (firstRun != lastRun) {
if (firstRun->isLineBreak())
firstRun = firstRun.nextOnLineIgnoringLineBreak();
else if (lastRun->isLineBreak())
lastRun = lastRun.previousOnLineIgnoringLineBreak();
}
if (firstRun == lastRun && (!editableOnly || isEditable(firstRun)))
return firstRun;
if (firstRun && leftPosition <= firstRun->logicalLeft() && !firstRun->renderer().isListMarker() && (!editableOnly || isEditable(firstRun)))
return firstRun;
if (lastRun && leftPosition >= lastRun->logicalRight() && !lastRun->renderer().isListMarker() && (!editableOnly || isEditable(lastRun)))
return lastRun;
auto closestRun = lastRun;
for (auto run = firstRun; run; run = run.traverseNextOnLineIgnoringLineBreak()) {
if (!run->renderer().isListMarker() && (!editableOnly || isEditable(run))) {
if (leftPosition < run->logicalRight())
return run;
closestRun = run;
}
}
return closestRun;
}
int PathLine::blockDirectionPointInLine() const
{
return !containingBlock().style().isFlippedBlocksWritingMode() ? std::max(top(), selectionTop()) : std::min(bottom(), selectionBottom());
}
}
}