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