blob: 354991cebe9252eb4d0b96b7554d60771e41552d [file] [log] [blame]
/*
* Copyright (C) 2011 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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.
*/
#ifndef LayoutFlowThread_h
#define LayoutFlowThread_h
#include "core/CoreExport.h"
#include "core/layout/LayoutBlockFlow.h"
#include "wtf/ListHashSet.h"
namespace blink {
class LayoutMultiColumnSet;
typedef ListHashSet<LayoutMultiColumnSet*> LayoutMultiColumnSetList;
// Layout state for multicol. To be stored when laying out a block child, so
// that we can roll back to the initial state if we need to re-lay out said
// block child.
class MultiColumnLayoutState {
friend class LayoutMultiColumnFlowThread;
public:
MultiColumnLayoutState() : m_columnSet(nullptr) {}
private:
explicit MultiColumnLayoutState(LayoutMultiColumnSet* columnSet)
: m_columnSet(columnSet) {}
LayoutMultiColumnSet* columnSet() const { return m_columnSet; }
LayoutMultiColumnSet* m_columnSet;
};
// LayoutFlowThread is used to collect all the layout objects that participate
// in a flow thread. It will also help in doing the layout. However, it will not
// layout directly to screen. Instead, LayoutMultiColumnSet objects will
// redirect their paint and nodeAtPoint methods to this object. Each
// LayoutMultiColumnSet will actually be a viewPort of the LayoutFlowThread.
class CORE_EXPORT LayoutFlowThread : public LayoutBlockFlow {
public:
LayoutFlowThread();
~LayoutFlowThread() override {}
bool isLayoutFlowThread() const final { return true; }
virtual bool isLayoutMultiColumnFlowThread() const { return false; }
virtual bool isLayoutPagedFlowThread() const { return false; }
static LayoutFlowThread* locateFlowThreadContainingBlockOf(
const LayoutObject&);
void layout() override;
// Always create a Layer for the LayoutFlowThread so that we
// can easily avoid drawing the children directly.
PaintLayerType layerTypeRequired() const final { return NormalPaintLayer; }
virtual void flowThreadDescendantWasInserted(LayoutObject*) {}
virtual void flowThreadDescendantWillBeRemoved(LayoutObject*) {}
virtual void flowThreadDescendantStyleWillChange(
LayoutBox*,
StyleDifference,
const ComputedStyle& newStyle) {}
virtual void flowThreadDescendantStyleDidChange(
LayoutBox*,
StyleDifference,
const ComputedStyle& oldStyle) {}
void absoluteQuadsForDescendant(const LayoutBox& descendant,
Vector<FloatQuad>&);
bool nodeAtPoint(HitTestResult&,
const HitTestLocation& locationInContainer,
const LayoutPoint& accumulatedOffset,
HitTestAction) final;
virtual void addColumnSetToThread(LayoutMultiColumnSet*) = 0;
virtual void removeColumnSetFromThread(LayoutMultiColumnSet*);
void computeLogicalHeight(LayoutUnit logicalHeight,
LayoutUnit logicalTop,
LogicalExtentComputedValues&) const override;
bool hasColumnSets() const { return m_multiColumnSetList.size(); }
void validateColumnSets();
void invalidateColumnSets() { m_columnSetsInvalidated = true; }
bool hasValidColumnSetInfo() const {
return !m_columnSetsInvalidated && !m_multiColumnSetList.isEmpty();
}
bool mapToVisualRectInAncestorSpace(
const LayoutBoxModelObject* ancestor,
LayoutRect&,
VisualRectFlags = DefaultVisualRectFlags) const override;
LayoutUnit pageLogicalHeightForOffset(LayoutUnit);
LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule);
virtual void contentWasLaidOut(
LayoutUnit logicalBottomInFlowThreadAfterPagination) = 0;
virtual bool canSkipLayout(const LayoutBox&) const = 0;
virtual MultiColumnLayoutState multiColumnLayoutState() const = 0;
virtual void restoreMultiColumnLayoutState(const MultiColumnLayoutState&) = 0;
// Find and return the next logical top after |flowThreadOffset| that can fit
// unbreakable content as tall as |contentLogicalHeight|. |flowThreadOffset|
// is expected to be at the exact top of a column that's known to not have
// enough space for |contentLogicalHeight|. This method is called when the
// current column is too short to fit the content, in the hope that there
// exists one that's tall enough further ahead. If no such column can be
// found, |flowThreadOffset| will be returned.
LayoutUnit nextLogicalTopForUnbreakableContent(
LayoutUnit flowThreadOffset,
LayoutUnit contentLogicalHeight) const;
virtual bool isPageLogicalHeightKnown() const { return true; }
virtual bool mayHaveNonUniformPageLogicalHeight() const = 0;
bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
// Return the visual bounding box based on the supplied flow-thread bounding
// box. Both rectangles are completely physical in terms of writing mode.
LayoutRect fragmentsBoundingBox(const LayoutRect& layerBoundingBox) const;
// Convert a logical position in the flow thread coordinate space to a logical
// position in the containing coordinate space.
void flowThreadToContainingCoordinateSpace(LayoutUnit& blockPosition,
LayoutUnit& inlinePosition) const;
virtual LayoutPoint flowThreadPointToVisualPoint(
const LayoutPoint& flowThreadPoint) const = 0;
virtual LayoutPoint visualPointToFlowThreadPoint(
const LayoutPoint& visualPoint) const = 0;
virtual LayoutMultiColumnSet* columnSetAtBlockOffset(
LayoutUnit,
PageBoundaryRule) const = 0;
virtual const char* name() const = 0;
protected:
void generateColumnSetIntervalTree();
LayoutMultiColumnSetList m_multiColumnSetList;
typedef PODInterval<LayoutUnit, LayoutMultiColumnSet*> MultiColumnSetInterval;
typedef PODIntervalTree<LayoutUnit, LayoutMultiColumnSet*>
MultiColumnSetIntervalTree;
class MultiColumnSetSearchAdapter {
public:
MultiColumnSetSearchAdapter(LayoutUnit offset)
: m_offset(offset), m_result(nullptr) {}
const LayoutUnit& lowValue() const { return m_offset; }
const LayoutUnit& highValue() const { return m_offset; }
void collectIfNeeded(const MultiColumnSetInterval&);
LayoutMultiColumnSet* result() const { return m_result; }
private:
LayoutUnit m_offset;
LayoutMultiColumnSet* m_result;
};
MultiColumnSetIntervalTree m_multiColumnSetIntervalTree;
bool m_columnSetsInvalidated : 1;
bool m_pageLogicalSizeChanged : 1;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFlowThread, isLayoutFlowThread());
// These structures are used by PODIntervalTree for debugging.
#ifndef NDEBUG
template <>
struct ValueToString<LayoutMultiColumnSet*> {
static String toString(const LayoutMultiColumnSet* value) {
return String::format("%p", value);
}
};
#endif
} // namespace blink
#endif // LayoutFlowThread_h