BoxObject.cpp 14 KB

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