layout/generic/nsFrameSetFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial