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/. */
7 /* rendering object for HTML <frameset> elements */
9 #include "nsFrameSetFrame.h"
11 #include "gfxContext.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"
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"
45 using namespace mozilla
;
46 using namespace mozilla::dom
;
47 using namespace mozilla::gfx
;
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
57 /*******************************************************************************
59 ******************************************************************************/
60 nsFramesetDrag::nsFramesetDrag() { UnSet(); }
62 void nsFramesetDrag::Reset(bool aVertical
, int32_t aIndex
, int32_t aChange
,
63 nsHTMLFramesetFrame
* aSource
) {
64 mVertical
= aVertical
;
70 void nsFramesetDrag::UnSet() {
77 /*******************************************************************************
78 * nsHTMLFramesetBorderFrame
79 ******************************************************************************/
80 class nsHTMLFramesetBorderFrame final
: public nsLeafFrame
{
82 NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBorderFrame
)
84 #ifdef DEBUG_FRAME_DUMP
85 virtual nsresult
GetFrameName(nsAString
& aResult
) const override
;
88 virtual nsresult
HandleEvent(nsPresContext
* aPresContext
,
89 WidgetGUIEvent
* aEvent
,
90 nsEventStatus
* aEventStatus
) override
;
92 Maybe
<Cursor
> GetCursor(const nsPoint
&) override
;
94 virtual void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
95 const nsDisplayListSet
& aLists
) override
;
97 virtual void Reflow(nsPresContext
* aPresContext
, ReflowOutput
& aDesiredSize
,
98 const ReflowInput
& aReflowInput
,
99 nsReflowStatus
& aStatus
) override
;
101 bool GetVisibility() { return mVisibility
; }
102 void SetVisibility(bool aVisibility
);
103 void SetColor(nscolor aColor
);
105 void PaintBorder(DrawTarget
* aDrawTarget
, nsPoint aPt
);
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
;
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
117 int32_t mPrevNeighbor
;
118 int32_t mNextNeighbor
;
124 friend class nsHTMLFramesetFrame
;
126 /*******************************************************************************
127 * nsHTMLFramesetBlankFrame
128 ******************************************************************************/
129 class nsHTMLFramesetBlankFrame final
: public nsLeafFrame
{
132 NS_DECL_FRAMEARENA_HELPERS(nsHTMLFramesetBlankFrame
)
134 #ifdef DEBUG_FRAME_DUMP
135 virtual nsresult
GetFrameName(nsAString
& aResult
) const override
{
136 return MakeFrameName(u
"FramesetBlank"_ns
, aResult
);
140 virtual void BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
141 const nsDisplayListSet
& aLists
) override
;
143 virtual void Reflow(nsPresContext
* aPresContext
, ReflowOutput
& aDesiredSize
,
144 const ReflowInput
& aReflowInput
,
145 nsReflowStatus
& aStatus
) override
;
148 explicit nsHTMLFramesetBlankFrame(ComputedStyle
* aStyle
,
149 nsPresContext
* aPresContext
)
150 : nsLeafFrame(aStyle
, aPresContext
, kClassID
) {}
152 virtual ~nsHTMLFramesetBlankFrame();
153 virtual nscoord
GetIntrinsicISize() override
;
154 virtual nscoord
GetIntrinsicBSize() override
;
156 friend class nsHTMLFramesetFrame
;
157 friend class nsHTMLFrameset
;
160 /*******************************************************************************
161 * nsHTMLFramesetFrame
162 ******************************************************************************/
163 bool nsHTMLFramesetFrame::gDragInProgress
= false;
164 #define DEFAULT_BORDER_WIDTH_PX 6
166 nsHTMLFramesetFrame::nsHTMLFramesetFrame(ComputedStyle
* aStyle
,
167 nsPresContext
* aPresContext
)
168 : nsContainerFrame(aStyle
, aPresContext
, kClassID
) {
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;
181 mTopLevelFrameset
= nullptr;
182 mEdgeColors
.Set(NO_COLOR
);
185 nsHTMLFramesetFrame::~nsHTMLFramesetFrame() = default;
187 NS_QUERYFRAME_HEAD(nsHTMLFramesetFrame
)
188 NS_QUERYFRAME_ENTRY(nsHTMLFramesetFrame
)
189 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
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
);
200 mTopLevelFrameset
= frameset
;
201 parentFrame
= parentFrame
->GetParent();
207 nsPresContext
* presContext
= PresContext();
208 mozilla::PresShell
* presShell
= presContext
->PresShell();
210 nsFrameborder frameborder
= GetFrameBorder();
211 int32_t borderWidth
= GetBorderWidth(presContext
, false);
212 nscolor borderColor
= GetBorderColor();
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
);
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
);
231 NS_MAX_FRAMESET_SPEC_COUNT
< INT32_MAX
/ NS_MAX_FRAMESET_SPEC_COUNT
,
232 "Should not overflow numCells");
233 int32_t numCells
= mNumRows
* mNumCols
;
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
241 for (int verX
= 0; verX
< mNumCols
; verX
++) mVerBorders
[verX
] = nullptr;
243 mHorBorders
= MakeUnique
<nsHTMLFramesetBorderFrame
*[]>(
244 mNumRows
); // 1 more than number of hor borders
246 for (int horX
= 0; horX
< mNumRows
; horX
++) mHorBorders
[horX
] = nullptr;
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
);
260 // create the children frames; skip content which isn't <frameset> or <frame>
261 mChildCount
= 0; // number of <frame> or <frameset> children
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
);
275 child
->UnsetFlags(NODE_DESCENDANTS_NEED_FRAMES
| NODE_NEEDS_FRAME
);
277 // IMPORTANT: This must match the conditions in
278 // nsCSSFrameConstructor::ContentAppended/Inserted/Removed
279 if (!child
->IsAnyOfHTMLElements(nsGkAtoms::frameset
, nsGkAtoms::frame
)) {
283 // FIXME(emilio): This doesn't even respect display: none, but that matches
284 // other browsers ;_;
286 // Maybe we should change that though.
287 RefPtr
<ComputedStyle
> kidStyle
=
288 ServoStyleSet::ResolveServoStyle(*child
->AsElement());
290 if (child
->IsHTMLElement(nsGkAtoms::frameset
)) {
291 frame
= NS_NewHTMLFramesetFrame(presShell
, kidStyle
);
293 nsHTMLFramesetFrame
* childFrame
= (nsHTMLFramesetFrame
*)frame
;
294 childFrame
->SetParentFrameborder(frameborder
);
295 childFrame
->SetParentBorderWidth(borderWidth
);
296 childFrame
->SetParentBorderColor(borderColor
);
297 frame
->Init(child
, this, nullptr);
299 mChildBorderColors
[mChildCount
].Set(childFrame
->GetBorderColor());
301 frame
= NS_NewSubDocumentFrame(presShell
, kidStyle
);
303 frame
->Init(child
, this, nullptr);
305 mChildFrameborder
[mChildCount
] = GetFrameBorder(child
);
306 mChildBorderColors
[mChildCount
].Set(GetBorderColor(child
));
308 child
->SetPrimaryFrame(frame
);
310 mFrames
.AppendFrame(nullptr, frame
);
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
);
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());
327 blankFrame
->Init(mContent
, this, nullptr);
329 mFrames
.AppendFrame(nullptr, blankFrame
);
331 mChildBorderColors
[mChildCount
].Set(NO_COLOR
);
335 mNonBorderChildCount
= mChildCount
;
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()) {
348 nsContainerFrame::SetInitialChildList(aListID
, aChildList
);
351 // XXX should this try to allocate twips based on an even pixel boundary?
352 void nsHTMLFramesetFrame::Scale(nscoord aDesired
, int32_t aNumIndicies
,
353 int32_t* aIndicies
, int32_t aNumItems
,
357 // get the actual total
358 for (i
= 0; i
< aNumIndicies
; i
++) {
364 float factor
= (float)aDesired
/ (float)actual
;
366 // scale the items up or down
367 for (i
= 0; i
< aNumIndicies
; i
++) {
369 aItems
[j
] = NSToCoordRound((float)aItems
[j
] * factor
);
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
;
382 if (aNumIndicies
> 0 && aDesired
!= actual
) {
383 int32_t unit
= (aDesired
> actual
) ? 1 : -1;
384 for (i
= 0; (i
< aNumIndicies
) && (aDesired
!= actual
); i
++) {
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.
400 void nsHTMLFramesetFrame::CalculateRowCol(nsPresContext
* aPresContext
,
401 nscoord aSize
, int32_t aNumSpecs
,
402 const nsFramesetSpec
* aSpecs
,
404 static_assert(NS_MAX_FRAMESET_SPEC_COUNT
< UINT_MAX
/ sizeof(int32_t),
405 "aNumSpecs maximum value is NS_MAX_FRAMESET_SPEC_COUNT");
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
);
416 if (MOZ_UNLIKELY(!fixed
|| !percent
|| !relative
)) {
417 return; // NS_ERROR_OUT_OF_MEMORY
422 // initialize the fixed, percent, relative indices, allocate the fixed sizes
423 // and zero the others
424 for (i
= 0; i
< aNumSpecs
; i
++) {
426 switch (aSpecs
[i
].mUnit
) {
427 case eFramesetUnit_Fixed
:
428 aValues
[i
] = nsPresContext::CSSPixelsToAppUnits(aSpecs
[i
].mValue
);
429 fixedTotal
+= aValues
[i
];
433 case eFramesetUnit_Percent
:
434 percent
[numPercent
] = i
;
437 case eFramesetUnit_Relative
:
438 relative
[numRelative
] = i
;
440 relativeSums
+= aSpecs
[i
].mValue
;
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
);
453 int32_t percentMax
= aSize
- fixedTotal
;
454 int32_t percentTotal
= 0;
455 // allocate the percentage sizes from what is left over from the fixed
457 for (i
= 0; i
< numPercent
; i
++) {
460 NSToCoordRound((float)aSpecs
[j
].mValue
* (float)aSize
/ 100.0f
);
461 percentTotal
+= aValues
[j
];
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
);
472 int32_t relativeMax
= percentMax
- percentTotal
;
473 int32_t relativeTotal
= 0;
474 // allocate the relative sizes from what is left over from the percent
476 for (i
= 0; i
< numRelative
; i
++) {
478 aValues
[j
] = NSToCoordRound((float)aSpecs
[j
].mValue
* (float)relativeMax
/
479 (float)relativeSums
);
480 relativeTotal
+= aValues
[j
];
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
);
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.
494 void nsHTMLFramesetFrame::GenerateRowCol(nsPresContext
* aPresContext
,
495 nscoord aSize
, int32_t aNumSpecs
,
496 const nsFramesetSpec
* aSpecs
,
497 nscoord
* aValues
, nsString
& aNewAttr
) {
500 for (i
= 0; i
< aNumSpecs
; i
++) {
501 if (!aNewAttr
.IsEmpty()) aNewAttr
.Append(char16_t(','));
503 switch (aSpecs
[i
].mUnit
) {
504 case eFramesetUnit_Fixed
:
505 aNewAttr
.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(aValues
[i
]));
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('%'));
517 int32_t nsHTMLFramesetFrame::GetBorderWidth(nsPresContext
* aPresContext
,
518 bool aTakeForcingIntoAccount
) {
519 nsFrameborder frameborder
= GetFrameBorder();
520 if (frameborder
== eFrameborder_No
) {
523 nsGenericHTMLElement
* content
= nsGenericHTMLElement::FromNode(mContent
);
526 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::border
);
529 if (attr
->Type() == nsAttrValue::eInteger
) {
530 intVal
= attr
->GetIntegerValue();
536 return nsPresContext::CSSPixelsToAppUnits(intVal
);
540 if (mParentBorderWidth
>= 0) {
541 return mParentBorderWidth
;
544 return nsPresContext::CSSPixelsToAppUnits(DEFAULT_BORDER_WIDTH_PX
);
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();
559 LogicalSize
area(wm
, aPresContext
->GetVisibleArea().Size());
561 desiredSize
.ISize(wm
) = area
.ISize(wm
);
562 desiredSize
.BSize(wm
) = area
.BSize(wm
);
565 LogicalSize
size(wm
);
566 framesetParent
->GetSizeOfChild(this, wm
, size
);
567 desiredSize
.ISize(wm
) = size
.ISize(wm
);
568 desiredSize
.BSize(wm
) = size
.BSize(wm
);
570 aDesiredSize
.SetSize(wm
, desiredSize
);
573 // only valid for non border children
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
];
586 aSize
.SizeTo(aWM
, 0, 0);
587 aCellIndex
.x
= aCellIndex
.y
= 0;
591 // only valid for non border children
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
597 for (nsIFrame
* child
: mFrames
) {
598 if (aChild
== child
) {
600 GetSizeOfChildAt(i
, aWM
, aSize
, ignore
);
605 aSize
.SizeTo(aWM
, 0, 0);
608 nsresult
nsHTMLFramesetFrame::HandleEvent(nsPresContext
* aPresContext
,
609 WidgetGUIEvent
* aEvent
,
610 nsEventStatus
* aEventStatus
) {
611 NS_ENSURE_ARG_POINTER(aEventStatus
);
613 // the nsFramesetBorderFrame has captured NS_MOUSE_DOWN
614 switch (aEvent
->mMessage
) {
616 MouseDrag(aPresContext
, aEvent
);
619 if (aEvent
->AsMouseEvent()->mButton
== MouseButton::ePrimary
) {
620 EndMouseDrag(aPresContext
);
626 *aEventStatus
= nsEventStatus_eConsumeNoDefault
;
628 *aEventStatus
= nsEventStatus_eIgnore
;
633 Maybe
<nsIFrame::Cursor
> nsHTMLFramesetFrame::GetCursor(const nsPoint
&) {
634 auto kind
= StyleCursorKind::Default
;
636 kind
= mDragger
->mVertical
? StyleCursorKind::EwResize
637 : StyleCursorKind::NsResize
;
639 return Some(Cursor
{kind
, AllowCustomCursorImage::No
});
642 void nsHTMLFramesetFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
643 const nsDisplayListSet
& aLists
) {
644 BuildDisplayListForInline(aBuilder
, aLists
);
646 if (mDragger
&& aBuilder
->IsForEventDelivery()) {
647 aLists
.Content()->AppendNewToTop
<nsDisplayEventReceiver
>(aBuilder
, this);
651 void nsHTMLFramesetFrame::ReflowPlaceChild(nsIFrame
* aChild
,
652 nsPresContext
* aPresContext
,
653 const ReflowInput
& aReflowInput
,
654 nsPoint
& aOffset
, nsSize
& aSize
,
655 nsIntPoint
* aCellIndex
) {
657 ReflowInput
reflowInput(aPresContext
, aReflowInput
, aChild
,
658 LogicalSize(aChild
->GetWritingMode(), aSize
));
659 reflowInput
.SetComputedWidth(std::max(
661 aSize
.width
- reflowInput
.ComputedPhysicalBorderPadding().LeftRight()));
662 reflowInput
.SetComputedHeight(std::max(
664 aSize
.height
- reflowInput
.ComputedPhysicalBorderPadding().TopBottom()));
665 ReflowOutput
reflowOutput(aReflowInput
);
666 reflowOutput
.Width() = aSize
.width
;
667 reflowOutput
.Height() = aSize
.height
;
668 nsReflowStatus status
;
670 ReflowChild(aChild
, aPresContext
, reflowOutput
, reflowInput
, aOffset
.x
,
671 aOffset
.y
, ReflowChildFlags::Default
, status
);
672 NS_ASSERTION(status
.IsComplete(), "bad status");
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
);
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
;
690 case NS_STYLE_FRAME_NO
:
691 case NS_STYLE_FRAME_0
:
692 return eFrameborder_No
;
696 return eFrameborder_Notset
;
699 nsFrameborder
nsHTMLFramesetFrame::GetFrameBorder() {
700 nsFrameborder result
= eFrameborder_Notset
;
701 nsGenericHTMLElement
* content
= nsGenericHTMLElement::FromNode(mContent
);
704 result
= GetFrameBorderHelper(content
);
706 if (eFrameborder_Notset
== result
) {
707 return mParentFrameborder
;
712 nsFrameborder
nsHTMLFramesetFrame::GetFrameBorder(nsIContent
* aContent
) {
713 nsFrameborder result
= eFrameborder_Notset
;
715 nsGenericHTMLElement
* content
= nsGenericHTMLElement::FromNode(aContent
);
718 result
= GetFrameBorderHelper(content
);
720 if (eFrameborder_Notset
== result
) {
721 return GetFrameBorder();
726 nscolor
nsHTMLFramesetFrame::GetBorderColor() {
727 nsGenericHTMLElement
* content
= nsGenericHTMLElement::FromNode(mContent
);
730 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::bordercolor
);
733 if (attr
->GetColorValue(color
)) {
739 return mParentBorderColor
;
742 nscolor
nsHTMLFramesetFrame::GetBorderColor(nsIContent
* aContent
) {
743 nsGenericHTMLElement
* content
= nsGenericHTMLElement::FromNode(aContent
);
746 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::bordercolor
);
749 if (attr
->GetColorValue(color
)) {
754 return GetBorderColor();
757 void nsHTMLFramesetFrame::Reflow(nsPresContext
* aPresContext
,
758 ReflowOutput
& aDesiredSize
,
759 const ReflowInput
& aReflowInput
,
760 nsReflowStatus
& aStatus
) {
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!");
766 mozilla::PresShell
* presShell
= aPresContext
->PresShell();
767 ServoStyleSet
* styleSet
= presShell
->StyleSet();
769 GetParent()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE
);
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
);
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();
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
;
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);
796 width
-= (mNumCols
- 1) * borderWidth
;
797 if (width
< 0) width
= 0;
799 height
-= (mNumRows
- 1) * borderWidth
;
800 if (height
< 0) height
= 0;
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;
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
) {
814 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowInput
, aDesiredSize
);
818 CalculateRowCol(aPresContext
, width
, mNumCols
, colSpecs
, mColSizes
.get());
819 CalculateRowCol(aPresContext
, height
, mNumRows
, rowSpecs
, mRowSizes
.get());
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();
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");
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
;
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
;
851 // reflow the children
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();
862 for (int32_t childX
= 0; childX
< mNonBorderChildCount
; childX
++) {
863 nsIntPoint cellIndex
;
864 GetSizeOfChildAt(childX
, wm
, logicalSize
, cellIndex
);
865 size
= logicalSize
.GetPhysicalSize(wm
);
867 if (lastRow
!= cellIndex
.y
) { // changed to next row
869 offset
.y
+= lastSize
.height
;
870 if (firstTime
) { // create horizontal border
872 RefPtr
<ComputedStyle
> pseudoComputedStyle
;
873 pseudoComputedStyle
= styleSet
->ResolveNonInheritingAnonymousBoxStyle(
874 PseudoStyleType::horizontalFramesetBorder
);
876 borderFrame
= new (presShell
) nsHTMLFramesetBorderFrame(
877 pseudoComputedStyle
, PresContext(), borderWidth
, false, false);
878 borderFrame
->Init(mContent
, this, nullptr);
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
;
886 borderFrame
= (nsHTMLFramesetBorderFrame
*)mFrames
.FrameAt(borderChildX
);
887 borderFrame
->mWidth
= borderWidth
;
890 nsSize
borderSize(aDesiredSize
.Width(), borderWidth
);
891 ReflowPlaceChild(borderFrame
, aPresContext
, aReflowInput
, offset
,
893 borderFrame
= nullptr;
894 offset
.y
+= borderWidth
;
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
900 RefPtr
<ComputedStyle
> pseudoComputedStyle
;
901 pseudoComputedStyle
=
902 styleSet
->ResolveNonInheritingAnonymousBoxStyle(
903 PseudoStyleType::verticalFramesetBorder
);
905 borderFrame
= new (presShell
) nsHTMLFramesetBorderFrame(
906 pseudoComputedStyle
, PresContext(), borderWidth
, true, false);
907 borderFrame
->Init(mContent
, this, nullptr);
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
;
916 (nsHTMLFramesetBorderFrame
*)mFrames
.FrameAt(borderChildX
);
917 borderFrame
->mWidth
= borderWidth
;
920 nsSize
borderSize(borderWidth
, aDesiredSize
.Height());
921 ReflowPlaceChild(borderFrame
, aPresContext
, aReflowInput
, offset
,
923 borderFrame
= nullptr;
925 offset
.x
+= borderWidth
;
929 ReflowPlaceChild(child
, aPresContext
, aReflowInput
, offset
, size
,
934 nsHTMLFramesetFrame
* framesetFrame
= do_QueryFrame(child
);
936 childVis
= framesetFrame
->mEdgeVisibility
;
937 mChildBorderColors
[childX
] = framesetFrame
->mEdgeColors
;
938 } else if (child
->IsSubDocumentFrame()) {
939 if (eFrameborder_Yes
== mChildFrameborder
[childX
]) {
941 } else if (eFrameborder_No
== mChildFrameborder
[childX
]) {
944 childVis
= (eFrameborder_No
== frameborder
) ? NONE_VIS
: ALL_VIS
;
948 nsHTMLFramesetBlankFrame
* blank
= do_QueryFrame(child
);
949 MOZ_ASSERT(blank
, "unexpected child frame type");
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
);
959 if (NO_COLOR
== mEdgeColors
.mLeft
) {
960 mEdgeColors
.mLeft
= childColors
.mLeft
;
963 if (0 == cellIndex
.y
) {
964 if (!(mEdgeVisibility
& TOP_VIS
)) {
965 mEdgeVisibility
|= (TOP_VIS
& childVis
);
967 if (NO_COLOR
== mEdgeColors
.mTop
) {
968 mEdgeColors
.mTop
= childColors
.mTop
;
971 if (mNumCols
- 1 == cellIndex
.x
) {
972 if (!(mEdgeVisibility
& RIGHT_VIS
)) {
973 mEdgeVisibility
|= (RIGHT_VIS
& childVis
);
975 if (NO_COLOR
== mEdgeColors
.mRight
) {
976 mEdgeColors
.mRight
= childColors
.mRight
;
979 if (mNumRows
- 1 == cellIndex
.y
) {
980 if (!(mEdgeVisibility
& BOTTOM_VIS
)) {
981 mEdgeVisibility
|= (BOTTOM_VIS
& childVis
);
983 if (NO_COLOR
== mEdgeColors
.mBottom
) {
984 mEdgeColors
.mBottom
= childColors
.mBottom
;
987 // set the visibility of borders that the child may affect
988 if (childVis
& RIGHT_VIS
) {
989 verBordersVis
[cellIndex
.x
] = true;
991 if (childVis
& BOTTOM_VIS
) {
992 horBordersVis
[cellIndex
.y
] = true;
994 if ((cellIndex
.x
> 0) && (childVis
& LEFT_VIS
)) {
995 verBordersVis
[cellIndex
.x
- 1] = true;
997 if ((cellIndex
.y
> 0) && (childVis
& TOP_VIS
)) {
998 horBordersVis
[cellIndex
.y
- 1] = true;
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
;
1004 if (NO_COLOR
== horBorderColors
[cellIndex
.y
]) {
1005 horBorderColors
[cellIndex
.y
] = mChildBorderColors
[childX
].mBottom
;
1007 if ((cellIndex
.x
> 0) && (NO_COLOR
== verBorderColors
[cellIndex
.x
- 1])) {
1008 verBorderColors
[cellIndex
.x
- 1] = mChildBorderColors
[childX
].mLeft
;
1010 if ((cellIndex
.y
> 0) && (NO_COLOR
== horBorderColors
[cellIndex
.y
- 1])) {
1011 horBorderColors
[cellIndex
.y
- 1] = mChildBorderColors
[childX
].mTop
;
1014 lastRow
= cellIndex
.y
;
1015 lastCol
= cellIndex
.x
;
1017 offset
.x
+= size
.width
;
1018 child
= child
->GetNextSibling();
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
])
1030 : verBorderColors
[verX
];
1031 mVerBorders
[verX
]->SetColor(childColor
);
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
])
1040 : horBorderColors
[horX
];
1041 mHorBorders
[horX
]->SetColor(childColor
);
1045 mChildFrameborder
.reset();
1046 mChildBorderColors
.reset();
1051 aDesiredSize
.SetOverflowAreasToDesiredBounds();
1052 FinishAndStoreOverflow(&aDesiredSize
);
1054 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowInput
, aDesiredSize
);
1057 #ifdef DEBUG_FRAME_DUMP
1058 nsresult
nsHTMLFramesetFrame::GetFrameName(nsAString
& aResult
) const {
1059 return MakeFrameName(u
"Frameset"_ns
, aResult
);
1063 bool nsHTMLFramesetFrame::CanResize(bool aVertical
, bool aLeft
) {
1067 startX
= (aLeft
) ? 0 : mNumCols
- 1;
1068 for (childX
= startX
; childX
< mNonBorderChildCount
; childX
+= mNumCols
) {
1069 if (!CanChildResize(aVertical
, aLeft
, childX
)) {
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
)) {
1085 bool nsHTMLFramesetFrame::GetNoResize(nsIFrame
* aChildFrame
) {
1086 nsIContent
* content
= aChildFrame
->GetContent();
1088 return content
&& content
->IsElement() &&
1089 content
->AsElement()->HasAttr(kNameSpaceID_None
, nsGkAtoms::noresize
);
1092 bool nsHTMLFramesetFrame::CanChildResize(bool aVertical
, bool aLeft
,
1094 nsIFrame
* child
= mFrames
.FrameAt(aChildX
);
1095 nsHTMLFramesetFrame
* frameset
= do_QueryFrame(child
);
1096 return frameset
? frameset
->CanResize(aVertical
, aLeft
) : !GetNoResize(child
);
1099 // This calculates and sets the resizability of all border frames
1101 void nsHTMLFramesetFrame::RecalculateBorderResize() {
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
1114 for (verX
= 0; verX
< mNumCols
- 1; verX
++) {
1115 if (mVerBorders
[verX
]) {
1116 mVerBorders
[verX
]->mCanResize
= true;
1117 SetBorderResize(mVerBorders
[verX
]);
1121 for (horX
= 0; horX
< mNumRows
- 1; horX
++) {
1122 if (mHorBorders
[horX
]) {
1123 mHorBorders
[horX
]->mCanResize
= true;
1124 SetBorderResize(mHorBorders
[horX
]);
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;
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;
1147 endX
= endX
+ mNumCols
;
1148 for (; childX
< endX
; childX
++) {
1149 if (!CanChildResize(false, true, childX
)) {
1150 aBorderFrame
->mCanResize
= false;
1156 void nsHTMLFramesetFrame::StartMouseDrag(nsPresContext
* aPresContext
,
1157 nsHTMLFramesetBorderFrame
* aBorder
,
1158 WidgetGUIEvent
* aEvent
) {
1161 IndexOf(aBorder
, index
);
1162 NS_ASSERTION((nullptr != aBorder
) && (index
>= 0), "invalid dragger");
1165 PresShell::SetCapturingContent(GetContent(),
1166 CaptureFlags::IgnoreAllowedState
);
1170 mFirstDragPoint
= aEvent
->mRefPoint
;
1172 // Store the original frame sizes
1173 if (mDragger
->mVertical
) {
1174 mPrevNeighborOrigSize
= mColSizes
[mDragger
->mPrevNeighbor
];
1175 mNextNeighborOrigSize
= mColSizes
[mDragger
->mNextNeighbor
];
1177 mPrevNeighborOrigSize
= mRowSizes
[mDragger
->mPrevNeighbor
];
1178 mNextNeighborOrigSize
= mRowSizes
[mDragger
->mNextNeighbor
];
1181 gDragInProgress
= true;
1184 void nsHTMLFramesetFrame::MouseDrag(nsPresContext
* aPresContext
,
1185 WidgetGUIEvent
* aEvent
) {
1186 // if the capture ended, reset the drag state
1187 if (PresShell::GetCapturingContent() != GetContent()) {
1189 gDragInProgress
= false;
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
-
1198 if (change
> mNextNeighborOrigSize
- mMinDrag
) {
1199 change
= mNextNeighborOrigSize
- mMinDrag
;
1200 } else if (change
<= mMinDrag
- mPrevNeighborOrigSize
) {
1201 change
= mMinDrag
- mPrevNeighborOrigSize
;
1203 mColSizes
[mDragger
->mPrevNeighbor
] = mPrevNeighborOrigSize
+ change
;
1204 mColSizes
[mDragger
->mNextNeighbor
] = mNextNeighborOrigSize
- change
;
1207 // Recompute the specs from the new sizes.
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(),
1217 // Setting the attr will trigger a reflow
1218 mContent
->AsElement()->SetAttr(kNameSpaceID_None
, nsGkAtoms::cols
,
1222 change
= aPresContext
->DevPixelsToAppUnits(aEvent
->mRefPoint
.y
-
1224 if (change
> mNextNeighborOrigSize
- mMinDrag
) {
1225 change
= mNextNeighborOrigSize
- mMinDrag
;
1226 } else if (change
<= mMinDrag
- mPrevNeighborOrigSize
) {
1227 change
= mMinDrag
- mPrevNeighborOrigSize
;
1229 mRowSizes
[mDragger
->mPrevNeighbor
] = mPrevNeighborOrigSize
+ change
;
1230 mRowSizes
[mDragger
->mNextNeighbor
] = mNextNeighborOrigSize
- change
;
1233 // Recompute the specs from the new sizes.
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(),
1243 // Setting the attr will trigger a reflow
1244 mContent
->AsElement()->SetAttr(kNameSpaceID_None
, nsGkAtoms::rows
,
1249 NS_ENSURE_TRUE_VOID(weakFrame
.IsAlive());
1251 mDrag
.Reset(mDragger
->mVertical
, mDragger
->mPrevNeighbor
, change
, this);
1255 void nsHTMLFramesetFrame::EndMouseDrag(nsPresContext
* aPresContext
) {
1256 PresShell::ReleaseCapturingContent();
1258 gDragInProgress
= false;
1261 nsIFrame
* NS_NewHTMLFramesetFrame(PresShell
* aPresShell
,
1262 ComputedStyle
* aStyle
) {
1264 const nsStyleDisplay
* disp
= aStyle
->StyleDisplay();
1265 NS_ASSERTION(!disp
->IsAbsolutelyPositionedStyle() && !disp
->IsFloatingStyle(),
1266 "Framesets should not be positioned and should not float");
1269 return new (aPresShell
)
1270 nsHTMLFramesetFrame(aStyle
, aPresShell
->GetPresContext());
1273 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetFrame
)
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
),
1283 mVertical(aVertical
),
1284 mVisibility(aVisibility
) {
1291 nsHTMLFramesetBorderFrame::~nsHTMLFramesetBorderFrame() {
1292 // printf("nsHTMLFramesetBorderFrame destructor %p \n", this);
1295 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetBorderFrame
)
1297 nscoord
nsHTMLFramesetBorderFrame::GetIntrinsicISize() {
1298 // No intrinsic width
1302 nscoord
nsHTMLFramesetBorderFrame::GetIntrinsicBSize() {
1303 // No intrinsic height
1307 void nsHTMLFramesetBorderFrame::SetVisibility(bool aVisibility
) {
1308 mVisibility
= aVisibility
;
1311 void nsHTMLFramesetBorderFrame::SetColor(nscolor aColor
) { mColor
= aColor
; }
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!");
1321 // Override Reflow(), since we don't want to deal with what our
1322 // computed values are.
1323 SizeToAvailSize(aReflowInput
, aDesiredSize
);
1325 aDesiredSize
.SetOverflowAreasToDesiredBounds();
1328 class nsDisplayFramesetBorder
: public nsPaintedDisplayItem
{
1330 nsDisplayFramesetBorder(nsDisplayListBuilder
* aBuilder
,
1331 nsHTMLFramesetBorderFrame
* aFrame
)
1332 : nsPaintedDisplayItem(aBuilder
, aFrame
) {
1333 MOZ_COUNT_CTOR(nsDisplayFramesetBorder
);
1335 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFramesetBorder
)
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
);
1344 virtual void Paint(nsDisplayListBuilder
* aBuilder
, gfxContext
* aCtx
) override
;
1345 NS_DISPLAY_DECL_NAME("FramesetBorder", TYPE_FRAMESET_BORDER
)
1348 void nsDisplayFramesetBorder::Paint(nsDisplayListBuilder
* aBuilder
,
1350 static_cast<nsHTMLFramesetBorderFrame
*>(mFrame
)->PaintBorder(
1351 aCtx
->GetDrawTarget(), ToReferenceFrame());
1354 void nsHTMLFramesetBorderFrame::BuildDisplayList(
1355 nsDisplayListBuilder
* aBuilder
, const nsDisplayListSet
& aLists
) {
1356 aLists
.Content()->AppendNewToTop
<nsDisplayFramesetBorder
>(aBuilder
, this);
1359 void nsHTMLFramesetBorderFrame::PaintBorder(DrawTarget
* aDrawTarget
,
1361 nscoord widthInPixels
= nsPresContext::AppUnitsToIntCSSPixels(mWidth
);
1362 nscoord pixelWidth
= nsPresContext::CSSPixelsToAppUnits(1);
1364 if (widthInPixels
<= 0) return;
1366 ColorPattern
bgColor(ToDeviceColor(LookAndFeel::GetColor(
1367 LookAndFeel::ColorID::WidgetBackground
, NS_RGB(200, 200, 200))));
1369 ColorPattern
fgColor(ToDeviceColor(LookAndFeel::GetColor(
1370 LookAndFeel::ColorID::WidgetForeground
, NS_RGB(0, 0, 0))));
1372 ColorPattern
hltColor(ToDeviceColor(LookAndFeel::GetColor(
1373 LookAndFeel::ColorID::Widget3DHighlight
, NS_RGB(255, 255, 255))));
1375 ColorPattern
sdwColor(ToDeviceColor(LookAndFeel::GetColor(
1376 LookAndFeel::ColorID::Widget3DShadow
, NS_RGB(128, 128, 128))));
1378 ColorPattern
color(ToDeviceColor(NS_RGB(255, 255, 255))); // default to white
1381 (NO_COLOR
== mColor
) ? bgColor
: ColorPattern(ToDeviceColor(mColor
));
1384 int32_t appUnitsPerDevPixel
= PresContext()->AppUnitsPerDevPixel();
1386 Point toRefFrame
= NSPointToPoint(aPt
, appUnitsPerDevPixel
);
1388 AutoRestoreTransform
autoRestoreTransform(aDrawTarget
);
1389 aDrawTarget
->SetTransform(
1390 aDrawTarget
->GetTransform().PreTranslate(toRefFrame
));
1392 nsPoint
start(0, 0);
1393 nsPoint end
= mVertical
? nsPoint(0, mRect
.height
) : nsPoint(mRect
.width
, 0);
1395 // draw grey or white first
1396 for (int i
= 0; i
< widthInPixels
; i
++) {
1397 StrokeLineWithSnapping(start
, end
, appUnitsPerDevPixel
, *aDrawTarget
,
1400 start
.x
+= pixelWidth
;
1403 start
.y
+= pixelWidth
;
1408 if (!mVisibility
) return;
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
,
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
,
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
,
1438 nsresult
nsHTMLFramesetBorderFrame::HandleEvent(nsPresContext
* aPresContext
,
1439 WidgetGUIEvent
* aEvent
,
1440 nsEventStatus
* aEventStatus
) {
1441 NS_ENSURE_ARG_POINTER(aEventStatus
);
1442 *aEventStatus
= nsEventStatus_eIgnore
;
1444 // XXX Mouse setting logic removed. The remaining logic should also move.
1449 if (aEvent
->mMessage
== eMouseDown
&&
1450 aEvent
->AsMouseEvent()->mButton
== MouseButton::ePrimary
) {
1451 nsHTMLFramesetFrame
* parentFrame
= do_QueryFrame(GetParent());
1453 parentFrame
->StartMouseDrag(aPresContext
, this, aEvent
);
1454 *aEventStatus
= nsEventStatus_eConsumeNoDefault
;
1460 Maybe
<nsIFrame::Cursor
> nsHTMLFramesetBorderFrame::GetCursor(const nsPoint
&) {
1461 auto kind
= StyleCursorKind::Default
;
1463 kind
= mVertical
? StyleCursorKind::EwResize
: StyleCursorKind::NsResize
;
1465 return Some(Cursor
{kind
, AllowCustomCursorImage::No
});
1468 #ifdef DEBUG_FRAME_DUMP
1469 nsresult
nsHTMLFramesetBorderFrame::GetFrameName(nsAString
& aResult
) const {
1470 return MakeFrameName(u
"FramesetBorder"_ns
, aResult
);
1474 /*******************************************************************************
1475 * nsHTMLFramesetBlankFrame
1476 ******************************************************************************/
1478 NS_QUERYFRAME_HEAD(nsHTMLFramesetBlankFrame
)
1479 NS_QUERYFRAME_ENTRY(nsHTMLFramesetBlankFrame
)
1480 NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame
)
1482 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetBlankFrame
)
1484 nsHTMLFramesetBlankFrame::~nsHTMLFramesetBlankFrame() {
1485 // printf("nsHTMLFramesetBlankFrame destructor %p \n", this);
1488 nscoord
nsHTMLFramesetBlankFrame::GetIntrinsicISize() {
1489 // No intrinsic width
1493 nscoord
nsHTMLFramesetBlankFrame::GetIntrinsicBSize() {
1494 // No intrinsic height
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!");
1505 // Override Reflow(), since we don't want to deal with what our
1506 // computed values are.
1507 SizeToAvailSize(aReflowInput
, aDesiredSize
);
1509 aDesiredSize
.SetOverflowAreasToDesiredBounds();
1512 class nsDisplayFramesetBlank
: public nsPaintedDisplayItem
{
1514 nsDisplayFramesetBlank(nsDisplayListBuilder
* aBuilder
, nsIFrame
* aFrame
)
1515 : nsPaintedDisplayItem(aBuilder
, aFrame
) {
1516 MOZ_COUNT_CTOR(nsDisplayFramesetBlank
);
1518 MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayFramesetBlank
)
1520 virtual void Paint(nsDisplayListBuilder
* aBuilder
, gfxContext
* aCtx
) override
;
1521 NS_DISPLAY_DECL_NAME("FramesetBlank", TYPE_FRAMESET_BLANK
)
1524 void nsDisplayFramesetBlank::Paint(nsDisplayListBuilder
* aBuilder
,
1526 DrawTarget
* drawTarget
= aCtx
->GetDrawTarget();
1527 int32_t appUnitsPerDevPixel
= mFrame
->PresContext()->AppUnitsPerDevPixel();
1529 NSRectToSnappedRect(GetPaintRect(), appUnitsPerDevPixel
, *drawTarget
);
1530 ColorPattern
white(ToDeviceColor(sRGBColor::OpaqueWhite()));
1531 drawTarget
->FillRect(rect
, white
);
1534 void nsHTMLFramesetBlankFrame::BuildDisplayList(
1535 nsDisplayListBuilder
* aBuilder
, const nsDisplayListSet
& aLists
) {
1536 aLists
.Content()->AppendNewToTop
<nsDisplayFramesetBlank
>(aBuilder
, this);