/* * Copyright (C) 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "LayoutRect.h" #include "RenderBlockFlow.h" #include "SimpleLineLayoutFlowContents.h" #include "SimpleLineLayoutFunctions.h" #include #include namespace WebCore { namespace SimpleLineLayout { class RunResolver { WTF_MAKE_FAST_ALLOCATED; public: class Iterator; class Run { public: explicit Run(const Iterator&); unsigned start() const; unsigned end() const; float logicalLeft() const; float logicalRight() const; FloatRect rect() const; float expansion() const; ExpansionBehavior expansionBehavior() const; int baselinePosition() const; StringView text() const; String textWithHyphen() const; bool isEndOfLine() const; bool hasHyphen() const { return m_iterator.simpleRun().hasHyphen; } unsigned lineIndex() const; private: float computeBaselinePosition() const; void constructStringForHyphenIfNeeded(); const Iterator& m_iterator; }; class Iterator { friend class Run; friend class RunResolver; friend class LineResolver; public: Iterator(const RunResolver&, unsigned runIndex, unsigned lineIndex); Iterator& operator++(); Iterator& operator--(); bool operator==(const Iterator&) const; bool operator!=(const Iterator&) const; Run operator*() const; private: const SimpleLineLayout::Run& simpleRun() const; unsigned lineIndex() const { return m_lineIndex; } Iterator& advance(); Iterator& advanceLines(unsigned); const RunResolver& resolver() const { return m_resolver; } bool inQuirksMode() const { return m_resolver.m_inQuirksMode; } const RunResolver& m_resolver; unsigned m_runIndex; unsigned m_lineIndex; }; RunResolver(const RenderBlockFlow&, const Layout&); const RenderBlockFlow& flow() const { return m_flowRenderer; } const FlowContents& flowContents() const { return m_flowContents; } Iterator begin() const; Iterator end() const; WTF::IteratorRange rangeForRect(const LayoutRect&) const; WTF::IteratorRange rangeForRenderer(const RenderObject&) const; Iterator runForPoint(const LayoutPoint&) const; WTF::IteratorRange rangeForRendererWithOffsets(const RenderObject&, unsigned start, unsigned end) const; private: enum class IndexType { First, Last }; unsigned lineIndexForHeight(LayoutUnit, IndexType) const; unsigned adjustLineIndexForStruts(LayoutUnit, unsigned lineIndexCandidate) const; const RenderBlockFlow& m_flowRenderer; const Layout& m_layout; const FlowContents m_flowContents; const LayoutUnit m_lineHeight; const LayoutUnit m_baseline; const LayoutUnit m_borderAndPaddingBefore; const float m_ascent; const float m_descent; const float m_visualOverflowOffset; const bool m_inQuirksMode; }; class LineResolver { public: class Iterator { public: explicit Iterator(RunResolver::Iterator); Iterator& operator++(); bool operator==(const Iterator&) const; bool operator!=(const Iterator&) const; FloatRect operator*() const; // FIXME: Use a list to support multiple renderers per line. const RenderObject& renderer() const; private: RunResolver::Iterator m_runIterator; }; LineResolver(const RenderBlockFlow&, const Layout&); Iterator begin() const; Iterator end() const; WTF::IteratorRange rangeForRect(const LayoutRect&) const; private: RunResolver m_runResolver; }; RunResolver runResolver(const RenderBlockFlow&, const Layout&); LineResolver lineResolver(const RenderBlockFlow&, const Layout&); inline unsigned RunResolver::Run::start() const { return m_iterator.simpleRun().start; } inline unsigned RunResolver::Run::end() const { return m_iterator.simpleRun().end; } inline float RunResolver::Run::logicalLeft() const { return m_iterator.simpleRun().logicalLeft; } inline float RunResolver::Run::logicalRight() const { return m_iterator.simpleRun().logicalRight; } inline float RunResolver::Run::expansion() const { return m_iterator.simpleRun().expansion; } inline ExpansionBehavior RunResolver::Run::expansionBehavior() const { return m_iterator.simpleRun().expansionBehavior; } inline int RunResolver::Run::baselinePosition() const { return roundToInt(computeBaselinePosition()); } inline bool RunResolver::Run::isEndOfLine() const { return m_iterator.simpleRun().isEndOfLine; } inline unsigned RunResolver::Run::lineIndex() const { return m_iterator.lineIndex(); } inline RunResolver::Iterator& RunResolver::Iterator::operator++() { return advance(); } inline float RunResolver::Run::computeBaselinePosition() const { auto& resolver = m_iterator.resolver(); auto offset = resolver.m_borderAndPaddingBefore + resolver.m_lineHeight * lineIndex(); if (!resolver.m_layout.hasLineStruts()) return offset + resolver.m_baseline; for (auto& strutEntry : resolver.m_layout.struts()) { if (strutEntry.lineBreak > lineIndex()) break; offset += strutEntry.offset; } return offset + resolver.m_baseline; } inline RunResolver::Iterator& RunResolver::Iterator::operator--() { --m_runIndex; if (simpleRun().isEndOfLine) --m_lineIndex; return *this; } inline bool RunResolver::Iterator::operator==(const Iterator& other) const { ASSERT(&m_resolver == &other.m_resolver); return m_runIndex == other.m_runIndex; } inline bool RunResolver::Iterator::operator!=(const Iterator& other) const { return !(*this == other); } inline RunResolver::Run RunResolver::Iterator::operator*() const { return Run(*this); } inline const SimpleLineLayout::Run& RunResolver::Iterator::simpleRun() const { return m_resolver.m_layout.runAt(m_runIndex); } inline RunResolver::Iterator RunResolver::begin() const { return Iterator(*this, 0, 0); } inline RunResolver::Iterator RunResolver::end() const { return Iterator(*this, m_layout.runCount(), m_layout.lineCount()); } inline LineResolver::Iterator& LineResolver::Iterator::operator++() { m_runIterator.advanceLines(1); return *this; } inline bool LineResolver::Iterator::operator==(const Iterator& other) const { return m_runIterator == other.m_runIterator; } inline bool LineResolver::Iterator::operator!=(const Iterator& other) const { return m_runIterator != other.m_runIterator; } inline LineResolver::Iterator LineResolver::begin() const { return Iterator(m_runResolver.begin()); } inline LineResolver::Iterator LineResolver::end() const { return Iterator(m_runResolver.end()); } inline WTF::IteratorRange LineResolver::rangeForRect(const LayoutRect& rect) const { auto runRange = m_runResolver.rangeForRect(rect); return { Iterator(runRange.begin()), Iterator(runRange.end()) }; } inline RunResolver runResolver(const RenderBlockFlow& flow, const Layout& layout) { return RunResolver(flow, layout); } inline LineResolver lineResolver(const RenderBlockFlow& flow, const Layout& layout) { return LineResolver(flow, layout); } } }