layout/generic/nsFrameSetFrame.cpp

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

mercurial