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