DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (5350524bb654)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsColumnSetFrame_h___
#define nsColumnSetFrame_h___

/* rendering object for css3 multi-column layout */

#include "mozilla/Attributes.h"
#include "nsContainerFrame.h"
#include "nsIFrameInlines.h" // for methods used by IS_TRUE_OVERFLOW_CONTAINER

/**
 * nsColumnSetFrame implements CSS multi-column layout.
 * @note nsColumnSetFrame keeps true overflow containers in the normal flow
 * child lists (i.e. the principal and overflow lists).
 */
class nsColumnSetFrame final : public nsContainerFrame
{
public:
  NS_DECL_FRAMEARENA_HELPERS

  explicit nsColumnSetFrame(nsStyleContext* aContext);

  virtual void Reflow(nsPresContext* aPresContext,
                      ReflowOutput& aDesiredSize,
                      const ReflowInput& aReflowInput,
                      nsReflowStatus& aStatus) override;

#ifdef DEBUG
  virtual void SetInitialChildList(ChildListID     aListID,
                                   nsFrameList&    aChildList) override;
  virtual void AppendFrames(ChildListID     aListID,
                            nsFrameList&    aFrameList) override;
  virtual void InsertFrames(ChildListID     aListID,
                            nsIFrame*       aPrevFrame,
                            nsFrameList&    aFrameList) override;
  virtual void RemoveFrame(ChildListID     aListID,
                           nsIFrame*       aOldFrame) override;
#endif

  virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
  virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;

  /**
   * Retrieve the available height for content of this frame. The available content
   * height is the available height for the frame, minus borders and padding.
   */
  virtual nscoord GetAvailableContentBSize(const ReflowInput& aReflowInput);

  virtual nsContainerFrame* GetContentInsertionFrame() override {
    nsIFrame* frame = PrincipalChildList().FirstChild();

    // if no children return nullptr
    if (!frame)
      return nullptr;

    return frame->GetContentInsertionFrame();
  }

  virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsContainerFrame::IsFrameOfType(aFlags &
              ~(nsIFrame::eCanContainOverflowContainers));
   }

  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists) override;

  virtual nsIAtom* GetType() const override;

  virtual void PaintColumnRule(nsRenderingContext* aCtx,
                               const nsRect&        aDirtyRect,
                               const nsPoint&       aPt);

  /**
   * Similar to nsBlockFrame::DrainOverflowLines. Locate any columns not
   * handled by our prev-in-flow, and any columns sitting on our own
   * overflow list, and put them in our primary child list for reflowing.
   */
  void DrainOverflowColumns();

#ifdef DEBUG_FRAME_DUMP
  virtual nsresult GetFrameName(nsAString& aResult) const override {
    return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult);
  }
#endif

