layout/xul/nsBoxObject.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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 #include "nsBoxObject.h"
michael@0 7 #include "nsCOMPtr.h"
michael@0 8 #include "nsIDocument.h"
michael@0 9 #include "nsIPresShell.h"
michael@0 10 #include "nsPresContext.h"
michael@0 11 #include "nsIContent.h"
michael@0 12 #include "nsIFrame.h"
michael@0 13 #include "nsIDocShell.h"
michael@0 14 #include "nsReadableUtils.h"
michael@0 15 #include "nsDOMClassInfoID.h"
michael@0 16 #include "nsView.h"
michael@0 17 #ifdef MOZ_XUL
michael@0 18 #include "nsIDOMXULElement.h"
michael@0 19 #else
michael@0 20 #include "nsIDOMElement.h"
michael@0 21 #endif
michael@0 22 #include "nsLayoutUtils.h"
michael@0 23 #include "nsISupportsPrimitives.h"
michael@0 24 #include "nsSupportsPrimitives.h"
michael@0 25 #include "mozilla/dom/Element.h"
michael@0 26 #include "nsComponentManagerUtils.h"
michael@0 27
michael@0 28 using namespace mozilla::dom;
michael@0 29
michael@0 30 // Implementation /////////////////////////////////////////////////////////////////
michael@0 31
michael@0 32 // Static member variable initialization
michael@0 33
michael@0 34 // Implement our nsISupports methods
michael@0 35
michael@0 36 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBoxObject)
michael@0 37 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBoxObject)
michael@0 38
michael@0 39 DOMCI_DATA(BoxObject, nsBoxObject)
michael@0 40
michael@0 41 // QueryInterface implementation for nsBoxObject
michael@0 42 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBoxObject)
michael@0 43 NS_INTERFACE_MAP_ENTRY(nsIBoxObject)
michael@0 44 NS_INTERFACE_MAP_ENTRY(nsPIBoxObject)
michael@0 45 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 46 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BoxObject)
michael@0 47 NS_INTERFACE_MAP_END
michael@0 48
michael@0 49 static PLDHashOperator
michael@0 50 PropertyTraverser(const nsAString& aKey, nsISupports* aProperty, void* userArg)
michael@0 51 {
michael@0 52 nsCycleCollectionTraversalCallback *cb =
michael@0 53 static_cast<nsCycleCollectionTraversalCallback*>(userArg);
michael@0 54
michael@0 55 cb->NoteXPCOMChild(aProperty);
michael@0 56
michael@0 57 return PL_DHASH_NEXT;
michael@0 58 }
michael@0 59
michael@0 60 NS_IMPL_CYCLE_COLLECTION_CLASS(nsBoxObject)
michael@0 61
michael@0 62 NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsBoxObject)
michael@0 63 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBoxObject)
michael@0 64 if (tmp->mPropertyTable) {
michael@0 65 tmp->mPropertyTable->EnumerateRead(PropertyTraverser, &cb);
michael@0 66 }
michael@0 67 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 68
michael@0 69 // Constructors/Destructors
michael@0 70 nsBoxObject::nsBoxObject(void)
michael@0 71 :mContent(nullptr)
michael@0 72 {
michael@0 73 }
michael@0 74
michael@0 75 nsBoxObject::~nsBoxObject(void)
michael@0 76 {
michael@0 77 }
michael@0 78
michael@0 79 NS_IMETHODIMP
michael@0 80 nsBoxObject::GetElement(nsIDOMElement** aResult)
michael@0 81 {
michael@0 82 if (mContent) {
michael@0 83 return CallQueryInterface(mContent, aResult);
michael@0 84 }
michael@0 85
michael@0 86 *aResult = nullptr;
michael@0 87 return NS_OK;
michael@0 88 }
michael@0 89
michael@0 90 // nsPIBoxObject //////////////////////////////////////////////////////////////////////////
michael@0 91
michael@0 92 nsresult
michael@0 93 nsBoxObject::Init(nsIContent* aContent)
michael@0 94 {
michael@0 95 mContent = aContent;
michael@0 96 return NS_OK;
michael@0 97 }
michael@0 98
michael@0 99 void
michael@0 100 nsBoxObject::Clear()
michael@0 101 {
michael@0 102 mPropertyTable = nullptr;
michael@0 103 mContent = nullptr;
michael@0 104 }
michael@0 105
michael@0 106 void
michael@0 107 nsBoxObject::ClearCachedValues()
michael@0 108 {
michael@0 109 }
michael@0 110
michael@0 111 nsIFrame*
michael@0 112 nsBoxObject::GetFrame(bool aFlushLayout)
michael@0 113 {
michael@0 114 nsIPresShell* shell = GetPresShell(aFlushLayout);
michael@0 115 if (!shell)
michael@0 116 return nullptr;
michael@0 117
michael@0 118 if (!aFlushLayout) {
michael@0 119 // If we didn't flush layout when getting the presshell, we should at least
michael@0 120 // flush to make sure our frame model is up to date.
michael@0 121 // XXXbz should flush on document, no? Except people call this from
michael@0 122 // frame code, maybe?
michael@0 123 shell->FlushPendingNotifications(Flush_Frames);
michael@0 124 }
michael@0 125
michael@0 126 // The flush might have killed mContent.
michael@0 127 if (!mContent) {
michael@0 128 return nullptr;
michael@0 129 }
michael@0 130
michael@0 131 return mContent->GetPrimaryFrame();
michael@0 132 }
michael@0 133
michael@0 134 nsIPresShell*
michael@0 135 nsBoxObject::GetPresShell(bool aFlushLayout)
michael@0 136 {
michael@0 137 if (!mContent) {
michael@0 138 return nullptr;
michael@0 139 }
michael@0 140
michael@0 141 nsCOMPtr<nsIDocument> doc = mContent->GetCurrentDoc();
michael@0 142 if (!doc) {
michael@0 143 return nullptr;
michael@0 144 }
michael@0 145
michael@0 146 if (aFlushLayout) {
michael@0 147 doc->FlushPendingNotifications(Flush_Layout);
michael@0 148 }
michael@0 149
michael@0 150 return doc->GetShell();
michael@0 151 }
michael@0 152
michael@0 153 nsresult
michael@0 154 nsBoxObject::GetOffsetRect(nsIntRect& aRect)
michael@0 155 {
michael@0 156 aRect.SetRect(0, 0, 0, 0);
michael@0 157
michael@0 158 if (!mContent)
michael@0 159 return NS_ERROR_NOT_INITIALIZED;
michael@0 160
michael@0 161 // Get the Frame for our content
michael@0 162 nsIFrame* frame = GetFrame(true);
michael@0 163 if (frame) {
michael@0 164 // Get its origin
michael@0 165 nsPoint origin = frame->GetPositionIgnoringScrolling();
michael@0 166
michael@0 167 // Find the frame parent whose content is the document element.
michael@0 168 Element *docElement = mContent->GetCurrentDoc()->GetRootElement();
michael@0 169 nsIFrame* parent = frame->GetParent();
michael@0 170 for (;;) {
michael@0 171 // If we've hit the document element, break here
michael@0 172 if (parent->GetContent() == docElement) {
michael@0 173 break;
michael@0 174 }
michael@0 175
michael@0 176 nsIFrame* next = parent->GetParent();
michael@0 177 if (!next) {
michael@0 178 NS_WARNING("We should have hit the document element...");
michael@0 179 origin += parent->GetPosition();
michael@0 180 break;
michael@0 181 }
michael@0 182
michael@0 183 // Add the parent's origin to our own to get to the
michael@0 184 // right coordinate system
michael@0 185 origin += next->GetPositionOfChildIgnoringScrolling(parent);
michael@0 186 parent = next;
michael@0 187 }
michael@0 188
michael@0 189 // For the origin, add in the border for the frame
michael@0 190 const nsStyleBorder* border = frame->StyleBorder();
michael@0 191 origin.x += border->GetComputedBorderWidth(NS_SIDE_LEFT);
michael@0 192 origin.y += border->GetComputedBorderWidth(NS_SIDE_TOP);
michael@0 193
michael@0 194 // And subtract out the border for the parent
michael@0 195 const nsStyleBorder* parentBorder = parent->StyleBorder();
michael@0 196 origin.x -= parentBorder->GetComputedBorderWidth(NS_SIDE_LEFT);
michael@0 197 origin.y -= parentBorder->GetComputedBorderWidth(NS_SIDE_TOP);
michael@0 198
michael@0 199 aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
michael@0 200 aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
michael@0 201
michael@0 202 // Get the union of all rectangles in this and continuation frames.
michael@0 203 // It doesn't really matter what we use as aRelativeTo here, since
michael@0 204 // we only care about the size. Using 'parent' might make things
michael@0 205 // a bit faster by speeding up the internal GetOffsetTo operations.
michael@0 206 nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent);
michael@0 207 aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
michael@0 208 aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
michael@0 209 }
michael@0 210
michael@0 211 return NS_OK;
michael@0 212 }
michael@0 213
michael@0 214 nsresult
michael@0 215 nsBoxObject::GetScreenPosition(nsIntPoint& aPoint)
michael@0 216 {
michael@0 217 aPoint.x = aPoint.y = 0;
michael@0 218
michael@0 219 if (!mContent)
michael@0 220 return NS_ERROR_NOT_INITIALIZED;
michael@0 221
michael@0 222 nsIFrame* frame = GetFrame(true);
michael@0 223 if (frame) {
michael@0 224 nsIntRect rect = frame->GetScreenRect();
michael@0 225 aPoint.x = rect.x;
michael@0 226 aPoint.y = rect.y;
michael@0 227 }
michael@0 228
michael@0 229 return NS_OK;
michael@0 230 }
michael@0 231
michael@0 232 NS_IMETHODIMP
michael@0 233 nsBoxObject::GetX(int32_t* aResult)
michael@0 234 {
michael@0 235 nsIntRect rect;
michael@0 236 GetOffsetRect(rect);
michael@0 237 *aResult = rect.x;
michael@0 238 return NS_OK;
michael@0 239 }
michael@0 240
michael@0 241 NS_IMETHODIMP
michael@0 242 nsBoxObject::GetY(int32_t* aResult)
michael@0 243 {
michael@0 244 nsIntRect rect;
michael@0 245 GetOffsetRect(rect);
michael@0 246 *aResult = rect.y;
michael@0 247 return NS_OK;
michael@0 248 }
michael@0 249
michael@0 250 NS_IMETHODIMP
michael@0 251 nsBoxObject::GetWidth(int32_t* aResult)
michael@0 252 {
michael@0 253 nsIntRect rect;
michael@0 254 GetOffsetRect(rect);
michael@0 255 *aResult = rect.width;
michael@0 256 return NS_OK;
michael@0 257 }
michael@0 258
michael@0 259 NS_IMETHODIMP
michael@0 260 nsBoxObject::GetHeight(int32_t* aResult)
michael@0 261 {
michael@0 262 nsIntRect rect;
michael@0 263 GetOffsetRect(rect);
michael@0 264 *aResult = rect.height;
michael@0 265 return NS_OK;
michael@0 266 }
michael@0 267
michael@0 268 NS_IMETHODIMP
michael@0 269 nsBoxObject::GetScreenX(int32_t *_retval)
michael@0 270 {
michael@0 271 nsIntPoint position;
michael@0 272 nsresult rv = GetScreenPosition(position);
michael@0 273 if (NS_FAILED(rv)) return rv;
michael@0 274
michael@0 275 *_retval = position.x;
michael@0 276
michael@0 277 return NS_OK;
michael@0 278 }
michael@0 279
michael@0 280 NS_IMETHODIMP
michael@0 281 nsBoxObject::GetScreenY(int32_t *_retval)
michael@0 282 {
michael@0 283 nsIntPoint position;
michael@0 284 nsresult rv = GetScreenPosition(position);
michael@0 285 if (NS_FAILED(rv)) return rv;
michael@0 286
michael@0 287 *_retval = position.y;
michael@0 288
michael@0 289 return NS_OK;
michael@0 290 }
michael@0 291
michael@0 292 NS_IMETHODIMP
michael@0 293 nsBoxObject::GetPropertyAsSupports(const char16_t* aPropertyName, nsISupports** aResult)
michael@0 294 {
michael@0 295 NS_ENSURE_ARG(aPropertyName && *aPropertyName);
michael@0 296 if (!mPropertyTable) {
michael@0 297 *aResult = nullptr;
michael@0 298 return NS_OK;
michael@0 299 }
michael@0 300 nsDependentString propertyName(aPropertyName);
michael@0 301 mPropertyTable->Get(propertyName, aResult); // Addref here.
michael@0 302 return NS_OK;
michael@0 303 }
michael@0 304
michael@0 305 NS_IMETHODIMP
michael@0 306 nsBoxObject::SetPropertyAsSupports(const char16_t* aPropertyName, nsISupports* aValue)
michael@0 307 {
michael@0 308 NS_ENSURE_ARG(aPropertyName && *aPropertyName);
michael@0 309
michael@0 310 if (!mPropertyTable) {
michael@0 311 mPropertyTable = new nsInterfaceHashtable<nsStringHashKey,nsISupports>(8);
michael@0 312 }
michael@0 313
michael@0 314 nsDependentString propertyName(aPropertyName);
michael@0 315 mPropertyTable->Put(propertyName, aValue);
michael@0 316 return NS_OK;
michael@0 317 }
michael@0 318
michael@0 319 NS_IMETHODIMP
michael@0 320 nsBoxObject::GetProperty(const char16_t* aPropertyName, char16_t** aResult)
michael@0 321 {
michael@0 322 nsCOMPtr<nsISupports> data;
michael@0 323 nsresult rv = GetPropertyAsSupports(aPropertyName,getter_AddRefs(data));
michael@0 324 NS_ENSURE_SUCCESS(rv, rv);
michael@0 325
michael@0 326 if (!data) {
michael@0 327 *aResult = nullptr;
michael@0 328 return NS_OK;
michael@0 329 }
michael@0 330
michael@0 331 nsCOMPtr<nsISupportsString> supportsStr = do_QueryInterface(data);
michael@0 332 if (!supportsStr)
michael@0 333 return NS_ERROR_FAILURE;
michael@0 334
michael@0 335 return supportsStr->ToString(aResult);
michael@0 336 }
michael@0 337
michael@0 338 NS_IMETHODIMP
michael@0 339 nsBoxObject::SetProperty(const char16_t* aPropertyName, const char16_t* aPropertyValue)
michael@0 340 {
michael@0 341 NS_ENSURE_ARG(aPropertyName && *aPropertyName);
michael@0 342
michael@0 343 nsDependentString propertyName(aPropertyName);
michael@0 344 nsDependentString propertyValue;
michael@0 345 if (aPropertyValue) {
michael@0 346 propertyValue.Rebind(aPropertyValue);
michael@0 347 } else {
michael@0 348 propertyValue.SetIsVoid(true);
michael@0 349 }
michael@0 350
michael@0 351 nsCOMPtr<nsISupportsString> supportsStr(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
michael@0 352 NS_ENSURE_TRUE(supportsStr, NS_ERROR_OUT_OF_MEMORY);
michael@0 353 supportsStr->SetData(propertyValue);
michael@0 354
michael@0 355 return SetPropertyAsSupports(aPropertyName,supportsStr);
michael@0 356 }
michael@0 357
michael@0 358 NS_IMETHODIMP
michael@0 359 nsBoxObject::RemoveProperty(const char16_t* aPropertyName)
michael@0 360 {
michael@0 361 NS_ENSURE_ARG(aPropertyName && *aPropertyName);
michael@0 362
michael@0 363 if (!mPropertyTable) return NS_OK;
michael@0 364
michael@0 365 nsDependentString propertyName(aPropertyName);
michael@0 366 mPropertyTable->Remove(propertyName);
michael@0 367 return NS_OK;
michael@0 368 }
michael@0 369
michael@0 370 NS_IMETHODIMP
michael@0 371 nsBoxObject::GetParentBox(nsIDOMElement * *aParentBox)
michael@0 372 {
michael@0 373 *aParentBox = nullptr;
michael@0 374 nsIFrame* frame = GetFrame(false);
michael@0 375 if (!frame) return NS_OK;
michael@0 376 nsIFrame* parent = frame->GetParent();
michael@0 377 if (!parent) return NS_OK;
michael@0 378
michael@0 379 nsCOMPtr<nsIDOMElement> el = do_QueryInterface(parent->GetContent());
michael@0 380 *aParentBox = el;
michael@0 381 NS_IF_ADDREF(*aParentBox);
michael@0 382 return NS_OK;
michael@0 383 }
michael@0 384
michael@0 385 NS_IMETHODIMP
michael@0 386 nsBoxObject::GetFirstChild(nsIDOMElement * *aFirstVisibleChild)
michael@0 387 {
michael@0 388 *aFirstVisibleChild = nullptr;
michael@0 389 nsIFrame* frame = GetFrame(false);
michael@0 390 if (!frame) return NS_OK;
michael@0 391 nsIFrame* firstFrame = frame->GetFirstPrincipalChild();
michael@0 392 if (!firstFrame) return NS_OK;
michael@0 393 // get the content for the box and query to a dom element
michael@0 394 nsCOMPtr<nsIDOMElement> el = do_QueryInterface(firstFrame->GetContent());
michael@0 395 el.swap(*aFirstVisibleChild);
michael@0 396 return NS_OK;
michael@0 397 }
michael@0 398
michael@0 399 NS_IMETHODIMP
michael@0 400 nsBoxObject::GetLastChild(nsIDOMElement * *aLastVisibleChild)
michael@0 401 {
michael@0 402 *aLastVisibleChild = nullptr;
michael@0 403 nsIFrame* frame = GetFrame(false);
michael@0 404 if (!frame) return NS_OK;
michael@0 405 return GetPreviousSibling(frame, nullptr, aLastVisibleChild);
michael@0 406 }
michael@0 407
michael@0 408 NS_IMETHODIMP
michael@0 409 nsBoxObject::GetNextSibling(nsIDOMElement **aNextOrdinalSibling)
michael@0 410 {
michael@0 411 *aNextOrdinalSibling = nullptr;
michael@0 412 nsIFrame* frame = GetFrame(false);
michael@0 413 if (!frame) return NS_OK;
michael@0 414 nsIFrame* nextFrame = frame->GetNextSibling();
michael@0 415 if (!nextFrame) return NS_OK;
michael@0 416 // get the content for the box and query to a dom element
michael@0 417 nsCOMPtr<nsIDOMElement> el = do_QueryInterface(nextFrame->GetContent());
michael@0 418 el.swap(*aNextOrdinalSibling);
michael@0 419 return NS_OK;
michael@0 420 }
michael@0 421
michael@0 422 NS_IMETHODIMP
michael@0 423 nsBoxObject::GetPreviousSibling(nsIDOMElement **aPreviousOrdinalSibling)
michael@0 424 {
michael@0 425 *aPreviousOrdinalSibling = nullptr;
michael@0 426 nsIFrame* frame = GetFrame(false);
michael@0 427 if (!frame) return NS_OK;
michael@0 428 nsIFrame* parentFrame = frame->GetParent();
michael@0 429 if (!parentFrame) return NS_OK;
michael@0 430 return GetPreviousSibling(parentFrame, frame, aPreviousOrdinalSibling);
michael@0 431 }
michael@0 432
michael@0 433 nsresult
michael@0 434 nsBoxObject::GetPreviousSibling(nsIFrame* aParentFrame, nsIFrame* aFrame,
michael@0 435 nsIDOMElement** aResult)
michael@0 436 {
michael@0 437 *aResult = nullptr;
michael@0 438 nsIFrame* nextFrame = aParentFrame->GetFirstPrincipalChild();
michael@0 439 nsIFrame* prevFrame = nullptr;
michael@0 440 while (nextFrame) {
michael@0 441 if (nextFrame == aFrame)
michael@0 442 break;
michael@0 443 prevFrame = nextFrame;
michael@0 444 nextFrame = nextFrame->GetNextSibling();
michael@0 445 }
michael@0 446
michael@0 447 if (!prevFrame) return NS_OK;
michael@0 448 // get the content for the box and query to a dom element
michael@0 449 nsCOMPtr<nsIDOMElement> el = do_QueryInterface(prevFrame->GetContent());
michael@0 450 el.swap(*aResult);
michael@0 451 return NS_OK;
michael@0 452 }
michael@0 453
michael@0 454 // Creation Routine ///////////////////////////////////////////////////////////////////////
michael@0 455
michael@0 456 nsresult
michael@0 457 NS_NewBoxObject(nsIBoxObject** aResult)
michael@0 458 {
michael@0 459 *aResult = new nsBoxObject;
michael@0 460 if (!*aResult)
michael@0 461 return NS_ERROR_OUT_OF_MEMORY;
michael@0 462 NS_ADDREF(*aResult);
michael@0 463 return NS_OK;
michael@0 464 }
michael@0 465

mercurial