[GTK] Menu list button doesn't use the text color from the theme
[WebKit-https.git] / Source / WebCore / rendering / RenderMultiColumnSet.h
index 2ee69df..1802167 100644 (file)
@@ -13,7 +13,7 @@
  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
  * 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
 #ifndef RenderMultiColumnSet_h
 #define RenderMultiColumnSet_h
 
+#include "LayerFragment.h"
+#include "RenderMultiColumnFlowThread.h"
 #include "RenderRegionSet.h"
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -41,35 +44,192 @@ namespace WebCore {
 //
 // Column spans result in the creation of new column sets as well, since a spanning region has to be placed in between the column sets that
 // come before and after the span.
-class RenderMultiColumnSet : public RenderRegionSet {
+class RenderMultiColumnSet final : public RenderRegionSet {
 public:
-    RenderMultiColumnSet(Node*, RenderFlowThread*);
-    
-    virtual bool isRenderMultiColumnSet() const OVERRIDE { return true; }
+    RenderMultiColumnSet(RenderFlowThread&, Ref<RenderStyle>&&);
 
-    unsigned columnCount() const { return m_columnCount; }
-    LayoutUnit columnWidth() const { return m_columnWidth; }
-    LayoutUnit columnHeight() const { return m_columnHeight; }
+    RenderBlockFlow* multiColumnBlockFlow() const { return downcast<RenderBlockFlow>(parent()); }
+    RenderMultiColumnFlowThread* multiColumnFlowThread() const { return static_cast<RenderMultiColumnFlowThread*>(flowThread()); }
 
-    void setColumnWidthAndCount(unsigned count, LayoutUnit width)
-    {
-        m_columnCount = count;
-        m_columnWidth = width;
-    }
-    void setColumnHeight(LayoutUnit height)
+    RenderMultiColumnSet* nextSiblingMultiColumnSet() const;
+    RenderMultiColumnSet* previousSiblingMultiColumnSet() const;
+
+    // Return the first object in the flow thread that's rendered inside this set.
+    RenderObject* firstRendererInFlowThread() const;
+    // Return the last object in the flow thread that's rendered inside this set.
+    RenderObject* lastRendererInFlowThread() const;
+
+    // Return true if the specified renderer (descendant of the flow thread) is inside this column set.
+    bool containsRendererInFlowThread(RenderObject*) const;
+
+    void setLogicalTopInFlowThread(LayoutUnit);
+    LayoutUnit logicalTopInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); }
+    void setLogicalBottomInFlowThread(LayoutUnit);
+    LayoutUnit logicalBottomInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().maxY() : flowThreadPortionRect().maxX(); }
+    LayoutUnit logicalHeightInFlowThread() const { return isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); }
+
+    unsigned computedColumnCount() const { return m_computedColumnCount; }
+    LayoutUnit computedColumnWidth() const { return m_computedColumnWidth; }
+    LayoutUnit computedColumnHeight() const { return m_computedColumnHeight; }
+    bool columnHeightComputed() const { return m_columnHeightComputed; }
+
+    void setComputedColumnWidthAndCount(LayoutUnit width, unsigned count)
     {
-        m_columnHeight = height;
+        m_computedColumnWidth = width;
+        m_computedColumnCount = count;
     }
 
-private:
-    virtual const char* renderName() const;
+    LayoutUnit heightAdjustedForSetOffset(LayoutUnit height) const;
+
+    void updateMinimumColumnHeight(LayoutUnit height) { m_minimumColumnHeight = std::max(height, m_minimumColumnHeight); }
+    LayoutUnit minimumColumnHeight() const { return m_minimumColumnHeight; }
+
+    unsigned forcedBreaksCount() const { return m_contentRuns.size(); }
+    void clearForcedBreaks();
+    void addForcedBreak(LayoutUnit offsetFromFirstPage);
+
+    // (Re-)calculate the column height. This is first and foremost needed by sets that are to
+    // balance the column height, but even when it isn't to be balanced, this is necessary if the
+    // multicol container's height is constrained. If |initial| is set, and we are to balance, guess
+    // an initial column height; otherwise, stretch the column height a tad. Return true if column
+    // height changed and another layout pass is required.
+    bool recalculateColumnHeight(bool initial);
+
+    // Record space shortage (the amount of space that would have been enough to prevent some
+    // element from being moved to the next column) at a column break. The smallest amount of space
+    // shortage we find is the amount with which we will stretch the column height, if it turns out
+    // after layout that the columns weren't tall enough.
+    void recordSpaceShortage(LayoutUnit spaceShortage);
+
+    void updateLogicalWidth() override;
+
+    void prepareForLayout(bool initial);
+    // Begin laying out content for this column set. This happens at the beginning of flow thread
+    // layout, and when advancing from a previous column set or spanner to this one.
+    void beginFlow(RenderBlock* container);
+    // Finish laying out content for this column set. This happens at end of flow thread layout, and
+    // when advancing to the next column set or spanner.
+    void endFlow(RenderBlock* container, LayoutUnit bottomInContainer);
+    // Has this set been flowed in this layout pass?
+    bool hasBeenFlowed() const { return logicalBottomInFlowThread() != RenderFlowThread::maxLogicalHeight(); }
+
+    bool requiresBalancing() const;
+
+    LayoutPoint columnTranslationForOffset(const LayoutUnit&) const;
+    
+    void paintColumnRules(PaintInfo&, const LayoutPoint& paintOffset) override;
+
+    enum ColumnHitTestTranslationMode {
+        ClampHitTestTranslationToColumns,
+        DoNotClampHitTestTranslationToColumns
+    };
+    LayoutPoint translateRegionPointToFlowThread(const LayoutPoint & logicalPoint, ColumnHitTestTranslationMode = DoNotClampHitTestTranslationToColumns) const;
+
+    void updateHitTestResult(HitTestResult&, const LayoutPoint&) override;
+    
+    LayoutRect columnRectAt(unsigned index) const;
+    unsigned columnCount() const;
+
+protected:
+    void addOverflowFromChildren() override;
     
