1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsBoxObject.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,465 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsBoxObject.h" 1.10 +#include "nsCOMPtr.h" 1.11 +#include "nsIDocument.h" 1.12 +#include "nsIPresShell.h" 1.13 +#include "nsPresContext.h" 1.14 +#include "nsIContent.h" 1.15 +#include "nsIFrame.h" 1.16 +#include "nsIDocShell.h" 1.17 +#include "nsReadableUtils.h" 1.18 +#include "nsDOMClassInfoID.h" 1.19 +#include "nsView.h" 1.20 +#ifdef MOZ_XUL 1.21 +#include "nsIDOMXULElement.h" 1.22 +#else 1.23 +#include "nsIDOMElement.h" 1.24 +#endif 1.25 +#include "nsLayoutUtils.h" 1.26 +#include "nsISupportsPrimitives.h" 1.27 +#include "nsSupportsPrimitives.h" 1.28 +#include "mozilla/dom/Element.h" 1.29 +#include "nsComponentManagerUtils.h" 1.30 + 1.31 +using namespace mozilla::dom; 1.32 + 1.33 +// Implementation ///////////////////////////////////////////////////////////////// 1.34 + 1.35 +// Static member variable initialization 1.36 + 1.37 +// Implement our nsISupports methods 1.38 + 1.39 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsBoxObject) 1.40 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsBoxObject) 1.41 + 1.42 +DOMCI_DATA(BoxObject, nsBoxObject) 1.43 + 1.44 +// QueryInterface implementation for nsBoxObject 1.45 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsBoxObject) 1.46 + NS_INTERFACE_MAP_ENTRY(nsIBoxObject) 1.47 + NS_INTERFACE_MAP_ENTRY(nsPIBoxObject) 1.48 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.49 + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BoxObject) 1.50 +NS_INTERFACE_MAP_END 1.51 + 1.52 +static PLDHashOperator 1.53 +PropertyTraverser(const nsAString& aKey, nsISupports* aProperty, void* userArg) 1.54 +{ 1.55 + nsCycleCollectionTraversalCallback *cb = 1.56 + static_cast<nsCycleCollectionTraversalCallback*>(userArg); 1.57 + 1.58 + cb->NoteXPCOMChild(aProperty); 1.59 + 1.60 + return PL_DHASH_NEXT; 1.61 +} 1.62 + 1.63 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsBoxObject) 1.64 + 1.65 +NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsBoxObject) 1.66 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsBoxObject) 1.67 + if (tmp->mPropertyTable) { 1.68 + tmp->mPropertyTable->EnumerateRead(PropertyTraverser, &cb); 1.69 + } 1.70 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.71 + 1.72 +// Constructors/Destructors 1.73 +nsBoxObject::nsBoxObject(void) 1.74 + :mContent(nullptr) 1.75 +{ 1.76 +} 1.77 + 1.78 +nsBoxObject::~nsBoxObject(void) 1.79 +{ 1.80 +} 1.81 + 1.82 +NS_IMETHODIMP 1.83 +nsBoxObject::GetElement(nsIDOMElement** aResult) 1.84 +{ 1.85 + if (mContent) { 1.86 + return CallQueryInterface(mContent, aResult); 1.87 + } 1.88 + 1.89 + *aResult = nullptr; 1.90 + return NS_OK; 1.91 +} 1.92 + 1.93 +// nsPIBoxObject ////////////////////////////////////////////////////////////////////////// 1.94 + 1.95 +nsresult 1.96 +nsBoxObject::Init(nsIContent* aContent) 1.97 +{ 1.98 + mContent = aContent; 1.99 + return NS_OK; 1.100 +} 1.101 + 1.102 +void 1.103 +nsBoxObject::Clear() 1.104 +{ 1.105 + mPropertyTable = nullptr; 1.106 + mContent = nullptr; 1.107 +} 1.108 + 1.109 +void 1.110 +nsBoxObject::ClearCachedValues() 1.111 +{ 1.112 +} 1.113 + 1.114 +nsIFrame* 1.115 +nsBoxObject::GetFrame(bool aFlushLayout) 1.116 +{ 1.117 + nsIPresShell* shell = GetPresShell(aFlushLayout); 1.118 + if (!shell) 1.119 + return nullptr; 1.120 + 1.121 + if (!aFlushLayout) { 1.122 + // If we didn't flush layout when getting the presshell, we should at least 1.123 + // flush to make sure our frame model is up to date. 1.124 + // XXXbz should flush on document, no? Except people call this from 1.125 + // frame code, maybe? 1.126 + shell->FlushPendingNotifications(Flush_Frames); 1.127 + } 1.128 + 1.129 + // The flush might have killed mContent. 1.130 + if (!mContent) { 1.131 + return nullptr; 1.132 + } 1.133 + 1.134 + return mContent->GetPrimaryFrame(); 1.135 +} 1.136 + 1.137 +nsIPresShell* 1.138 +nsBoxObject::GetPresShell(bool aFlushLayout) 1.139 +{ 1.140 + if (!mContent) { 1.141 + return nullptr; 1.142 + } 1.143 + 1.144 + nsCOMPtr<nsIDocument> doc = mContent->GetCurrentDoc(); 1.145 + if (!doc) { 1.146 + return nullptr; 1.147 + } 1.148 + 1.149 + if (aFlushLayout) { 1.150 + doc->FlushPendingNotifications(Flush_Layout); 1.151 + } 1.152 + 1.153 + return doc->GetShell(); 1.154 +} 1.155 + 1.156 +nsresult 1.157 +nsBoxObject::GetOffsetRect(nsIntRect& aRect) 1.158 +{ 1.159 + aRect.SetRect(0, 0, 0, 0); 1.160 + 1.161 + if (!mContent) 1.162 + return NS_ERROR_NOT_INITIALIZED; 1.163 + 1.164 + // Get the Frame for our content 1.165 + nsIFrame* frame = GetFrame(true); 1.166 + if (frame) { 1.167 + // Get its origin 1.168 + nsPoint origin = frame->GetPositionIgnoringScrolling(); 1.169 + 1.170 + // Find the frame parent whose content is the document element. 1.171 + Element *docElement = mContent->GetCurrentDoc()->GetRootElement(); 1.172 + nsIFrame* parent = frame->GetParent(); 1.173 + for (;;) { 1.174 + // If we've hit the document element, break here 1.175 + if (parent->GetContent() == docElement) { 1.176 + break; 1.177 + } 1.178 + 1.179 + nsIFrame* next = parent->GetParent(); 1.180 + if (!next) { 1.181 + NS_WARNING("We should have hit the document element..."); 1.182 + origin += parent->GetPosition(); 1.183 + break; 1.184 + } 1.185 + 1.186 + // Add the parent's origin to our own to get to the 1.187 + // right coordinate system 1.188 + origin += next->GetPositionOfChildIgnoringScrolling(parent); 1.189 + parent = next; 1.190 + } 1.191 + 1.192 + // For the origin, add in the border for the frame 1.193 + const nsStyleBorder* border = frame->StyleBorder(); 1.194 + origin.x += border->GetComputedBorderWidth(NS_SIDE_LEFT); 1.195 + origin.y += border->GetComputedBorderWidth(NS_SIDE_TOP); 1.196 + 1.197 + // And subtract out the border for the parent 1.198 + const nsStyleBorder* parentBorder = parent->StyleBorder(); 1.199 + origin.x -= parentBorder->GetComputedBorderWidth(NS_SIDE_LEFT); 1.200 + origin.y -= parentBorder->GetComputedBorderWidth(NS_SIDE_TOP); 1.201 + 1.202 + aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x); 1.203 + aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y); 1.204 + 1.205 + // Get the union of all rectangles in this and continuation frames. 1.206 + // It doesn't really matter what we use as aRelativeTo here, since 1.207 + // we only care about the size. Using 'parent' might make things 1.208 + // a bit faster by speeding up the internal GetOffsetTo operations. 1.209 + nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, parent); 1.210 + aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width); 1.211 + aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height); 1.212 + } 1.213 + 1.214 + return NS_OK; 1.215 +} 1.216 + 1.217 +nsresult 1.218 +nsBoxObject::GetScreenPosition(nsIntPoint& aPoint) 1.219 +{ 1.220 + aPoint.x = aPoint.y = 0; 1.221 + 1.222 + if (!mContent) 1.223 + return NS_ERROR_NOT_INITIALIZED; 1.224 + 1.225 + nsIFrame* frame = GetFrame(true); 1.226 + if (frame) { 1.227 + nsIntRect rect = frame->GetScreenRect(); 1.228 + aPoint.x = rect.x; 1.229 + aPoint.y = rect.y; 1.230 + } 1.231 + 1.232 + return NS_OK; 1.233 +} 1.234 + 1.235 +NS_IMETHODIMP 1.236 +nsBoxObject::GetX(int32_t* aResult) 1.237 +{ 1.238 + nsIntRect rect; 1.239 + GetOffsetRect(rect); 1.240 + *aResult = rect.x; 1.241 + return NS_OK; 1.242 +} 1.243 + 1.244 +NS_IMETHODIMP 1.245 +nsBoxObject::GetY(int32_t* aResult) 1.246 +{ 1.247 + nsIntRect rect; 1.248 + GetOffsetRect(rect); 1.249 + *aResult = rect.y; 1.250 + return NS_OK; 1.251 +} 1.252 + 1.253 +NS_IMETHODIMP 1.254 +nsBoxObject::GetWidth(int32_t* aResult) 1.255 +{ 1.256 + nsIntRect rect; 1.257 + GetOffsetRect(rect); 1.258 + *aResult = rect.width; 1.259 + return NS_OK; 1.260 +} 1.261 + 1.262 +NS_IMETHODIMP 1.263 +nsBoxObject::GetHeight(int32_t* aResult) 1.264 +{ 1.265 + nsIntRect rect; 1.266 + GetOffsetRect(rect); 1.267 + *aResult = rect.height; 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +NS_IMETHODIMP 1.272 +nsBoxObject::GetScreenX(int32_t *_retval) 1.273 +{ 1.274 + nsIntPoint position; 1.275 + nsresult rv = GetScreenPosition(position); 1.276 + if (NS_FAILED(rv)) return rv; 1.277 + 1.278 + *_retval = position.x; 1.279 + 1.280 + return NS_OK; 1.281 +} 1.282 + 1.283 +NS_IMETHODIMP 1.284 +nsBoxObject::GetScreenY(int32_t *_retval) 1.285 +{ 1.286 + nsIntPoint position; 1.287 + nsresult rv = GetScreenPosition(position); 1.288 + if (NS_FAILED(rv)) return rv; 1.289 + 1.290 + *_retval = position.y; 1.291 + 1.292 + return NS_OK; 1.293 +} 1.294 + 1.295 +NS_IMETHODIMP 1.296 +nsBoxObject::GetPropertyAsSupports(const char16_t* aPropertyName, nsISupports** aResult) 1.297 +{ 1.298 + NS_ENSURE_ARG(aPropertyName && *aPropertyName); 1.299 + if (!mPropertyTable) { 1.300 + *aResult = nullptr; 1.301 + return NS_OK; 1.302 + } 1.303 + nsDependentString propertyName(aPropertyName); 1.304 + mPropertyTable->Get(propertyName, aResult); // Addref here. 1.305 + return NS_OK; 1.306 +} 1.307 + 1.308 +NS_IMETHODIMP 1.309 +nsBoxObject::SetPropertyAsSupports(const char16_t* aPropertyName, nsISupports* aValue) 1.310 +{ 1.311 + NS_ENSURE_ARG(aPropertyName && *aPropertyName); 1.312 + 1.313 + if (!mPropertyTable) { 1.314 + mPropertyTable = new nsInterfaceHashtable<nsStringHashKey,nsISupports>(8); 1.315 + } 1.316 + 1.317 + nsDependentString propertyName(aPropertyName); 1.318 + mPropertyTable->Put(propertyName, aValue); 1.319 + return NS_OK; 1.320 +} 1.321 + 1.322 +NS_IMETHODIMP 1.323 +nsBoxObject::GetProperty(const char16_t* aPropertyName, char16_t** aResult) 1.324 +{ 1.325 + nsCOMPtr<nsISupports> data; 1.326 + nsresult rv = GetPropertyAsSupports(aPropertyName,getter_AddRefs(data)); 1.327 + NS_ENSURE_SUCCESS(rv, rv); 1.328 + 1.329 + if (!data) { 1.330 + *aResult = nullptr; 1.331 + return NS_OK; 1.332 + } 1.333 + 1.334 + nsCOMPtr<nsISupportsString> supportsStr = do_QueryInterface(data); 1.335 + if (!supportsStr) 1.336 + return NS_ERROR_FAILURE; 1.337 + 1.338 + return supportsStr->ToString(aResult); 1.339 +} 1.340 + 1.341 +NS_IMETHODIMP 1.342 +nsBoxObject::SetProperty(const char16_t* aPropertyName, const char16_t* aPropertyValue) 1.343 +{ 1.344 + NS_ENSURE_ARG(aPropertyName && *aPropertyName); 1.345 + 1.346 + nsDependentString propertyName(aPropertyName); 1.347 + nsDependentString propertyValue; 1.348 + if (aPropertyValue) { 1.349 + propertyValue.Rebind(aPropertyValue); 1.350 + } else { 1.351 + propertyValue.SetIsVoid(true); 1.352 + } 1.353 + 1.354 + nsCOMPtr<nsISupportsString> supportsStr(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); 1.355 + NS_ENSURE_TRUE(supportsStr, NS_ERROR_OUT_OF_MEMORY); 1.356 + supportsStr->SetData(propertyValue); 1.357 + 1.358 + return SetPropertyAsSupports(aPropertyName,supportsStr); 1.359 +} 1.360 + 1.361 +NS_IMETHODIMP 1.362 +nsBoxObject::RemoveProperty(const char16_t* aPropertyName) 1.363 +{ 1.364 + NS_ENSURE_ARG(aPropertyName && *aPropertyName); 1.365 + 1.366 + if (!mPropertyTable) return NS_OK; 1.367 + 1.368 + nsDependentString propertyName(aPropertyName); 1.369 + mPropertyTable->Remove(propertyName); 1.370 + return NS_OK; 1.371 +} 1.372 + 1.373 +NS_IMETHODIMP 1.374 +nsBoxObject::GetParentBox(nsIDOMElement * *aParentBox) 1.375 +{ 1.376 + *aParentBox = nullptr; 1.377 + nsIFrame* frame = GetFrame(false); 1.378 + if (!frame) return NS_OK; 1.379 + nsIFrame* parent = frame->GetParent(); 1.380 + if (!parent) return NS_OK; 1.381 + 1.382 + nsCOMPtr<nsIDOMElement> el = do_QueryInterface(parent->GetContent()); 1.383 + *aParentBox = el; 1.384 + NS_IF_ADDREF(*aParentBox); 1.385 + return NS_OK; 1.386 +} 1.387 + 1.388 +NS_IMETHODIMP 1.389 +nsBoxObject::GetFirstChild(nsIDOMElement * *aFirstVisibleChild) 1.390 +{ 1.391 + *aFirstVisibleChild = nullptr; 1.392 + nsIFrame* frame = GetFrame(false); 1.393 + if (!frame) return NS_OK; 1.394 + nsIFrame* firstFrame = frame->GetFirstPrincipalChild(); 1.395 + if (!firstFrame) return NS_OK; 1.396 + // get the content for the box and query to a dom element 1.397 + nsCOMPtr<nsIDOMElement> el = do_QueryInterface(firstFrame->GetContent()); 1.398 + el.swap(*aFirstVisibleChild); 1.399 + return NS_OK; 1.400 +} 1.401 + 1.402 +NS_IMETHODIMP 1.403 +nsBoxObject::GetLastChild(nsIDOMElement * *aLastVisibleChild) 1.404 +{ 1.405 + *aLastVisibleChild = nullptr; 1.406 + nsIFrame* frame = GetFrame(false); 1.407 + if (!frame) return NS_OK; 1.408 + return GetPreviousSibling(frame, nullptr, aLastVisibleChild); 1.409 +} 1.410 + 1.411 +NS_IMETHODIMP 1.412 +nsBoxObject::GetNextSibling(nsIDOMElement **aNextOrdinalSibling) 1.413 +{ 1.414 + *aNextOrdinalSibling = nullptr; 1.415 + nsIFrame* frame = GetFrame(false); 1.416 + if (!frame) return NS_OK; 1.417 + nsIFrame* nextFrame = frame->GetNextSibling(); 1.418 + if (!nextFrame) return NS_OK; 1.419 + // get the content for the box and query to a dom element 1.420 + nsCOMPtr<nsIDOMElement> el = do_QueryInterface(nextFrame->GetContent()); 1.421 + el.swap(*aNextOrdinalSibling); 1.422 + return NS_OK; 1.423 +} 1.424 + 1.425 +NS_IMETHODIMP 1.426 +nsBoxObject::GetPreviousSibling(nsIDOMElement **aPreviousOrdinalSibling) 1.427 +{ 1.428 + *aPreviousOrdinalSibling = nullptr; 1.429 + nsIFrame* frame = GetFrame(false); 1.430 + if (!frame) return NS_OK; 1.431 + nsIFrame* parentFrame = frame->GetParent(); 1.432 + if (!parentFrame) return NS_OK; 1.433 + return GetPreviousSibling(parentFrame, frame, aPreviousOrdinalSibling); 1.434 +} 1.435 + 1.436 +nsresult 1.437 +nsBoxObject::GetPreviousSibling(nsIFrame* aParentFrame, nsIFrame* aFrame, 1.438 + nsIDOMElement** aResult) 1.439 +{ 1.440 + *aResult = nullptr; 1.441 + nsIFrame* nextFrame = aParentFrame->GetFirstPrincipalChild(); 1.442 + nsIFrame* prevFrame = nullptr; 1.443 + while (nextFrame) { 1.444 + if (nextFrame == aFrame) 1.445 + break; 1.446 + prevFrame = nextFrame; 1.447 + nextFrame = nextFrame->GetNextSibling(); 1.448 + } 1.449 + 1.450 + if (!prevFrame) return NS_OK; 1.451 + // get the content for the box and query to a dom element 1.452 + nsCOMPtr<nsIDOMElement> el = do_QueryInterface(prevFrame->GetContent()); 1.453 + el.swap(*aResult); 1.454 + return NS_OK; 1.455 +} 1.456 + 1.457 +// Creation Routine /////////////////////////////////////////////////////////////////////// 1.458 + 1.459 +nsresult 1.460 +NS_NewBoxObject(nsIBoxObject** aResult) 1.461 +{ 1.462 + *aResult = new nsBoxObject; 1.463 + if (!*aResult) 1.464 + return NS_ERROR_OUT_OF_MEMORY; 1.465 + NS_ADDREF(*aResult); 1.466 + return NS_OK; 1.467 +} 1.468 +