tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsFrameSetFrame.cpp (54731B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* rendering object for HTML <frameset> elements */
      8 
      9 #include "nsFrameSetFrame.h"
     10 
     11 #include "gfxContext.h"
     12 #include "gfxUtils.h"
     13 #include "mozAutoDocUpdate.h"
     14 #include "mozilla/ComputedStyle.h"
     15 #include "mozilla/LookAndFeel.h"
     16 #include "mozilla/MouseEvents.h"
     17 #include "mozilla/Preferences.h"
     18 #include "mozilla/PresShell.h"
     19 #include "mozilla/PresShellInlines.h"
     20 #include "mozilla/ServoStyleSet.h"
     21 #include "mozilla/ServoStyleSetInlines.h"
     22 #include "mozilla/dom/ChildIterator.h"
     23 #include "mozilla/dom/Element.h"
     24 #include "mozilla/dom/HTMLFrameSetElement.h"
     25 #include "mozilla/gfx/2D.h"
     26 #include "mozilla/gfx/Helpers.h"
     27 #include "nsAttrValueInlines.h"
     28 #include "nsCSSAnonBoxes.h"
     29 #include "nsContainerFrame.h"
     30 #include "nsDisplayList.h"
     31 #include "nsGenericHTMLElement.h"
     32 #include "nsGkAtoms.h"
     33 #include "nsHTMLParts.h"
     34 #include "nsIContentInlines.h"
     35 #include "nsLayoutUtils.h"
     36 #include "nsLeafFrame.h"
     37 #include "nsNameSpaceManager.h"
     38 #include "nsPresContext.h"
     39 #include "nsStyleConsts.h"
     40 #include "nsSubDocumentFrame.h"
     41 
     42 using namespace mozilla;
     43 using namespace mozilla::dom;
     44 using namespace mozilla::gfx;
     45 
     46 // masks for mEdgeVisibility
     47 #define LEFT_VIS 0x0001
     48 #define RIGHT_VIS 0x0002
     49 #define TOP_VIS 0x0004
     50 #define BOTTOM_VIS 0x0008
     51 #define ALL_VIS 0x000F
     52 #define NONE_VIS 0x0000
     53 
     54 /*******************************************************************************
     55 * nsFramesetDrag
     56 ******************************************************************************/
     57 nsFramesetDrag::nsFramesetDrag() { UnSet(); }
     58 
     59 void nsFramesetDrag::Reset(bool aVertical, int32_t aIndex, int32_t aChange,
     60                           nsHTMLFramesetFrame* aSource) {
     61  mVertical = aVertical;
     62  mIndex = aIndex;
     63  mChange = aChange;
     64  mSource = aSource;
     65 }
     66 
     67 void nsFramesetDrag::UnSet() {
     68  mVertical = true;
     69  mIndex = -1;
     70  mChange = 0;
     71  mSource = nullptr;
     72 }
     73 
     74 /*******************************************************************************
     75 * nsHTMLFramesetBorderFrame
     76 ******************************************************************************/
     77 class nsHTMLFramesetBorderFrame final : public nsLeafFrame {
     78 public:
     79  NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBorderFrame)
     80 
     81 #ifdef DEBUG_FRAME_DUMP
     82  virtual nsresult GetFrameName(nsAString& aResult) const override;
     83 #endif
     84 
     85  virtual nsresult HandleEvent(nsPresContext* aPresContext,
     86                               WidgetGUIEvent* aEvent,
     87                               nsEventStatus* aEventStatus) override;
     88 
     89  Cursor GetCursor(const nsPoint&) override;
     90 
     91  virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
     92                                const nsDisplayListSet& aLists) override;
     93 
     94  virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
     95                      const ReflowInput& aReflowInput,
     96                      nsReflowStatus& aStatus) override;
     97 
     98  bool GetVisibility() { return mVisibility; }
     99  void SetVisibility(bool aVisibility);
    100  void SetColor(nscolor aColor);
    101 
    102  void PaintBorder(DrawTarget* aDrawTarget, nsPoint aPt);
    103 
    104 protected:
    105  nsHTMLFramesetBorderFrame(ComputedStyle*, nsPresContext*, int32_t aWidth,
    106                            bool aVertical, bool aVisible);
    107  virtual ~nsHTMLFramesetBorderFrame();
    108 
    109  // the prev and next neighbors are indexes into the row (for a horizontal
    110  // border) or col (for a vertical border) of nsHTMLFramesetFrames or
    111  // nsHTMLFrames
    112  int32_t mPrevNeighbor;
    113  int32_t mNextNeighbor;
    114  nscolor mColor;
    115  int32_t mWidth;
    116  bool mVertical;
    117  bool mVisibility;
    118  bool mCanResize;
    119  friend class nsHTMLFramesetFrame;
    120 };
    121 /*******************************************************************************
    122 * nsHTMLFramesetBlankFrame
    123 ******************************************************************************/
    124 class nsHTMLFramesetBlankFrame final : public nsLeafFrame {
    125 public:
    126  NS_DECL_QUERYFRAME
    127  NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBlankFrame)
    128 
    129 #ifdef DEBUG_FRAME_DUMP
    130  virtual nsresult GetFrameName(nsAString& aResult) const override {
    131    return MakeFrameName(u"FramesetBlank"_ns, aResult);
    132  }
    133 #endif
    134 
    135  virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
    136                                const nsDisplayListSet& aLists) override;
    137 
    138  virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
    139                      const ReflowInput& aReflowInput,
    140                      nsReflowStatus& aStatus) override;
    141 
    142 protected:
    143  explicit nsHTMLFramesetBlankFrame(ComputedStyle* aStyle,
    144                                    nsPresContext* aPresContext)
    145      : nsLeafFrame(aStyle, aPresContext, kClassID) {}
    146 
    147  virtual ~nsHTMLFramesetBlankFrame();
    148 
    149  friend class nsHTMLFramesetFrame;
    150  friend class nsHTMLFrameset;
    151 };
    152 
    153 /*******************************************************************************
    154 * nsHTMLFramesetFrame
    155 ******************************************************************************/
    156 bool nsHTMLFramesetFrame::gDragInProgress = false;
    157 #define DEFAULT_BORDER_WIDTH_PX 6
    158 
    159 nsHTMLFramesetFrame::nsHTMLFramesetFrame(ComputedStyle* aStyle,
    160                                         nsPresContext* aPresContext)
    161    : nsContainerFrame(aStyle, aPresContext, kClassID) {
    162  mEdgeVisibility = 0;
    163  mParentFrameborder = eFrameborder_Yes;  // default
    164  mParentBorderWidth = -1;                // default not set
    165  mParentBorderColor = NO_COLOR;          // default not set
    166  mFirstDragPoint.x = mFirstDragPoint.y = 0;
    167  mMinDrag = nsPresContext::CSSPixelsToAppUnits(2);
    168  mNonBorderChildCount = 0;
    169  mNonBlankChildCount = 0;
    170  mDragger = nullptr;
    171  mChildCount = 0;
    172  mTopLevelFrameset = nullptr;
    173  mEdgeColors.Set(NO_COLOR);
    174 }
    175 
    176 nsHTMLFramesetFrame::~nsHTMLFramesetFrame() = default;
    177 
    178 NS_QUERYFRAME_HEAD(nsHTMLFramesetFrame)
    179  NS_QUERYFRAME_ENTRY(nsHTMLFramesetFrame)
    180 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    181 
    182 void nsHTMLFramesetFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
    183                               nsIFrame* aPrevInFlow) {
    184  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    185  // find the highest ancestor that is a frameset
    186  nsIFrame* parentFrame = GetParent();
    187  mTopLevelFrameset = this;
    188  while (parentFrame) {
    189    nsHTMLFramesetFrame* frameset = do_QueryFrame(parentFrame);
    190    if (frameset) {
    191      mTopLevelFrameset = frameset;
    192      parentFrame = parentFrame->GetParent();
    193    } else {
    194      break;
    195    }
    196  }
    197 
    198  nsPresContext* presContext = PresContext();
    199  mozilla::PresShell* presShell = presContext->PresShell();
    200 
    201  nsFrameborder frameborder = GetFrameBorder();
    202  int32_t borderWidth = GetBorderWidth(presContext, false);
    203  nscolor borderColor = GetBorderColor();
    204 
    205  // Get the rows= cols= data
    206  HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromNode(mContent);
    207  NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
    208  auto rowSpecs = ourContent->GetRowSpec();
    209  auto colSpecs = ourContent->GetColSpec();
    210 
    211  static_assert(
    212      NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscoord),
    213      "Maximum value of NumRows() and NumCols() is NS_MAX_FRAMESET_SPEC_COUNT");
    214  mRowSizes.Clear();
    215  mRowSizes.SetLength(rowSpecs.Length());
    216  mColSizes.Clear();
    217  mColSizes.SetLength(colSpecs.Length());
    218 
    219  static_assert(
    220      NS_MAX_FRAMESET_SPEC_COUNT < INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT,
    221      "Should not overflow numCells");
    222  int32_t numCells = NumRows() * NumCols();
    223 
    224  static_assert(NS_MAX_FRAMESET_SPEC_COUNT <
    225                    UINT_MAX / sizeof(nsHTMLFramesetBorderFrame*),
    226                "Should not overflow nsHTMLFramesetBorderFrame");
    227  mVerBorders.Clear();
    228  mVerBorders.SetLength(NumCols());  // 1 more than number of ver borders
    229 
    230  for (int32_t verX = 0; verX < NumCols(); verX++) {
    231    mVerBorders[verX] = nullptr;
    232  }
    233 
    234  mHorBorders.Clear();
    235  mHorBorders.SetLength(NumRows());  // 1 more than number of hor borders
    236 
    237  for (int32_t horX = 0; horX < NumRows(); horX++) {
    238    mHorBorders[horX] = nullptr;
    239  }
    240 
    241  static_assert(NS_MAX_FRAMESET_SPEC_COUNT <
    242                    UINT_MAX / sizeof(int32_t) / NS_MAX_FRAMESET_SPEC_COUNT,
    243                "Should not overflow numCells");
    244  static_assert(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nsFrameborder) /
    245                                                 NS_MAX_FRAMESET_SPEC_COUNT,
    246                "Should not overflow numCells");
    247  static_assert(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nsBorderColor) /
    248                                                 NS_MAX_FRAMESET_SPEC_COUNT,
    249                "Should not overflow numCells");
    250  mNeedFirstReflowWork = true;
    251  mChildFrameborder.Clear();
    252  mChildFrameborder.SetLength(numCells);
    253  mChildBorderColors.Clear();
    254  mChildBorderColors.SetLength(numCells);
    255 
    256  // create the children frames; skip content which isn't <frameset> or <frame>
    257  mChildCount = 0;  // number of <frame> or <frameset> children
    258 
    259  FlattenedChildIterator children(mContent);
    260  for (nsIContent* child = children.GetNextChild(); child;
    261       child = children.GetNextChild()) {
    262    if (mChildCount == numCells) {
    263      // we have more <frame> or <frameset> than cells
    264      // Clear the lazy bits in the remaining children.  Also clear
    265      // the restyle flags, like nsCSSFrameConstructor::ProcessChildren does.
    266      for (; child; child = child->GetNextSibling()) {
    267        child->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
    268      }
    269      break;
    270    }
    271    child->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME);
    272 
    273    // IMPORTANT: This must match the conditions in
    274    // nsCSSFrameConstructor::ContentAppended/Inserted/Removed
    275    if (!child->IsAnyOfHTMLElements(nsGkAtoms::frameset, nsGkAtoms::frame)) {
    276      continue;
    277    }
    278 
    279    // FIXME(emilio): This doesn't even respect display: none, but that matches
    280    // other browsers ;_;
    281    //
    282    // Maybe we should change that though.
    283    RefPtr<ComputedStyle> kidStyle =
    284        ServoStyleSet::ResolveServoStyle(*child->AsElement());
    285    nsIFrame* frame;
    286    if (child->IsHTMLElement(nsGkAtoms::frameset)) {
    287      frame = NS_NewHTMLFramesetFrame(presShell, kidStyle);
    288 
    289      nsHTMLFramesetFrame* childFrame = (nsHTMLFramesetFrame*)frame;
    290      childFrame->SetParentFrameborder(frameborder);
    291      childFrame->SetParentBorderWidth(borderWidth);
    292      childFrame->SetParentBorderColor(borderColor);
    293      frame->Init(child, this, nullptr);
    294 
    295      mChildBorderColors[mChildCount].Set(childFrame->GetBorderColor());
    296    } else {  // frame
    297      frame = NS_NewSubDocumentFrame(presShell, kidStyle);
    298 
    299      frame->Init(child, this, nullptr);
    300 
    301      mChildFrameborder[mChildCount] = GetFrameBorder(child);
    302      mChildBorderColors[mChildCount].Set(GetBorderColor(child));
    303    }
    304    child->SetPrimaryFrame(frame);
    305 
    306    mFrames.AppendFrame(nullptr, frame);
    307 
    308    mChildCount++;
    309  }
    310 
    311  mNonBlankChildCount = mChildCount;
    312  // add blank frames for frameset cells that had no content provided
    313  for (int blankX = mChildCount; blankX < numCells; blankX++) {
    314    RefPtr<ComputedStyle> pseudoComputedStyle =
    315        presShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
    316            PseudoStyleType::framesetBlank);
    317 
    318    // XXX the blank frame is using the content of its parent - at some point it
    319    // should just have null content, if we support that
    320    nsHTMLFramesetBlankFrame* blankFrame = new (presShell)
    321        nsHTMLFramesetBlankFrame(pseudoComputedStyle, PresContext());
    322 
    323    blankFrame->Init(mContent, this, nullptr);
    324 
    325    mFrames.AppendFrame(nullptr, blankFrame);
    326 
    327    mChildBorderColors[mChildCount].Set(NO_COLOR);
    328    mChildCount++;
    329  }
    330 
    331  mNonBorderChildCount = mChildCount;
    332 }
    333 
    334 void nsHTMLFramesetFrame::SetInitialChildList(ChildListID aListID,
    335                                              nsFrameList&& aChildList) {
    336  // We do this weirdness where we create our child frames in Init().  On the
    337  // other hand, we're going to get a SetInitialChildList() with an empty list
    338  // and null list name after the frame constructor is done creating us.  So
    339  // just ignore that call.
    340  if (aListID == FrameChildListID::Principal && aChildList.IsEmpty()) {
    341    return;
    342  }
    343 
    344  nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
    345 }
    346 
    347 // XXX should this try to allocate twips based on an even pixel boundary?
    348 void nsHTMLFramesetFrame::Scale(nscoord aDesired, int32_t aNumIndicies,
    349                                const nsTArray<int32_t>& aIndicies,
    350                                nsTArray<int32_t>& aItems) {
    351  int32_t actual = 0;
    352  // get the actual total
    353  for (int32_t i = 0; i < aNumIndicies; i++) {
    354    int32_t j = aIndicies[i];
    355    actual += aItems[j];
    356  }
    357 
    358  if (actual > 0) {
    359    float factor = (float)aDesired / (float)actual;
    360    actual = 0;
    361    // scale the items up or down
    362    for (int32_t i = 0; i < aNumIndicies; i++) {
    363      int32_t j = aIndicies[i];
    364      aItems[j] = NSToCoordRound((float)aItems[j] * factor);
    365      actual += aItems[j];
    366    }
    367  } else if (aNumIndicies != 0) {
    368    // All the specs say zero width, but we have to fill up space
    369    // somehow.  Distribute it equally.
    370    nscoord width = NSToCoordRound((float)aDesired / (float)aNumIndicies);
    371    actual = width * aNumIndicies;
    372    for (int32_t i = 0; i < aNumIndicies; i++) {
    373      aItems[aIndicies[i]] = width;
    374    }
    375  }
    376 
    377  if (aNumIndicies > 0 && aDesired != actual) {
    378    int32_t unit = (aDesired > actual) ? 1 : -1;
    379    for (int32_t i = 0; (i < aNumIndicies) && (aDesired != actual); i++) {
    380      int32_t j = aIndicies[i];
    381      if (CheckedInt<size_t>(j).value() < aItems.Length()) {
    382        aItems[j] += unit;
    383        actual += unit;
    384      }
    385    }
    386  }
    387 }
    388 
    389 /**
    390 * Translate the rows/cols specs into an array of integer sizes for
    391 * each cell in the frameset. Sizes are allocated based on the priorities of the
    392 * specifier - fixed sizes have the highest priority, percentage sizes have the
    393 * next highest priority and relative sizes have the lowest.
    394 */
    395 void nsHTMLFramesetFrame::CalculateRowCol(
    396    nsPresContext* aPresContext, nscoord aSize,
    397    const mozilla::Span<const nsFramesetSpec>& aSpecs,
    398    nsTArray<nscoord>& aValues) {
    399  static_assert(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(int32_t),
    400                "aNumSpecs maximum value is NS_MAX_FRAMESET_SPEC_COUNT");
    401  MOZ_ASSERT(aSpecs.Length() == aValues.Length());
    402 
    403  int32_t fixedTotal = 0;
    404  int32_t numFixed = 0;
    405  nsTArray<int32_t> fixed;
    406  fixed.SetLength(aSpecs.Length());
    407  int32_t numPercent = 0;
    408  nsTArray<int32_t> percent;
    409  percent.SetLength(aSpecs.Length());
    410  int32_t relativeSums = 0;
    411  int32_t numRelative = 0;
    412  nsTArray<int32_t> relative;
    413  relative.SetLength(aSpecs.Length());
    414 
    415  // initialize the fixed, percent, relative indices, allocate the fixed sizes
    416  // and zero the others
    417  for (int32_t i = 0; i < CheckedInt<int32_t>(aSpecs.Length()).value(); i++) {
    418    aValues[i] = 0;
    419    switch (aSpecs[i].mUnit) {
    420      case eFramesetUnit_Fixed:
    421        aValues[i] = nsPresContext::CSSPixelsToAppUnits(aSpecs[i].mValue);
    422        fixedTotal += aValues[i];
    423        fixed[numFixed] = i;
    424        numFixed++;
    425        break;
    426      case eFramesetUnit_Percent:
    427        percent[numPercent] = i;
    428        numPercent++;
    429        break;
    430      case eFramesetUnit_Relative:
    431        relative[numRelative] = i;
    432        numRelative++;
    433        relativeSums += aSpecs[i].mValue;
    434        break;
    435    }
    436  }
    437 
    438  // scale the fixed sizes if they total too much (or too little and there
    439  // aren't any percent or relative)
    440  if ((fixedTotal > aSize) ||
    441      ((fixedTotal < aSize) && (0 == numPercent) && (0 == numRelative))) {
    442    Scale(aSize, numFixed, fixed, aValues);
    443    return;
    444  }
    445 
    446  int32_t percentMax = aSize - fixedTotal;
    447  int32_t percentTotal = 0;
    448  // allocate the percentage sizes from what is left over from the fixed
    449  // allocation
    450  for (int32_t i = 0; i < numPercent; i++) {
    451    int32_t j = percent[i];
    452    aValues[j] =
    453        NSToCoordRound((float)aSpecs[j].mValue * (float)aSize / 100.0f);
    454    percentTotal += aValues[j];
    455  }
    456 
    457  // scale the percent sizes if they total too much (or too little and there
    458  // aren't any relative)
    459  if ((percentTotal > percentMax) ||
    460      ((percentTotal < percentMax) && (0 == numRelative))) {
    461    Scale(percentMax, numPercent, percent, aValues);
    462    return;
    463  }
    464 
    465  int32_t relativeMax = percentMax - percentTotal;
    466  int32_t relativeTotal = 0;
    467  // allocate the relative sizes from what is left over from the percent
    468  // allocation
    469  for (int32_t i = 0; i < numRelative; i++) {
    470    int32_t j = relative[i];
    471    aValues[j] = NSToCoordRound((float)aSpecs[j].mValue * (float)relativeMax /
    472                                (float)relativeSums);
    473    relativeTotal += aValues[j];
    474  }
    475 
    476  // scale the relative sizes if they take up too much or too little
    477  if (relativeTotal != relativeMax) {
    478    Scale(relativeMax, numRelative, relative, aValues);
    479  }
    480 }
    481 
    482 /**
    483 * Translate the rows/cols integer sizes into an array of specs for
    484 * each cell in the frameset.  Reverse of CalculateRowCol() behaviour.
    485 * This allows us to maintain the user size info through reflows.
    486 */
    487 void nsHTMLFramesetFrame::GenerateRowCol(
    488    nsPresContext* aPresContext, nscoord aSize,
    489    const mozilla::Span<const nsFramesetSpec>& aSpecs,
    490    const nsTArray<nscoord>& aValues, nsString& aNewAttr) {
    491  MOZ_ASSERT(aSpecs.Length() == aValues.Length());
    492 
    493  for (size_t i = 0; i < aSpecs.Length(); i++) {
    494    if (!aNewAttr.IsEmpty()) {
    495      aNewAttr.Append(char16_t(','));
    496    }
    497 
    498    switch (aSpecs[i].mUnit) {
    499      case eFramesetUnit_Fixed:
    500        aNewAttr.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(aValues[i]));
    501        break;
    502      case eFramesetUnit_Percent:  // XXX Only accurate to 1%, need 1 pixel
    503      case eFramesetUnit_Relative:
    504        // Add 0.5 to the percentage to make rounding work right.
    505        aNewAttr.AppendInt(uint32_t((100.0 * aValues[i]) / aSize + 0.5));
    506        aNewAttr.Append(char16_t('%'));
    507        break;
    508    }
    509  }
    510 }
    511 
    512 int32_t nsHTMLFramesetFrame::GetBorderWidth(nsPresContext* aPresContext,
    513                                            bool aTakeForcingIntoAccount) {
    514  nsFrameborder frameborder = GetFrameBorder();
    515  if (frameborder == eFrameborder_No) {
    516    return 0;
    517  }
    518  nsGenericHTMLElement* content = nsGenericHTMLElement::FromNode(mContent);
    519 
    520  if (content) {
    521    const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::border);
    522    if (attr) {
    523      int32_t intVal = 0;
    524      if (attr->Type() == nsAttrValue::eInteger) {
    525        intVal = attr->GetIntegerValue();
    526        if (intVal < 0) {
    527          intVal = 0;
    528        }
    529      }
    530 
    531      return nsPresContext::CSSPixelsToAppUnits(intVal);
    532    }
    533  }
    534 
    535  if (mParentBorderWidth >= 0) {
    536    return mParentBorderWidth;
    537  }
    538 
    539  return nsPresContext::CSSPixelsToAppUnits(DEFAULT_BORDER_WIDTH_PX);
    540 }
    541 
    542 void nsHTMLFramesetFrame::GetDesiredSize(nsPresContext* aPresContext,
    543                                         const ReflowInput& aReflowInput,
    544                                         ReflowOutput& aDesiredSize) {
    545  WritingMode wm = aReflowInput.GetWritingMode();
    546  LogicalSize desiredSize(wm);
    547  nsHTMLFramesetFrame* framesetParent = do_QueryFrame(GetParent());
    548  if (nullptr == framesetParent) {
    549    if (aPresContext->IsPaginated()) {
    550      // XXX This needs to be changed when framesets paginate properly
    551      desiredSize.ISize(wm) = aReflowInput.AvailableISize();
    552      desiredSize.BSize(wm) = aReflowInput.AvailableBSize();
    553    } else {
    554      LogicalSize area(wm, aPresContext->GetVisibleArea().Size());
    555 
    556      desiredSize.ISize(wm) = area.ISize(wm);
    557      desiredSize.BSize(wm) = area.BSize(wm);
    558    }
    559  } else {
    560    LogicalSize size(wm);
    561    framesetParent->GetSizeOfChild(this, wm, size);
    562    desiredSize.ISize(wm) = size.ISize(wm);
    563    desiredSize.BSize(wm) = size.BSize(wm);
    564  }
    565  aDesiredSize.SetSize(wm, desiredSize);
    566 }
    567 
    568 // only valid for non border children
    569 void nsHTMLFramesetFrame::GetSizeOfChildAt(int32_t aIndexInParent,
    570                                           WritingMode aWM, LogicalSize& aSize,
    571                                           nsIntPoint& aCellIndex) {
    572  int32_t row = aIndexInParent / NumCols();
    573  int32_t col =
    574      aIndexInParent -
    575      (row * NumCols());  // remainder from dividing index by NumCols()
    576  if ((row < NumRows()) && (col < NumCols())) {
    577    aSize.ISize(aWM) = mColSizes[col];
    578    aSize.BSize(aWM) = mRowSizes[row];
    579    aCellIndex.x = col;
    580    aCellIndex.y = row;
    581  } else {
    582    aSize.SizeTo(aWM, 0, 0);
    583    aCellIndex.x = aCellIndex.y = 0;
    584  }
    585 }
    586 
    587 // only valid for non border children
    588 void nsHTMLFramesetFrame::GetSizeOfChild(nsIFrame* aChild, WritingMode aWM,
    589                                         LogicalSize& aSize) {
    590  // Reflow only creates children frames for <frameset> and <frame> content.
    591  // this assumption is used here
    592  int i = 0;
    593  for (nsIFrame* child : mFrames) {
    594    if (aChild == child) {
    595      nsIntPoint ignore;
    596      GetSizeOfChildAt(i, aWM, aSize, ignore);
    597      return;
    598    }
    599    i++;
    600  }
    601  aSize.SizeTo(aWM, 0, 0);
    602 }
    603 
    604 nsresult nsHTMLFramesetFrame::HandleEvent(nsPresContext* aPresContext,
    605                                          WidgetGUIEvent* aEvent,
    606                                          nsEventStatus* aEventStatus) {
    607  NS_ENSURE_ARG_POINTER(aEventStatus);
    608  if (mDragger) {
    609    // the nsFramesetBorderFrame has captured NS_MOUSE_DOWN
    610    switch (aEvent->mMessage) {
    611      case eMouseMove:
    612        MouseDrag(aPresContext, aEvent);
    613        break;
    614      case eMouseUp:
    615        if (aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) {
    616          EndMouseDrag(aPresContext);
    617        }
    618        break;
    619      default:
    620        break;
    621    }
    622    *aEventStatus = nsEventStatus_eConsumeNoDefault;
    623  } else {
    624    *aEventStatus = nsEventStatus_eIgnore;
    625  }
    626  return NS_OK;
    627 }
    628 
    629 nsIFrame::Cursor nsHTMLFramesetFrame::GetCursor(const nsPoint&) {
    630  auto kind = StyleCursorKind::Default;
    631  if (mDragger) {
    632    kind = mDragger->mVertical ? StyleCursorKind::EwResize
    633                               : StyleCursorKind::NsResize;
    634  }
    635  return Cursor{kind, AllowCustomCursorImage::No};
    636 }
    637 
    638 void nsHTMLFramesetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
    639                                           const nsDisplayListSet& aLists) {
    640  BuildDisplayListForInline(aBuilder, aLists);
    641 
    642  if (mDragger && aBuilder->IsForEventDelivery()) {
    643    aLists.Content()->AppendNewToTop<nsDisplayEventReceiver>(aBuilder, this);
    644  }
    645 }
    646 
    647 void nsHTMLFramesetFrame::ReflowPlaceChild(nsIFrame* aChild,
    648                                           nsPresContext* aPresContext,
    649                                           const ReflowInput& aReflowInput,
    650                                           nsPoint& aOffset, nsSize& aSize,
    651                                           nsIntPoint* aCellIndex) {
    652  // reflow the child
    653  ReflowInput reflowInput(aPresContext, aReflowInput, aChild,
    654                          LogicalSize(aChild->GetWritingMode(), aSize));
    655  reflowInput.SetComputedWidth(std::max(
    656      0,
    657      aSize.width - reflowInput.ComputedPhysicalBorderPadding().LeftRight()));
    658  reflowInput.SetComputedHeight(std::max(
    659      0,
    660      aSize.height - reflowInput.ComputedPhysicalBorderPadding().TopBottom()));
    661  ReflowOutput reflowOutput(aReflowInput);
    662  reflowOutput.Width() = aSize.width;
    663  reflowOutput.Height() = aSize.height;
    664  nsReflowStatus status;
    665 
    666  ReflowChild(aChild, aPresContext, reflowOutput, reflowInput, aOffset.x,
    667              aOffset.y, ReflowChildFlags::Default, status);
    668  NS_ASSERTION(status.IsComplete(), "bad status");
    669 
    670  // Place and size the child
    671  reflowOutput.Width() = aSize.width;
    672  reflowOutput.Height() = aSize.height;
    673  FinishReflowChild(aChild, aPresContext, reflowOutput, &reflowInput, aOffset.x,
    674                    aOffset.y, ReflowChildFlags::Default);
    675 }
    676 
    677 static nsFrameborder GetFrameBorderHelper(nsGenericHTMLElement* aContent) {
    678  if (nullptr != aContent) {
    679    const nsAttrValue* attr = aContent->GetParsedAttr(nsGkAtoms::frameborder);
    680    if (attr && attr->Type() == nsAttrValue::eEnum) {
    681      switch (static_cast<FrameBorderProperty>(attr->GetEnumValue())) {
    682        case FrameBorderProperty::Yes:
    683        case FrameBorderProperty::One:
    684          return eFrameborder_Yes;
    685 
    686        case FrameBorderProperty::No:
    687        case FrameBorderProperty::Zero:
    688          return eFrameborder_No;
    689      }
    690    }
    691  }
    692  return eFrameborder_Notset;
    693 }
    694 
    695 nsFrameborder nsHTMLFramesetFrame::GetFrameBorder() {
    696  nsFrameborder result = eFrameborder_Notset;
    697  nsGenericHTMLElement* content = nsGenericHTMLElement::FromNode(mContent);
    698 
    699  if (content) {
    700    result = GetFrameBorderHelper(content);
    701  }
    702  if (eFrameborder_Notset == result) {
    703    return mParentFrameborder;
    704  }
    705  return result;
    706 }
    707 
    708 nsFrameborder nsHTMLFramesetFrame::GetFrameBorder(nsIContent* aContent) {
    709  nsFrameborder result = eFrameborder_Notset;
    710 
    711  nsGenericHTMLElement* content = nsGenericHTMLElement::FromNode(aContent);
    712 
    713  if (content) {
    714    result = GetFrameBorderHelper(content);
    715  }
    716  if (eFrameborder_Notset == result) {
    717    return GetFrameBorder();
    718  }
    719  return result;
    720 }
    721 
    722 nscolor nsHTMLFramesetFrame::GetBorderColor() {
    723  nsGenericHTMLElement* content = nsGenericHTMLElement::FromNode(mContent);
    724 
    725  if (content) {
    726    const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::bordercolor);
    727    if (attr) {
    728      nscolor color;
    729      if (attr->GetColorValue(color)) {
    730        return color;
    731      }
    732    }
    733  }
    734 
    735  return mParentBorderColor;
    736 }
    737 
    738 nscolor nsHTMLFramesetFrame::GetBorderColor(nsIContent* aContent) {
    739  nsGenericHTMLElement* content = nsGenericHTMLElement::FromNode(aContent);
    740 
    741  if (content) {
    742    const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::bordercolor);
    743    if (attr) {
    744      nscolor color;
    745      if (attr->GetColorValue(color)) {
    746        return color;
    747      }
    748    }
    749  }
    750  return GetBorderColor();
    751 }
    752 
    753 void nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext,
    754                                 ReflowOutput& aDesiredSize,
    755                                 const ReflowInput& aReflowInput,
    756                                 nsReflowStatus& aStatus) {
    757  MarkInReflow();
    758  DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetFrame");
    759  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
    760 
    761  mozilla::PresShell* presShell = aPresContext->PresShell();
    762  ServoStyleSet* styleSet = presShell->StyleSet();
    763 
    764  GetParent()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
    765 
    766  // printf("FramesetFrame2::Reflow %X (%d,%d) \n", this,
    767  // aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight());
    768  // Always get the size so that the caller knows how big we are
    769  GetDesiredSize(aPresContext, aReflowInput, aDesiredSize);
    770 
    771  nscoord width = (aDesiredSize.Width() <= aReflowInput.AvailableWidth())
    772                      ? aDesiredSize.Width()
    773                      : aReflowInput.AvailableWidth();
    774  nscoord height = (aDesiredSize.Height() <= aReflowInput.AvailableHeight())
    775                       ? aDesiredSize.Height()
    776                       : aReflowInput.AvailableHeight();
    777 
    778  // We might be reflowed more than once with NS_FRAME_FIRST_REFLOW;
    779  // that's allowed.  (Though it will only happen for misuse of frameset
    780  // that includes it within other content.)  So measure firstTime by
    781  // what we care about, which is whether we've processed the data we
    782  // process below if firstTime is true. We can't assert that IsEmpty()
    783  // is the same for the 2 child arrays, because they can also end up
    784  // empty in Init() if they hit an error state.
    785  MOZ_ASSERT_IF(!mChildFrameborder.IsEmpty(), mNeedFirstReflowWork);
    786  MOZ_ASSERT_IF(!mChildBorderColors.IsEmpty(), mNeedFirstReflowWork);
    787  bool firstTime = mNeedFirstReflowWork;
    788 
    789  // subtract out the width of all of the potential borders. There are
    790  // only borders between <frame>s. There are none on the edges (e.g the
    791  // leftmost <frame> has no left border).
    792  int32_t borderWidth = GetBorderWidth(aPresContext, true);
    793 
    794  width -= (NumCols() - 1) * borderWidth;
    795  if (width < 0) {
    796    width = 0;
    797  }
    798 
    799  height -= (NumRows() - 1) * borderWidth;
    800  if (height < 0) {
    801    height = 0;
    802  }
    803 
    804  HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromNode(mContent);
    805  NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
    806  auto rowSpecs = ourContent->GetRowSpec();
    807  auto colSpecs = ourContent->GetColSpec();
    808  // If the number of cols or rows has changed, the frame for the frameset
    809  // will be re-created.
    810  if (CheckedInt<size_t>(NumRows()).value() != rowSpecs.Length() ||
    811      CheckedInt<size_t>(NumCols()).value() != colSpecs.Length()) {
    812    mDrag.UnSet();
    813    return;
    814  }
    815 
    816  CalculateRowCol(aPresContext, width, colSpecs, mColSizes);
    817  CalculateRowCol(aPresContext, height, rowSpecs, mRowSizes);
    818 
    819  nsTArray<bool> verBordersVis;  // vertical borders visibility
    820  nsTArray<nscolor> verBorderColors;
    821  nsTArray<bool> horBordersVis;  // horizontal borders visibility
    822  nsTArray<nscolor> horBorderColors;
    823  nscolor borderColor = GetBorderColor();
    824  nsFrameborder frameborder = GetFrameBorder();
    825 
    826  if (firstTime) {
    827    // Check for overflow in memory allocations using NumCols() and NumRows()
    828    // which have a maxium value of NS_MAX_FRAMESET_SPEC_COUNT.
    829    static_assert(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(bool),
    830                  "Check for overflow");
    831    static_assert(NS_MAX_FRAMESET_SPEC_COUNT < UINT_MAX / sizeof(nscolor),
    832                  "Check for overflow");
    833 
    834    verBordersVis.SetLength(NumCols());
    835    verBorderColors.SetLength(NumCols());
    836    for (int32_t verX = 0; verX < NumCols(); verX++) {
    837      verBordersVis[verX] = false;
    838      verBorderColors[verX] = NO_COLOR;
    839    }
    840 
    841    horBordersVis.SetLength(NumRows());
    842    horBorderColors.SetLength(NumRows());
    843    for (int32_t horX = 0; horX < NumRows(); horX++) {
    844      horBordersVis[horX] = false;
    845      horBorderColors[horX] = NO_COLOR;
    846    }
    847  }
    848 
    849  // reflow the children
    850  int32_t lastRow = 0;
    851  int32_t lastCol = 0;
    852  int32_t borderChildX = mNonBorderChildCount;  // index of border children
    853  nsHTMLFramesetBorderFrame* borderFrame = nullptr;
    854  nsPoint offset(0, 0);
    855  nsSize size, lastSize;
    856  WritingMode wm = GetWritingMode();
    857  LogicalSize logicalSize(wm);
    858  nsIFrame* child = mFrames.FirstChild();
    859 
    860  for (int32_t childX = 0; childX < mNonBorderChildCount; childX++) {
    861    nsIntPoint cellIndex;
    862    GetSizeOfChildAt(childX, wm, logicalSize, cellIndex);
    863    size = logicalSize.GetPhysicalSize(wm);
    864 
    865    if (lastRow != cellIndex.y) {  // changed to next row
    866      offset.x = 0;
    867      offset.y += lastSize.height;
    868      if (firstTime) {  // create horizontal border
    869 
    870        RefPtr<ComputedStyle> pseudoComputedStyle;
    871        pseudoComputedStyle = styleSet->ResolveNonInheritingAnonymousBoxStyle(
    872            PseudoStyleType::horizontalFramesetBorder);
    873 
    874        borderFrame = new (presShell) nsHTMLFramesetBorderFrame(
    875            pseudoComputedStyle, PresContext(), borderWidth, false, false);
    876        borderFrame->Init(mContent, this, nullptr);
    877        mChildCount++;
    878        mFrames.AppendFrame(nullptr, borderFrame);
    879        mHorBorders[cellIndex.y - 1] = borderFrame;
    880        // set the neighbors for determining drag boundaries
    881        borderFrame->mPrevNeighbor = lastRow;
    882        borderFrame->mNextNeighbor = cellIndex.y;
    883      } else {
    884        borderFrame = (nsHTMLFramesetBorderFrame*)mFrames.FrameAt(borderChildX);
    885        borderFrame->mWidth = borderWidth;
    886        borderChildX++;
    887      }
    888      nsSize borderSize(aDesiredSize.Width(), borderWidth);
    889      ReflowPlaceChild(borderFrame, aPresContext, aReflowInput, offset,
    890                       borderSize);
    891      borderFrame = nullptr;
    892      offset.y += borderWidth;
    893    } else {
    894      if (cellIndex.x > 0) {     // moved to next col in same row
    895        if (0 == cellIndex.y) {  // in 1st row
    896          if (firstTime) {       // create vertical border
    897 
    898            RefPtr<ComputedStyle> pseudoComputedStyle;
    899            pseudoComputedStyle =
    900                styleSet->ResolveNonInheritingAnonymousBoxStyle(
    901                    PseudoStyleType::verticalFramesetBorder);
    902 
    903            borderFrame = new (presShell) nsHTMLFramesetBorderFrame(
    904                pseudoComputedStyle, PresContext(), borderWidth, true, false);
    905            borderFrame->Init(mContent, this, nullptr);
    906            mChildCount++;
    907            mFrames.AppendFrame(nullptr, borderFrame);
    908            mVerBorders[cellIndex.x - 1] = borderFrame;
    909            // set the neighbors for determining drag boundaries
    910            borderFrame->mPrevNeighbor = lastCol;
    911            borderFrame->mNextNeighbor = cellIndex.x;
    912          } else {
    913            borderFrame =
    914                (nsHTMLFramesetBorderFrame*)mFrames.FrameAt(borderChildX);
    915            borderFrame->mWidth = borderWidth;
    916            borderChildX++;
    917          }
    918          nsSize borderSize(borderWidth, aDesiredSize.Height());
    919          ReflowPlaceChild(borderFrame, aPresContext, aReflowInput, offset,
    920                           borderSize);
    921          borderFrame = nullptr;
    922        }
    923        offset.x += borderWidth;
    924      }
    925    }
    926 
    927    ReflowPlaceChild(child, aPresContext, aReflowInput, offset, size,
    928                     &cellIndex);
    929 
    930    if (firstTime) {
    931      int32_t childVis;
    932      nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(child);
    933      if (framesetFrame) {
    934        childVis = framesetFrame->mEdgeVisibility;
    935        mChildBorderColors[childX] = framesetFrame->mEdgeColors;
    936      } else if (child->IsSubDocumentFrame()) {
    937        if (eFrameborder_Yes == mChildFrameborder[childX]) {
    938          childVis = ALL_VIS;
    939        } else if (eFrameborder_No == mChildFrameborder[childX]) {
    940          childVis = NONE_VIS;
    941        } else {  // notset
    942          childVis = (eFrameborder_No == frameborder) ? NONE_VIS : ALL_VIS;
    943        }
    944      } else {  // blank
    945 #ifdef DEBUG
    946        nsHTMLFramesetBlankFrame* blank = do_QueryFrame(child);
    947        MOZ_ASSERT(blank, "unexpected child frame type");
    948 #endif
    949        childVis = NONE_VIS;
    950      }
    951      nsBorderColor childColors = mChildBorderColors[childX];
    952      // set the visibility, color of our edge borders based on children
    953      if (0 == cellIndex.x) {
    954        if (!(mEdgeVisibility & LEFT_VIS)) {
    955          mEdgeVisibility |= (LEFT_VIS & childVis);
    956        }
    957        if (NO_COLOR == mEdgeColors.mLeft) {
    958          mEdgeColors.mLeft = childColors.mLeft;
    959        }
    960      }
    961      if (0 == cellIndex.y) {
    962        if (!(mEdgeVisibility & TOP_VIS)) {
    963          mEdgeVisibility |= (TOP_VIS & childVis);
    964        }
    965        if (NO_COLOR == mEdgeColors.mTop) {
    966          mEdgeColors.mTop = childColors.mTop;
    967        }
    968      }
    969      if (NumCols() - 1 == cellIndex.x) {
    970        if (!(mEdgeVisibility & RIGHT_VIS)) {
    971          mEdgeVisibility |= (RIGHT_VIS & childVis);
    972        }
    973        if (NO_COLOR == mEdgeColors.mRight) {
    974          mEdgeColors.mRight = childColors.mRight;
    975        }
    976      }
    977      if (NumRows() - 1 == cellIndex.y) {
    978        if (!(mEdgeVisibility & BOTTOM_VIS)) {
    979          mEdgeVisibility |= (BOTTOM_VIS & childVis);
    980        }
    981        if (NO_COLOR == mEdgeColors.mBottom) {
    982          mEdgeColors.mBottom = childColors.mBottom;
    983        }
    984      }
    985      // set the visibility of borders that the child may affect
    986      if (childVis & RIGHT_VIS) {
    987        verBordersVis[cellIndex.x] = true;
    988      }
    989      if (childVis & BOTTOM_VIS) {
    990        horBordersVis[cellIndex.y] = true;
    991      }
    992      if ((cellIndex.x > 0) && (childVis & LEFT_VIS)) {
    993        verBordersVis[cellIndex.x - 1] = true;
    994      }
    995      if ((cellIndex.y > 0) && (childVis & TOP_VIS)) {
    996        horBordersVis[cellIndex.y - 1] = true;
    997      }
    998      // set the colors of borders that the child may affect
    999      if (NO_COLOR == verBorderColors[cellIndex.x]) {
   1000        verBorderColors[cellIndex.x] = mChildBorderColors[childX].mRight;
   1001      }
   1002      if (NO_COLOR == horBorderColors[cellIndex.y]) {
   1003        horBorderColors[cellIndex.y] = mChildBorderColors[childX].mBottom;
   1004      }
   1005      if ((cellIndex.x > 0) && (NO_COLOR == verBorderColors[cellIndex.x - 1])) {
   1006        verBorderColors[cellIndex.x - 1] = mChildBorderColors[childX].mLeft;
   1007      }
   1008      if ((cellIndex.y > 0) && (NO_COLOR == horBorderColors[cellIndex.y - 1])) {
   1009        horBorderColors[cellIndex.y - 1] = mChildBorderColors[childX].mTop;
   1010      }
   1011    }
   1012    lastRow = cellIndex.y;
   1013    lastCol = cellIndex.x;
   1014    lastSize = size;
   1015    offset.x += size.width;
   1016    child = child->GetNextSibling();
   1017  }
   1018 
   1019  if (firstTime) {
   1020    nscolor childColor;
   1021    // set the visibility, color, mouse sensitivity of borders
   1022    for (int32_t verX = 0; verX < NumCols() - 1; verX++) {
   1023      if (mVerBorders[verX]) {
   1024        mVerBorders[verX]->SetVisibility(verBordersVis[verX]);
   1025        SetBorderResize(mVerBorders[verX]);
   1026        childColor = (NO_COLOR == verBorderColors[verX])
   1027                         ? borderColor
   1028                         : verBorderColors[verX];
   1029        mVerBorders[verX]->SetColor(childColor);
   1030      }
   1031    }
   1032    for (int32_t horX = 0; horX < NumRows() - 1; horX++) {
   1033      if (mHorBorders[horX]) {
   1034        mHorBorders[horX]->SetVisibility(horBordersVis[horX]);
   1035        SetBorderResize(mHorBorders[horX]);
   1036        childColor = (NO_COLOR == horBorderColors[horX])
   1037                         ? borderColor
   1038                         : horBorderColors[horX];
   1039        mHorBorders[horX]->SetColor(childColor);
   1040      }
   1041    }
   1042 
   1043    mNeedFirstReflowWork = false;
   1044    mChildFrameborder.Clear();
   1045    mChildBorderColors.Clear();
   1046  }
   1047 
   1048  mDrag.UnSet();
   1049 
   1050  aDesiredSize.SetOverflowAreasToDesiredBounds();
   1051  FinishAndStoreOverflow(&aDesiredSize);
   1052 }
   1053 
   1054 #ifdef DEBUG_FRAME_DUMP
   1055 nsresult nsHTMLFramesetFrame::GetFrameName(nsAString& aResult) const {
   1056  return MakeFrameName(u"Frameset"_ns, aResult);
   1057 }
   1058 #endif
   1059 
   1060 bool nsHTMLFramesetFrame::CanResize(bool aVertical, bool aLeft) {
   1061  int32_t childX;
   1062  int32_t startX;
   1063  if (aVertical) {
   1064    startX = (aLeft) ? 0 : NumCols() - 1;
   1065    for (childX = startX; childX < mNonBorderChildCount; childX += NumCols()) {
   1066      if (!CanChildResize(aVertical, aLeft, childX)) {
   1067        return false;
   1068      }
   1069    }
   1070  } else {
   1071    startX = (aLeft) ? 0 : (NumRows() - 1) * NumCols();
   1072    int32_t endX = startX + NumCols();
   1073    for (childX = startX; childX < endX; childX++) {
   1074      if (!CanChildResize(aVertical, aLeft, childX)) {
   1075        return false;
   1076      }
   1077    }
   1078  }
   1079  return true;
   1080 }
   1081 
   1082 bool nsHTMLFramesetFrame::GetNoResize(nsIFrame* aChildFrame) {
   1083  nsIContent* content = aChildFrame->GetContent();
   1084 
   1085  return content && content->IsElement() &&
   1086         content->AsElement()->HasAttr(nsGkAtoms::noresize);
   1087 }
   1088 
   1089 bool nsHTMLFramesetFrame::CanChildResize(bool aVertical, bool aLeft,
   1090                                         int32_t aChildX) {
   1091  nsIFrame* child = mFrames.FrameAt(aChildX);
   1092  nsHTMLFramesetFrame* frameset = do_QueryFrame(child);
   1093  return frameset ? frameset->CanResize(aVertical, aLeft) : !GetNoResize(child);
   1094 }
   1095 
   1096 // This calculates and sets the resizability of all border frames
   1097 
   1098 void nsHTMLFramesetFrame::RecalculateBorderResize() {
   1099  if (!mContent) {
   1100    return;
   1101  }
   1102 
   1103  static_assert(
   1104      NS_MAX_FRAMESET_SPEC_COUNT < INT32_MAX / NS_MAX_FRAMESET_SPEC_COUNT,
   1105      "Check for overflow");
   1106  static_assert(NS_MAX_FRAMESET_SPEC_COUNT <
   1107                    UINT_MAX / sizeof(int32_t) / NS_MAX_FRAMESET_SPEC_COUNT,
   1108                "Check for overflow");
   1109  // set the visibility and mouse sensitivity of borders
   1110  for (int32_t verX = 0; verX < NumCols() - 1; verX++) {
   1111    if (mVerBorders[verX]) {
   1112      mVerBorders[verX]->mCanResize = true;
   1113      SetBorderResize(mVerBorders[verX]);
   1114    }
   1115  }
   1116  for (int32_t horX = 0; horX < NumRows() - 1; horX++) {
   1117    if (mHorBorders[horX]) {
   1118      mHorBorders[horX]->mCanResize = true;
   1119      SetBorderResize(mHorBorders[horX]);
   1120    }
   1121  }
   1122 }
   1123 
   1124 void nsHTMLFramesetFrame::SetBorderResize(
   1125    nsHTMLFramesetBorderFrame* aBorderFrame) {
   1126  if (aBorderFrame->mVertical) {
   1127    for (int32_t rowX = 0; rowX < NumRows(); rowX++) {
   1128      int32_t childX = aBorderFrame->mPrevNeighbor + (rowX * NumCols());
   1129      if (!CanChildResize(true, false, childX) ||
   1130          !CanChildResize(true, true, childX + 1)) {
   1131        aBorderFrame->mCanResize = false;
   1132      }
   1133    }
   1134  } else {
   1135    int32_t childX = aBorderFrame->mPrevNeighbor * NumCols();
   1136    int32_t endX = childX + NumCols();
   1137    for (; childX < endX; childX++) {
   1138      if (!CanChildResize(false, false, childX)) {
   1139        aBorderFrame->mCanResize = false;
   1140      }
   1141    }
   1142    endX = endX + NumCols();
   1143    for (; childX < endX; childX++) {
   1144      if (!CanChildResize(false, true, childX)) {
   1145        aBorderFrame->mCanResize = false;
   1146      }
   1147    }
   1148  }
   1149 }
   1150 
   1151 int32_t nsHTMLFramesetFrame::NumRows() const {
   1152  return CheckedInt<int32_t>(mRowSizes.Length()).value();
   1153 }
   1154 
   1155 int32_t nsHTMLFramesetFrame::NumCols() const {
   1156  return CheckedInt<int32_t>(mColSizes.Length()).value();
   1157 }
   1158 
   1159 void nsHTMLFramesetFrame::StartMouseDrag(nsPresContext* aPresContext,
   1160                                         nsHTMLFramesetBorderFrame* aBorder,
   1161                                         WidgetGUIEvent* aEvent) {
   1162 #if 0
   1163  int32_t index;
   1164  IndexOf(aBorder, index);
   1165  NS_ASSERTION((nullptr != aBorder) && (index >= 0), "invalid dragger");
   1166 #endif
   1167 
   1168  PresShell::SetCapturingContent(GetContent(),
   1169                                 CaptureFlags::IgnoreAllowedState);
   1170 
   1171  mDragger = aBorder;
   1172 
   1173  mFirstDragPoint = aEvent->mRefPoint;
   1174 
   1175  // Store the original frame sizes
   1176  if (mDragger->mVertical) {
   1177    mPrevNeighborOrigSize = mColSizes[mDragger->mPrevNeighbor];
   1178    mNextNeighborOrigSize = mColSizes[mDragger->mNextNeighbor];
   1179  } else {
   1180    mPrevNeighborOrigSize = mRowSizes[mDragger->mPrevNeighbor];
   1181    mNextNeighborOrigSize = mRowSizes[mDragger->mNextNeighbor];
   1182  }
   1183 
   1184  gDragInProgress = true;
   1185 }
   1186 
   1187 void nsHTMLFramesetFrame::MouseDrag(nsPresContext* aPresContext,
   1188                                    WidgetGUIEvent* aEvent) {
   1189  // if the capture ended, reset the drag state
   1190  if (PresShell::GetCapturingContent() != GetContent()) {
   1191    mDragger = nullptr;
   1192    gDragInProgress = false;
   1193    return;
   1194  }
   1195 
   1196  int32_t change;  // measured positive from left-to-right or top-to-bottom
   1197  AutoWeakFrame weakFrame(this);
   1198  if (mDragger->mVertical) {
   1199    change = aPresContext->DevPixelsToAppUnits(aEvent->mRefPoint.x -
   1200                                               mFirstDragPoint.x);
   1201    if (change > mNextNeighborOrigSize - mMinDrag) {
   1202      change = mNextNeighborOrigSize - mMinDrag;
   1203    } else if (change <= mMinDrag - mPrevNeighborOrigSize) {
   1204      change = mMinDrag - mPrevNeighborOrigSize;
   1205    }
   1206    mColSizes[mDragger->mPrevNeighbor] = mPrevNeighborOrigSize + change;
   1207    mColSizes[mDragger->mNextNeighbor] = mNextNeighborOrigSize - change;
   1208 
   1209    if (change != 0) {
   1210      // Recompute the specs from the new sizes.
   1211      nscoord width =
   1212          mRect.width - (NumCols() - 1) * GetBorderWidth(aPresContext, true);
   1213      HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromNode(mContent);
   1214      NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
   1215      auto colSpecs = ourContent->GetColSpec();
   1216      nsAutoString newColAttr;
   1217      GenerateRowCol(aPresContext, width, colSpecs, mColSizes, newColAttr);
   1218      // Setting the attr will trigger a reflow
   1219      mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::cols,
   1220                                     newColAttr, true);
   1221    }
   1222  } else {
   1223    change = aPresContext->DevPixelsToAppUnits(aEvent->mRefPoint.y -
   1224                                               mFirstDragPoint.y);
   1225    if (change > mNextNeighborOrigSize - mMinDrag) {
   1226      change = mNextNeighborOrigSize - mMinDrag;
   1227    } else if (change <= mMinDrag - mPrevNeighborOrigSize) {
   1228      change = mMinDrag - mPrevNeighborOrigSize;
   1229    }
   1230    mRowSizes[mDragger->mPrevNeighbor] = mPrevNeighborOrigSize + change;
   1231    mRowSizes[mDragger->mNextNeighbor] = mNextNeighborOrigSize - change;
   1232 
   1233    if (change != 0) {
   1234      // Recompute the specs from the new sizes.
   1235      nscoord height =
   1236          mRect.height - (NumRows() - 1) * GetBorderWidth(aPresContext, true);
   1237      HTMLFrameSetElement* ourContent = HTMLFrameSetElement::FromNode(mContent);
   1238      NS_ASSERTION(ourContent, "Someone gave us a broken frameset element!");
   1239      Span<const nsFramesetSpec> rowSpecs = ourContent->GetRowSpec();
   1240      nsAutoString newRowAttr;
   1241      GenerateRowCol(aPresContext, height, rowSpecs, mRowSizes, newRowAttr);
   1242      // Setting the attr will trigger a reflow
   1243      mContent->AsElement()->SetAttr(kNameSpaceID_None, nsGkAtoms::rows,
   1244                                     newRowAttr, true);
   1245    }
   1246  }
   1247 
   1248  NS_ENSURE_TRUE_VOID(weakFrame.IsAlive());
   1249  if (change != 0) {
   1250    mDrag.Reset(mDragger->mVertical, mDragger->mPrevNeighbor, change, this);
   1251  }
   1252 }
   1253 
   1254 void nsHTMLFramesetFrame::EndMouseDrag(nsPresContext* aPresContext) {
   1255  PresShell::ReleaseCapturingContent();
   1256  mDragger = nullptr;
   1257  gDragInProgress = false;
   1258 }
   1259 
   1260 nsIFrame* NS_NewHTMLFramesetFrame(PresShell* aPresShell,
   1261                                  ComputedStyle* aStyle) {
   1262 #ifdef DEBUG
   1263  const nsStyleDisplay* disp = aStyle->StyleDisplay();
   1264  NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle() && !disp->IsFloatingStyle(),
   1265               "Framesets should not be positioned and should not float");
   1266 #endif
   1267 
   1268  return new (aPresShell)
   1269      nsHTMLFramesetFrame(aStyle, aPresShell->GetPresContext());
   1270 }
   1271 
   1272 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetFrame)
   1273 
   1274 /*******************************************************************************
   1275 * nsHTMLFramesetBorderFrame
   1276 ******************************************************************************/
   1277 nsHTMLFramesetBorderFrame::nsHTMLFramesetBorderFrame(
   1278    ComputedStyle* aStyle, nsPresContext* aPresContext, int32_t aWidth,
   1279    bool aVertical, bool aVisibility)
   1280    : nsLeafFrame(aStyle, aPresContext, kClassID),
   1281      mWidth(aWidth),
   1282      mVertical(aVertical),
   1283      mVisibility(aVisibility) {
   1284  mCanResize = true;
   1285  mColor = NO_COLOR;
   1286  mPrevNeighbor = 0;
   1287  mNextNeighbor = 0;
   1288 }
   1289 
   1290 nsHTMLFramesetBorderFrame::~nsHTMLFramesetBorderFrame() {
   1291  // printf("nsHTMLFramesetBorderFrame destructor %p \n", this);
   1292 }
   1293 
   1294 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetBorderFrame)
   1295 
   1296 void nsHTMLFramesetBorderFrame::SetVisibility(bool aVisibility) {
   1297  mVisibility = aVisibility;
   1298 }
   1299 
   1300 void nsHTMLFramesetBorderFrame::SetColor(nscolor aColor) { mColor = aColor; }
   1301 
   1302 void nsHTMLFramesetBorderFrame::Reflow(nsPresContext* aPresContext,
   1303                                       ReflowOutput& aDesiredSize,
   1304                                       const ReflowInput& aReflowInput,
   1305                                       nsReflowStatus& aStatus) {
   1306  DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBorderFrame");
   1307  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
   1308 
   1309  // Override Reflow(), since we don't want to deal with what our
   1310  // computed values are. We just size to our available size.
   1311  aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
   1312                       aReflowInput.AvailableSize());
   1313  aDesiredSize.SetOverflowAreasToDesiredBounds();
   1314  FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
   1315 }
   1316 
   1317 class nsDisplayFramesetBorder final : public nsPaintedDisplayItem {
   1318 public:
   1319  nsDisplayFramesetBorder(nsDisplayListBuilder* aBuilder,
   1320                          nsHTMLFramesetBorderFrame* aFrame)
   1321      : nsPaintedDisplayItem(aBuilder, aFrame) {
   1322    MOZ_COUNT_CTOR(nsDisplayFramesetBorder);
   1323  }
   1324 
   1325  MOZ_COUNTED_DTOR_FINAL(nsDisplayFramesetBorder)
   1326 
   1327  // REVIEW: see old GetFrameForPoint
   1328  // Receives events in its bounds
   1329  void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   1330               HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override {
   1331    if (ShouldIgnoreForBackfaceHidden(aState)) {
   1332      return;
   1333    }
   1334 
   1335    aOutFrames->AppendElement(mFrame);
   1336  }
   1337  virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   1338  NS_DISPLAY_DECL_NAME("FramesetBorder", TYPE_FRAMESET_BORDER)
   1339 };
   1340 
   1341 void nsDisplayFramesetBorder::Paint(nsDisplayListBuilder* aBuilder,
   1342                                    gfxContext* aCtx) {
   1343  static_cast<nsHTMLFramesetBorderFrame*>(mFrame)->PaintBorder(
   1344      aCtx->GetDrawTarget(), ToReferenceFrame());
   1345 }
   1346 
   1347 void nsHTMLFramesetBorderFrame::BuildDisplayList(
   1348    nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) {
   1349  aLists.Content()->AppendNewToTop<nsDisplayFramesetBorder>(aBuilder, this);
   1350 }
   1351 
   1352 void nsHTMLFramesetBorderFrame::PaintBorder(DrawTarget* aDrawTarget,
   1353                                            nsPoint aPt) {
   1354  nscoord widthInPixels = nsPresContext::AppUnitsToIntCSSPixels(mWidth);
   1355  nscoord pixelWidth = nsPresContext::CSSPixelsToAppUnits(1);
   1356 
   1357  if (widthInPixels <= 0) {
   1358    return;
   1359  }
   1360 
   1361  ColorPattern bgColor(ToDeviceColor(LookAndFeel::Color(
   1362      LookAndFeel::ColorID::Window, this, NS_RGB(200, 200, 200))));
   1363 
   1364  ColorPattern fgColor(ToDeviceColor(LookAndFeel::Color(
   1365      LookAndFeel::ColorID::Windowtext, this, NS_RGB(0, 0, 0))));
   1366 
   1367  ColorPattern hltColor(ToDeviceColor(LookAndFeel::Color(
   1368      LookAndFeel::ColorID::Threedhighlight, this, NS_RGB(255, 255, 255))));
   1369 
   1370  ColorPattern sdwColor(ToDeviceColor(LookAndFeel::Color(
   1371      LookAndFeel::ColorID::Threedshadow, this, NS_RGB(128, 128, 128))));
   1372 
   1373  ColorPattern color(ToDeviceColor(NS_RGB(255, 255, 255)));  // default to white
   1374  if (mVisibility) {
   1375    color =
   1376        (NO_COLOR == mColor) ? bgColor : ColorPattern(ToDeviceColor(mColor));
   1377  }
   1378 
   1379  int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
   1380 
   1381  Point toRefFrame = NSPointToPoint(aPt, appUnitsPerDevPixel);
   1382 
   1383  AutoRestoreTransform autoRestoreTransform(aDrawTarget);
   1384  aDrawTarget->SetTransform(
   1385      aDrawTarget->GetTransform().PreTranslate(toRefFrame));
   1386 
   1387  nsPoint start(0, 0);
   1388  nsPoint end = mVertical ? nsPoint(0, mRect.height) : nsPoint(mRect.width, 0);
   1389 
   1390  // draw grey or white first
   1391  for (int i = 0; i < widthInPixels; i++) {
   1392    StrokeLineWithSnapping(start, end, appUnitsPerDevPixel, *aDrawTarget,
   1393                           color);
   1394    if (mVertical) {
   1395      start.x += pixelWidth;
   1396      end.x = start.x;
   1397    } else {
   1398      start.y += pixelWidth;
   1399      end.y = start.y;
   1400    }
   1401  }
   1402 
   1403  if (!mVisibility) {
   1404    return;
   1405  }
   1406 
   1407  if (widthInPixels >= 5) {
   1408    start.x = (mVertical) ? pixelWidth : 0;
   1409    start.y = (mVertical) ? 0 : pixelWidth;
   1410    end.x = (mVertical) ? start.x : mRect.width;
   1411    end.y = (mVertical) ? mRect.height : start.y;
   1412    StrokeLineWithSnapping(start, end, appUnitsPerDevPixel, *aDrawTarget,
   1413                           hltColor);
   1414  }
   1415 
   1416  if (widthInPixels >= 2) {
   1417    start.x = (mVertical) ? mRect.width - (2 * pixelWidth) : 0;
   1418    start.y = (mVertical) ? 0 : mRect.height - (2 * pixelWidth);
   1419    end.x = (mVertical) ? start.x : mRect.width;
   1420    end.y = (mVertical) ? mRect.height : start.y;
   1421    StrokeLineWithSnapping(start, end, appUnitsPerDevPixel, *aDrawTarget,
   1422                           sdwColor);
   1423  }
   1424 
   1425  if (widthInPixels >= 1) {
   1426    start.x = (mVertical) ? mRect.width - pixelWidth : 0;
   1427    start.y = (mVertical) ? 0 : mRect.height - pixelWidth;
   1428    end.x = (mVertical) ? start.x : mRect.width;
   1429    end.y = (mVertical) ? mRect.height : start.y;
   1430    StrokeLineWithSnapping(start, end, appUnitsPerDevPixel, *aDrawTarget,
   1431                           fgColor);
   1432  }
   1433 }
   1434 
   1435 nsresult nsHTMLFramesetBorderFrame::HandleEvent(nsPresContext* aPresContext,
   1436                                                WidgetGUIEvent* aEvent,
   1437                                                nsEventStatus* aEventStatus) {
   1438  NS_ENSURE_ARG_POINTER(aEventStatus);
   1439  *aEventStatus = nsEventStatus_eIgnore;
   1440 
   1441  // XXX Mouse setting logic removed.  The remaining logic should also move.
   1442  if (!mCanResize) {
   1443    return NS_OK;
   1444  }
   1445 
   1446  if (aEvent->mMessage == eMouseDown &&
   1447      aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary) {
   1448    nsHTMLFramesetFrame* parentFrame = do_QueryFrame(GetParent());
   1449    if (parentFrame) {
   1450      parentFrame->StartMouseDrag(aPresContext, this, aEvent);
   1451      *aEventStatus = nsEventStatus_eConsumeNoDefault;
   1452    }
   1453  }
   1454  return NS_OK;
   1455 }
   1456 
   1457 nsIFrame::Cursor nsHTMLFramesetBorderFrame::GetCursor(const nsPoint&) {
   1458  auto kind = StyleCursorKind::Default;
   1459  if (mCanResize) {
   1460    kind = mVertical ? StyleCursorKind::EwResize : StyleCursorKind::NsResize;
   1461  }
   1462  return Cursor{kind, AllowCustomCursorImage::No};
   1463 }
   1464 
   1465 #ifdef DEBUG_FRAME_DUMP
   1466 nsresult nsHTMLFramesetBorderFrame::GetFrameName(nsAString& aResult) const {
   1467  return MakeFrameName(u"FramesetBorder"_ns, aResult);
   1468 }
   1469 #endif
   1470 
   1471 /*******************************************************************************
   1472 * nsHTMLFramesetBlankFrame
   1473 ******************************************************************************/
   1474 
   1475 NS_QUERYFRAME_HEAD(nsHTMLFramesetBlankFrame)
   1476  NS_QUERYFRAME_ENTRY(nsHTMLFramesetBlankFrame)
   1477 NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame)
   1478 
   1479 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetBlankFrame)
   1480 
   1481 nsHTMLFramesetBlankFrame::~nsHTMLFramesetBlankFrame() {
   1482  // printf("nsHTMLFramesetBlankFrame destructor %p \n", this);
   1483 }
   1484 
   1485 void nsHTMLFramesetBlankFrame::Reflow(nsPresContext* aPresContext,
   1486                                      ReflowOutput& aDesiredSize,
   1487                                      const ReflowInput& aReflowInput,
   1488                                      nsReflowStatus& aStatus) {
   1489  DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBlankFrame");
   1490  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
   1491 
   1492  // Override Reflow(), since we don't want to deal with what our
   1493  // computed values are. We just size to our available size.
   1494  aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
   1495                       aReflowInput.AvailableSize());
   1496  aDesiredSize.SetOverflowAreasToDesiredBounds();
   1497  FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
   1498 }
   1499 
   1500 class nsDisplayFramesetBlank final : public nsPaintedDisplayItem {
   1501 public:
   1502  nsDisplayFramesetBlank(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
   1503      : nsPaintedDisplayItem(aBuilder, aFrame) {
   1504    MOZ_COUNT_CTOR(nsDisplayFramesetBlank);
   1505  }
   1506 
   1507  MOZ_COUNTED_DTOR_FINAL(nsDisplayFramesetBlank)
   1508 
   1509  virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   1510  NS_DISPLAY_DECL_NAME("FramesetBlank", TYPE_FRAMESET_BLANK)
   1511 };
   1512 
   1513 void nsDisplayFramesetBlank::Paint(nsDisplayListBuilder* aBuilder,
   1514                                   gfxContext* aCtx) {
   1515  DrawTarget* drawTarget = aCtx->GetDrawTarget();
   1516  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   1517  Rect rect = NSRectToSnappedRect(GetPaintRect(aBuilder, aCtx),
   1518                                  appUnitsPerDevPixel, *drawTarget);
   1519  ColorPattern white(ToDeviceColor(sRGBColor::OpaqueWhite()));
   1520  drawTarget->FillRect(rect, white);
   1521 }
   1522 
   1523 void nsHTMLFramesetBlankFrame::BuildDisplayList(
   1524    nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists) {
   1525  aLists.Content()->AppendNewToTop<nsDisplayFramesetBlank>(aBuilder, this);
   1526 }