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