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