-    unsigned m_columnCount;
-    LayoutUnit m_columnWidth;
-    LayoutUnit m_columnHeight;
+private:
+    bool isRenderMultiColumnSet() const override { return true; }
+    void layout() override;
+
+    void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const override;
+
+    void paintObject(PaintInfo&, const LayoutPoint&) override { }
+
+    LayoutUnit pageLogicalWidth() const override { return m_computedColumnWidth; }
+    LayoutUnit pageLogicalHeight() const override { return m_computedColumnHeight; }
+
+    LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const override;
+
+    LayoutUnit logicalHeightOfAllFlowThreadContent() const override { return logicalHeightInFlowThread(); }
+
+    void repaintFlowThreadContent(const LayoutRect& repaintRect) override;
+
+    void collectLayerFragments(LayerFragments&, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) override;
+
+    void adjustRegionBoundsFromFlowThreadPortionRect(LayoutRect& regionBounds) const override;
+
+    VisiblePosition positionForPoint(const LayoutPoint&, const RenderRegion*) override;
+
+    const char* renderName() const override;
+
+    LayoutUnit calculateMaxColumnHeight() const;
+    LayoutUnit columnGap() const;
+
+    LayoutUnit columnLogicalLeft(unsigned) const;
+    LayoutUnit columnLogicalTop(unsigned) const;
+
+    LayoutRect flowThreadPortionRectAt(unsigned index) const;
+    LayoutRect flowThreadPortionOverflowRect(const LayoutRect& flowThreadPortion, unsigned index, unsigned colCount, LayoutUnit colGap);
+
+    LayoutUnit initialBlockOffsetForPainting() const;
+
+    enum ColumnIndexCalculationMode {
+        ClampToExistingColumns, // Stay within the range of already existing columns.
+        AssumeNewColumns // Allow column indices outside the range of already existing columns.
+    };
+    unsigned columnIndexAtOffset(LayoutUnit, ColumnIndexCalculationMode = ClampToExistingColumns) const;
+
+    void setAndConstrainColumnHeight(LayoutUnit);
+
+    // Return the index of the content run with the currently tallest columns, taking all implicit
+    // breaks assumed so far into account.
+    unsigned findRunWithTallestColumns() const;
+
+    // Given the current list of content runs, make assumptions about where we need to insert
+    // implicit breaks (if there's room for any at all; depending on the number of explicit breaks),
+    // and store the results. This is needed in order to balance the columns.
+    void distributeImplicitBreaks();
+
+    LayoutUnit calculateBalancedHeight(bool initial) const;
+
+    unsigned m_computedColumnCount; // Used column count (the resulting 'N' from the pseudo-algorithm in the multicol spec)
+    LayoutUnit m_computedColumnWidth; // Used column width (the resulting 'W' from the pseudo-algorithm in the multicol spec)
+    LayoutUnit m_computedColumnHeight;
+    LayoutUnit m_availableColumnHeight;
+    bool m_columnHeightComputed;
+
+    // The following variables are used when balancing the column set.
+    LayoutUnit m_maxColumnHeight; // Maximum column height allowed.
+    LayoutUnit m_minSpaceShortage; // The smallest amout of space shortage that caused a column break.
+    LayoutUnit m_minimumColumnHeight;
+
+    // A run of content without explicit (forced) breaks; i.e. a flow thread portion between two
+    // explicit breaks, between flow thread start and an explicit break, between an explicit break
+    // and flow thread end, or, in cases when there are no explicit breaks at all: between flow flow
+    // thread start and flow thread end. We need to know where the explicit breaks are, in order to
+    // figure out where the implicit breaks will end up, so that we get the columns properly
+    // balanced. A content run starts out as representing one single column, and will represent one
+    // additional column for each implicit break "inserted" there.
+    class ContentRun {
+    public:
+        ContentRun(LayoutUnit breakOffset)
+            : m_breakOffset(breakOffset)
+            , m_assumedImplicitBreaks(0) { }
+
+        unsigned assumedImplicitBreaks() const { return m_assumedImplicitBreaks; }
+        void assumeAnotherImplicitBreak() { m_assumedImplicitBreaks++; }
+        LayoutUnit breakOffset() const { return m_breakOffset; }
+
+        // Return the column height that this content run would require, considering the implicit
+        // breaks assumed so far.
+        LayoutUnit columnLogicalHeight(LayoutUnit startOffset) const { return ceilf(float(m_breakOffset - startOffset) / float(m_assumedImplicitBreaks + 1)); }
+
+    private:
+        LayoutUnit m_breakOffset; // Flow thread offset where this run ends.
+        unsigned m_assumedImplicitBreaks; // Number of implicit breaks in this run assumed so far.
+    };
+    Vector<ContentRun, 1> m_contentRuns;
 };
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderMultiColumnSet, isRenderMultiColumnSet())
+
 #endif // RenderMultiColumnSet_h