protected:
  nscoord        mLastBalanceBSize;
  nsReflowStatus mLastFrameStatus;

  /**
   * These are the parameters that control the layout of columns.
   */
  struct ReflowConfig {
    // The number of columns that we want to balance across. If we're not
    // balancing, this will be set to INT32_MAX.
    int32_t mBalanceColCount;

    // The inline-size of each individual column.
    nscoord mColISize;

    // The amount of inline-size that is expected to be left over after all the
    // columns and column gaps are laid out.
    nscoord mExpectedISizeLeftOver;

    // The width (inline-size) of each column gap.
    nscoord mColGap;

    // The maximum bSize of any individual column during a reflow iteration.
    // This parameter is set during each iteration of the binary search for
    // the best column block-size.
    nscoord mColMaxBSize;

    // A boolean controlling whether or not we are balancing. This should be
    // equivalent to mBalanceColCount == INT32_MAX.
    bool mIsBalancing;

    // The last known column block-size that was 'feasible'. A column bSize is
    // feasible if all child content fits within the specified bSize.
    nscoord mKnownFeasibleBSize;

    // The last known block-size that was 'infeasible'. A column bSize is
    // infeasible if not all child content fits within the specified bSize.
    nscoord mKnownInfeasibleBSize;

    // block-size of the column set frame
    nscoord mComputedBSize;

    // The block-size "consumed" by previous-in-flows.
    // The computed block-size should be equal to the block-size of the element
    // (i.e. the computed block-size itself) plus the consumed block-size.
    nscoord mConsumedBSize;
  };

  /**
   * Some data that is better calculated during reflow
   */
  struct ColumnBalanceData {
    // The maximum "content block-size" of any column
    nscoord mMaxBSize;
    // The sum of the "content block-size" for all columns
    nscoord mSumBSize;
    // The "content block-size" of the last column
    nscoord mLastBSize;
    // The maximum "content block-size" of all columns that overflowed
    // their available block-size
    nscoord mMaxOverflowingBSize;
    // This flag determines whether the last reflow of children exceeded the
    // computed block-size of the column set frame. If so, we set the bSize to
    // this maximum allowable bSize, and continue reflow without balancing.
    bool mHasExcessBSize;

    void Reset() {
      mMaxBSize = mSumBSize = mLastBSize = mMaxOverflowingBSize = 0;
      mHasExcessBSize = false;
    }
  };

  bool ReflowColumns(ReflowOutput& aDesiredSize,
                     const ReflowInput& aReflowInput,
                     nsReflowStatus& aReflowStatus,
                     ReflowConfig& aConfig,
                     bool aLastColumnUnbounded,
                     nsCollapsingMargin* aCarriedOutBEndMargin,
                     ColumnBalanceData& aColData);

  /**
   * The basic reflow strategy is to call this function repeatedly to
   * obtain specific parameters that determine the layout of the
   * columns. This function will compute those parameters from the CSS
   * style. This function will also be responsible for implementing
   * the state machine that controls column balancing.
   */
  ReflowConfig ChooseColumnStrategy(const ReflowInput& aReflowInput,
                                    bool aForceAuto, nscoord aFeasibleBSize,
                                    nscoord aInfeasibleBSize);

  /**
   * Perform the binary search for the best balance height for this column set.
   *
   * @param aReflowInput The input parameters for the current reflow iteration.
   * @param aPresContext The presentation context in which the current reflow
   *        iteration is occurring.
   * @param aConfig The ReflowConfig object associated with this column set
   *        frame, generated by ChooseColumnStrategy().
   * @param aColData A data structure used to keep track of data needed between
   *        successive iterations of the balancing process.
   * @param aDesiredSize The final output size of the column set frame (output
   *        of reflow procedure).
   * @param aOutMargin The bottom margin of the column set frame that may be
   *        carried out from reflow (and thus collapsed).
   * @param aUnboundedLastColumn A boolean value indicating that the last column
   *        can be of any height. Used during the first iteration of the
   *        balancing procedure to measure the height of all content in
   *        descendant frames of the column set.
   * @param aRunWasFeasible An input/output parameter indicating whether or not
   *        the last iteration of the balancing loop was a feasible height to
   *        fit all content from descendant frames.
   * @param aStatus A final reflow status of the column set frame, passed in as
   *        an output parameter.
   */
  void FindBestBalanceBSize(const ReflowInput& aReflowInput,
                            nsPresContext* aPresContext,
                            ReflowConfig& aConfig,
                            ColumnBalanceData& aColData,
                            ReflowOutput& aDesiredSize,
                            nsCollapsingMargin& aOutMargin,
                            bool& aUnboundedLastColumn,
                            bool& aRunWasFeasible,
                            nsReflowStatus& aStatus);
  /**
   * Reflow column children. Returns true iff the content that was reflowed
   * fit into the mColMaxBSize.
   */
  bool ReflowChildren(ReflowOutput& aDesiredSize,
                        const ReflowInput& aReflowInput,
                        nsReflowStatus& aStatus,
                        const ReflowConfig& aConfig,
                        bool aLastColumnUnbounded,
                        nsCollapsingMargin* aCarriedOutBEndMargin,
                        ColumnBalanceData& aColData);
};

#endif // nsColumnSetFrame_h___