|
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/. */ |
|
5 |
|
6 #include "nsCoreUtils.h" |
|
7 |
|
8 #include "nsIAccessibleTypes.h" |
|
9 |
|
10 #include "nsIBaseWindow.h" |
|
11 #include "nsIDocShellTreeOwner.h" |
|
12 #include "nsIDocument.h" |
|
13 #include "nsIDOMHTMLDocument.h" |
|
14 #include "nsIDOMHTMLElement.h" |
|
15 #include "nsRange.h" |
|
16 #include "nsIBoxObject.h" |
|
17 #include "nsIDOMXULElement.h" |
|
18 #include "nsIDocShell.h" |
|
19 #include "nsIPresShell.h" |
|
20 #include "nsPresContext.h" |
|
21 #include "nsIScrollableFrame.h" |
|
22 #include "nsISelectionPrivate.h" |
|
23 #include "nsISelectionController.h" |
|
24 #include "mozilla/dom/TouchEvent.h" |
|
25 #include "mozilla/EventListenerManager.h" |
|
26 #include "mozilla/EventStateManager.h" |
|
27 #include "mozilla/MouseEvents.h" |
|
28 #include "mozilla/TouchEvents.h" |
|
29 #include "nsView.h" |
|
30 #include "nsGkAtoms.h" |
|
31 |
|
32 #include "nsComponentManagerUtils.h" |
|
33 |
|
34 #include "nsITreeBoxObject.h" |
|
35 #include "nsITreeColumns.h" |
|
36 #include "mozilla/dom/Element.h" |
|
37 |
|
38 using namespace mozilla; |
|
39 |
|
40 //////////////////////////////////////////////////////////////////////////////// |
|
41 // nsCoreUtils |
|
42 //////////////////////////////////////////////////////////////////////////////// |
|
43 |
|
44 bool |
|
45 nsCoreUtils::HasClickListener(nsIContent *aContent) |
|
46 { |
|
47 NS_ENSURE_TRUE(aContent, false); |
|
48 EventListenerManager* listenerManager = |
|
49 aContent->GetExistingListenerManager(); |
|
50 |
|
51 return listenerManager && |
|
52 (listenerManager->HasListenersFor(nsGkAtoms::onclick) || |
|
53 listenerManager->HasListenersFor(nsGkAtoms::onmousedown) || |
|
54 listenerManager->HasListenersFor(nsGkAtoms::onmouseup)); |
|
55 } |
|
56 |
|
57 void |
|
58 nsCoreUtils::DispatchClickEvent(nsITreeBoxObject *aTreeBoxObj, |
|
59 int32_t aRowIndex, nsITreeColumn *aColumn, |
|
60 const nsCString& aPseudoElt) |
|
61 { |
|
62 nsCOMPtr<nsIDOMElement> tcElm; |
|
63 aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm)); |
|
64 if (!tcElm) |
|
65 return; |
|
66 |
|
67 nsCOMPtr<nsIContent> tcContent(do_QueryInterface(tcElm)); |
|
68 nsIDocument *document = tcContent->GetCurrentDoc(); |
|
69 if (!document) |
|
70 return; |
|
71 |
|
72 nsCOMPtr<nsIPresShell> presShell = document->GetShell(); |
|
73 if (!presShell) |
|
74 return; |
|
75 |
|
76 // Ensure row is visible. |
|
77 aTreeBoxObj->EnsureRowIsVisible(aRowIndex); |
|
78 |
|
79 // Calculate x and y coordinates. |
|
80 int32_t x = 0, y = 0, width = 0, height = 0; |
|
81 nsresult rv = aTreeBoxObj->GetCoordsForCellItem(aRowIndex, aColumn, |
|
82 aPseudoElt, |
|
83 &x, &y, &width, &height); |
|
84 if (NS_FAILED(rv)) |
|
85 return; |
|
86 |
|
87 nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm)); |
|
88 nsCOMPtr<nsIBoxObject> tcBoxObj; |
|
89 tcXULElm->GetBoxObject(getter_AddRefs(tcBoxObj)); |
|
90 |
|
91 int32_t tcX = 0; |
|
92 tcBoxObj->GetX(&tcX); |
|
93 |
|
94 int32_t tcY = 0; |
|
95 tcBoxObj->GetY(&tcY); |
|
96 |
|
97 // Dispatch mouse events. |
|
98 nsWeakFrame tcFrame = tcContent->GetPrimaryFrame(); |
|
99 nsIFrame* rootFrame = presShell->GetRootFrame(); |
|
100 |
|
101 nsPoint offset; |
|
102 nsIWidget *rootWidget = |
|
103 rootFrame->GetViewExternal()->GetNearestWidget(&offset); |
|
104 |
|
105 nsRefPtr<nsPresContext> presContext = presShell->GetPresContext(); |
|
106 |
|
107 int32_t cnvdX = presContext->CSSPixelsToDevPixels(tcX + x + 1) + |
|
108 presContext->AppUnitsToDevPixels(offset.x); |
|
109 int32_t cnvdY = presContext->CSSPixelsToDevPixels(tcY + y + 1) + |
|
110 presContext->AppUnitsToDevPixels(offset.y); |
|
111 |
|
112 // XUL is just desktop, so there is no real reason for senfing touch events. |
|
113 DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, cnvdX, cnvdY, |
|
114 tcContent, tcFrame, presShell, rootWidget); |
|
115 |
|
116 DispatchMouseEvent(NS_MOUSE_BUTTON_UP, cnvdX, cnvdY, |
|
117 tcContent, tcFrame, presShell, rootWidget); |
|
118 } |
|
119 |
|
120 void |
|
121 nsCoreUtils::DispatchMouseEvent(uint32_t aEventType, int32_t aX, int32_t aY, |
|
122 nsIContent *aContent, nsIFrame *aFrame, |
|
123 nsIPresShell *aPresShell, nsIWidget *aRootWidget) |
|
124 { |
|
125 WidgetMouseEvent event(true, aEventType, aRootWidget, |
|
126 WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal); |
|
127 |
|
128 event.refPoint = LayoutDeviceIntPoint(aX, aY); |
|
129 |
|
130 event.clickCount = 1; |
|
131 event.button = WidgetMouseEvent::eLeftButton; |
|
132 event.time = PR_IntervalNow(); |
|
133 event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN; |
|
134 |
|
135 nsEventStatus status = nsEventStatus_eIgnore; |
|
136 aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status); |
|
137 } |
|
138 |
|
139 void |
|
140 nsCoreUtils::DispatchTouchEvent(uint32_t aEventType, int32_t aX, int32_t aY, |
|
141 nsIContent* aContent, nsIFrame* aFrame, |
|
142 nsIPresShell* aPresShell, nsIWidget* aRootWidget) |
|
143 { |
|
144 if (!dom::TouchEvent::PrefEnabled()) |
|
145 return; |
|
146 |
|
147 WidgetTouchEvent event(true, aEventType, aRootWidget); |
|
148 |
|
149 event.time = PR_IntervalNow(); |
|
150 |
|
151 // XXX: Touch has an identifier of -1 to hint that it is synthesized. |
|
152 nsRefPtr<dom::Touch> t = new dom::Touch(-1, nsIntPoint(aX, aY), |
|
153 nsIntPoint(1, 1), 0.0f, 1.0f); |
|
154 t->SetTarget(aContent); |
|
155 event.touches.AppendElement(t); |
|
156 nsEventStatus status = nsEventStatus_eIgnore; |
|
157 aPresShell->HandleEventWithTarget(&event, aFrame, aContent, &status); |
|
158 } |
|
159 |
|
160 uint32_t |
|
161 nsCoreUtils::GetAccessKeyFor(nsIContent* aContent) |
|
162 { |
|
163 // Accesskeys are registered by @accesskey attribute only. At first check |
|
164 // whether it is presented on the given element to avoid the slow |
|
165 // EventStateManager::GetRegisteredAccessKey() method. |
|
166 if (!aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::accesskey)) |
|
167 return 0; |
|
168 |
|
169 nsIPresShell* presShell = aContent->OwnerDoc()->GetShell(); |
|
170 if (!presShell) |
|
171 return 0; |
|
172 |
|
173 nsPresContext *presContext = presShell->GetPresContext(); |
|
174 if (!presContext) |
|
175 return 0; |
|
176 |
|
177 EventStateManager *esm = presContext->EventStateManager(); |
|
178 if (!esm) |
|
179 return 0; |
|
180 |
|
181 return esm->GetRegisteredAccessKey(aContent); |
|
182 } |
|
183 |
|
184 nsIContent * |
|
185 nsCoreUtils::GetDOMElementFor(nsIContent *aContent) |
|
186 { |
|
187 if (aContent->IsElement()) |
|
188 return aContent; |
|
189 |
|
190 if (aContent->IsNodeOfType(nsINode::eTEXT)) |
|
191 return aContent->GetFlattenedTreeParent(); |
|
192 |
|
193 return nullptr; |
|
194 } |
|
195 |
|
196 nsINode * |
|
197 nsCoreUtils::GetDOMNodeFromDOMPoint(nsINode *aNode, uint32_t aOffset) |
|
198 { |
|
199 if (aNode && aNode->IsElement()) { |
|
200 uint32_t childCount = aNode->GetChildCount(); |
|
201 NS_ASSERTION(aOffset <= childCount, "Wrong offset of the DOM point!"); |
|
202 |
|
203 // The offset can be after last child of container node that means DOM point |
|
204 // is placed immediately after the last child. In this case use the DOM node |
|
205 // from the given DOM point is used as result node. |
|
206 if (aOffset != childCount) |
|
207 return aNode->GetChildAt(aOffset); |
|
208 } |
|
209 |
|
210 return aNode; |
|
211 } |
|
212 |
|
213 nsIContent* |
|
214 nsCoreUtils::GetRoleContent(nsINode *aNode) |
|
215 { |
|
216 nsCOMPtr<nsIContent> content(do_QueryInterface(aNode)); |
|
217 if (!content) { |
|
218 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode)); |
|
219 if (doc) { |
|
220 nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(aNode)); |
|
221 if (htmlDoc) { |
|
222 nsCOMPtr<nsIDOMHTMLElement> bodyElement; |
|
223 htmlDoc->GetBody(getter_AddRefs(bodyElement)); |
|
224 content = do_QueryInterface(bodyElement); |
|
225 } |
|
226 else { |
|
227 return doc->GetDocumentElement(); |
|
228 } |
|
229 } |
|
230 } |
|
231 |
|
232 return content; |
|
233 } |
|
234 |
|
235 bool |
|
236 nsCoreUtils::IsAncestorOf(nsINode *aPossibleAncestorNode, |
|
237 nsINode *aPossibleDescendantNode, |
|
238 nsINode *aRootNode) |
|
239 { |
|
240 NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, false); |
|
241 |
|
242 nsINode *parentNode = aPossibleDescendantNode; |
|
243 while ((parentNode = parentNode->GetParentNode()) && |
|
244 parentNode != aRootNode) { |
|
245 if (parentNode == aPossibleAncestorNode) |
|
246 return true; |
|
247 } |
|
248 |
|
249 return false; |
|
250 } |
|
251 |
|
252 nsresult |
|
253 nsCoreUtils::ScrollSubstringTo(nsIFrame* aFrame, nsRange* aRange, |
|
254 uint32_t aScrollType) |
|
255 { |
|
256 nsIPresShell::ScrollAxis vertical, horizontal; |
|
257 ConvertScrollTypeToPercents(aScrollType, &vertical, &horizontal); |
|
258 |
|
259 return ScrollSubstringTo(aFrame, aRange, vertical, horizontal); |
|
260 } |
|
261 |
|
262 nsresult |
|
263 nsCoreUtils::ScrollSubstringTo(nsIFrame* aFrame, nsRange* aRange, |
|
264 nsIPresShell::ScrollAxis aVertical, |
|
265 nsIPresShell::ScrollAxis aHorizontal) |
|
266 { |
|
267 if (!aFrame) |
|
268 return NS_ERROR_FAILURE; |
|
269 |
|
270 nsPresContext *presContext = aFrame->PresContext(); |
|
271 |
|
272 nsCOMPtr<nsISelectionController> selCon; |
|
273 aFrame->GetSelectionController(presContext, getter_AddRefs(selCon)); |
|
274 NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); |
|
275 |
|
276 nsCOMPtr<nsISelection> selection; |
|
277 selCon->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY, |
|
278 getter_AddRefs(selection)); |
|
279 |
|
280 nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(selection)); |
|
281 selection->RemoveAllRanges(); |
|
282 selection->AddRange(aRange); |
|
283 |
|
284 privSel->ScrollIntoViewInternal( |
|
285 nsISelectionController::SELECTION_ANCHOR_REGION, |
|
286 true, aVertical, aHorizontal); |
|
287 |
|
288 selection->CollapseToStart(); |
|
289 |
|
290 return NS_OK; |
|
291 } |
|
292 |
|
293 void |
|
294 nsCoreUtils::ScrollFrameToPoint(nsIFrame *aScrollableFrame, |
|
295 nsIFrame *aFrame, |
|
296 const nsIntPoint& aPoint) |
|
297 { |
|
298 nsIScrollableFrame* scrollableFrame = do_QueryFrame(aScrollableFrame); |
|
299 if (!scrollableFrame) |
|
300 return; |
|
301 |
|
302 nsPoint point = |
|
303 aPoint.ToAppUnits(aFrame->PresContext()->AppUnitsPerDevPixel()); |
|
304 nsRect frameRect = aFrame->GetScreenRectInAppUnits(); |
|
305 nsPoint deltaPoint(point.x - frameRect.x, point.y - frameRect.y); |
|
306 |
|
307 nsPoint scrollPoint = scrollableFrame->GetScrollPosition(); |
|
308 scrollPoint -= deltaPoint; |
|
309 |
|
310 scrollableFrame->ScrollTo(scrollPoint, nsIScrollableFrame::INSTANT); |
|
311 } |
|
312 |
|
313 void |
|
314 nsCoreUtils::ConvertScrollTypeToPercents(uint32_t aScrollType, |
|
315 nsIPresShell::ScrollAxis *aVertical, |
|
316 nsIPresShell::ScrollAxis *aHorizontal) |
|
317 { |
|
318 int16_t whereY, whereX; |
|
319 nsIPresShell::WhenToScroll whenY, whenX; |
|
320 switch (aScrollType) |
|
321 { |
|
322 case nsIAccessibleScrollType::SCROLL_TYPE_TOP_LEFT: |
|
323 whereY = nsIPresShell::SCROLL_TOP; |
|
324 whenY = nsIPresShell::SCROLL_ALWAYS; |
|
325 whereX = nsIPresShell::SCROLL_LEFT; |
|
326 whenX = nsIPresShell::SCROLL_ALWAYS; |
|
327 break; |
|
328 case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_RIGHT: |
|
329 whereY = nsIPresShell::SCROLL_BOTTOM; |
|
330 whenY = nsIPresShell::SCROLL_ALWAYS; |
|
331 whereX = nsIPresShell::SCROLL_RIGHT; |
|
332 whenX = nsIPresShell::SCROLL_ALWAYS; |
|
333 break; |
|
334 case nsIAccessibleScrollType::SCROLL_TYPE_TOP_EDGE: |
|
335 whereY = nsIPresShell::SCROLL_TOP; |
|
336 whenY = nsIPresShell::SCROLL_ALWAYS; |
|
337 whereX = nsIPresShell::SCROLL_MINIMUM; |
|
338 whenX = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
339 break; |
|
340 case nsIAccessibleScrollType::SCROLL_TYPE_BOTTOM_EDGE: |
|
341 whereY = nsIPresShell::SCROLL_BOTTOM; |
|
342 whenY = nsIPresShell::SCROLL_ALWAYS; |
|
343 whereX = nsIPresShell::SCROLL_MINIMUM; |
|
344 whenX = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
345 break; |
|
346 case nsIAccessibleScrollType::SCROLL_TYPE_LEFT_EDGE: |
|
347 whereY = nsIPresShell::SCROLL_MINIMUM; |
|
348 whenY = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
349 whereX = nsIPresShell::SCROLL_LEFT; |
|
350 whenX = nsIPresShell::SCROLL_ALWAYS; |
|
351 break; |
|
352 case nsIAccessibleScrollType::SCROLL_TYPE_RIGHT_EDGE: |
|
353 whereY = nsIPresShell::SCROLL_MINIMUM; |
|
354 whenY = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
355 whereX = nsIPresShell::SCROLL_RIGHT; |
|
356 whenX = nsIPresShell::SCROLL_ALWAYS; |
|
357 break; |
|
358 default: |
|
359 whereY = nsIPresShell::SCROLL_MINIMUM; |
|
360 whenY = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
361 whereX = nsIPresShell::SCROLL_MINIMUM; |
|
362 whenX = nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; |
|
363 } |
|
364 *aVertical = nsIPresShell::ScrollAxis(whereY, whenY); |
|
365 *aHorizontal = nsIPresShell::ScrollAxis(whereX, whenX); |
|
366 } |
|
367 |
|
368 nsIntPoint |
|
369 nsCoreUtils::GetScreenCoordsForWindow(nsINode *aNode) |
|
370 { |
|
371 nsIntPoint coords(0, 0); |
|
372 nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShellFor(aNode)); |
|
373 if (!treeItem) |
|
374 return coords; |
|
375 |
|
376 nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
|
377 treeItem->GetTreeOwner(getter_AddRefs(treeOwner)); |
|
378 if (!treeOwner) |
|
379 return coords; |
|
380 |
|
381 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner); |
|
382 if (baseWindow) |
|
383 baseWindow->GetPosition(&coords.x, &coords.y); // in device pixels |
|
384 |
|
385 return coords; |
|
386 } |
|
387 |
|
388 already_AddRefed<nsIDocShell> |
|
389 nsCoreUtils::GetDocShellFor(nsINode *aNode) |
|
390 { |
|
391 if (!aNode) |
|
392 return nullptr; |
|
393 |
|
394 nsCOMPtr<nsIDocShell> docShell = aNode->OwnerDoc()->GetDocShell(); |
|
395 return docShell.forget(); |
|
396 } |
|
397 |
|
398 bool |
|
399 nsCoreUtils::IsRootDocument(nsIDocument *aDocument) |
|
400 { |
|
401 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell(); |
|
402 NS_ASSERTION(docShellTreeItem, "No document shell for document!"); |
|
403 |
|
404 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; |
|
405 docShellTreeItem->GetParent(getter_AddRefs(parentTreeItem)); |
|
406 |
|
407 return !parentTreeItem; |
|
408 } |
|
409 |
|
410 bool |
|
411 nsCoreUtils::IsContentDocument(nsIDocument *aDocument) |
|
412 { |
|
413 nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem = aDocument->GetDocShell(); |
|
414 NS_ASSERTION(docShellTreeItem, "No document shell tree item for document!"); |
|
415 |
|
416 return (docShellTreeItem->ItemType() == nsIDocShellTreeItem::typeContent); |
|
417 } |
|
418 |
|
419 bool |
|
420 nsCoreUtils::IsTabDocument(nsIDocument* aDocumentNode) |
|
421 { |
|
422 nsCOMPtr<nsIDocShellTreeItem> treeItem(aDocumentNode->GetDocShell()); |
|
423 |
|
424 nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; |
|
425 treeItem->GetParent(getter_AddRefs(parentTreeItem)); |
|
426 |
|
427 // Tab document running in own process doesn't have parent. |
|
428 if (XRE_GetProcessType() == GeckoProcessType_Content) |
|
429 return !parentTreeItem; |
|
430 |
|
431 // Parent of docshell for tab document running in chrome process is root. |
|
432 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; |
|
433 treeItem->GetRootTreeItem(getter_AddRefs(rootTreeItem)); |
|
434 |
|
435 return parentTreeItem == rootTreeItem; |
|
436 } |
|
437 |
|
438 bool |
|
439 nsCoreUtils::IsErrorPage(nsIDocument *aDocument) |
|
440 { |
|
441 nsIURI *uri = aDocument->GetDocumentURI(); |
|
442 bool isAboutScheme = false; |
|
443 uri->SchemeIs("about", &isAboutScheme); |
|
444 if (!isAboutScheme) |
|
445 return false; |
|
446 |
|
447 nsAutoCString path; |
|
448 uri->GetPath(path); |
|
449 |
|
450 NS_NAMED_LITERAL_CSTRING(neterror, "neterror"); |
|
451 NS_NAMED_LITERAL_CSTRING(certerror, "certerror"); |
|
452 |
|
453 return StringBeginsWith(path, neterror) || StringBeginsWith(path, certerror); |
|
454 } |
|
455 |
|
456 bool |
|
457 nsCoreUtils::GetID(nsIContent *aContent, nsAString& aID) |
|
458 { |
|
459 nsIAtom *idAttribute = aContent->GetIDAttributeName(); |
|
460 return idAttribute ? aContent->GetAttr(kNameSpaceID_None, idAttribute, aID) : false; |
|
461 } |
|
462 |
|
463 bool |
|
464 nsCoreUtils::GetUIntAttr(nsIContent *aContent, nsIAtom *aAttr, int32_t *aUInt) |
|
465 { |
|
466 nsAutoString value; |
|
467 aContent->GetAttr(kNameSpaceID_None, aAttr, value); |
|
468 if (!value.IsEmpty()) { |
|
469 nsresult error = NS_OK; |
|
470 int32_t integer = value.ToInteger(&error); |
|
471 if (NS_SUCCEEDED(error) && integer > 0) { |
|
472 *aUInt = integer; |
|
473 return true; |
|
474 } |
|
475 } |
|
476 |
|
477 return false; |
|
478 } |
|
479 |
|
480 void |
|
481 nsCoreUtils::GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent, |
|
482 nsAString& aLanguage) |
|
483 { |
|
484 aLanguage.Truncate(); |
|
485 |
|
486 nsIContent *walkUp = aContent; |
|
487 while (walkUp && walkUp != aRootContent && |
|
488 !walkUp->GetAttr(kNameSpaceID_None, nsGkAtoms::lang, aLanguage)) |
|
489 walkUp = walkUp->GetParent(); |
|
490 } |
|
491 |
|
492 already_AddRefed<nsIBoxObject> |
|
493 nsCoreUtils::GetTreeBodyBoxObject(nsITreeBoxObject *aTreeBoxObj) |
|
494 { |
|
495 nsCOMPtr<nsIDOMElement> tcElm; |
|
496 aTreeBoxObj->GetTreeBody(getter_AddRefs(tcElm)); |
|
497 nsCOMPtr<nsIDOMXULElement> tcXULElm(do_QueryInterface(tcElm)); |
|
498 if (!tcXULElm) |
|
499 return nullptr; |
|
500 |
|
501 nsCOMPtr<nsIBoxObject> boxObj; |
|
502 tcXULElm->GetBoxObject(getter_AddRefs(boxObj)); |
|
503 return boxObj.forget(); |
|
504 } |
|
505 |
|
506 already_AddRefed<nsITreeBoxObject> |
|
507 nsCoreUtils::GetTreeBoxObject(nsIContent *aContent) |
|
508 { |
|
509 // Find DOMNode's parents recursively until reach the <tree> tag |
|
510 nsIContent* currentContent = aContent; |
|
511 while (currentContent) { |
|
512 if (currentContent->NodeInfo()->Equals(nsGkAtoms::tree, |
|
513 kNameSpaceID_XUL)) { |
|
514 // We will get the nsITreeBoxObject from the tree node |
|
515 nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(currentContent)); |
|
516 if (xulElement) { |
|
517 nsCOMPtr<nsIBoxObject> box; |
|
518 xulElement->GetBoxObject(getter_AddRefs(box)); |
|
519 nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box)); |
|
520 if (treeBox) |
|
521 return treeBox.forget(); |
|
522 } |
|
523 } |
|
524 currentContent = currentContent->GetFlattenedTreeParent(); |
|
525 } |
|
526 |
|
527 return nullptr; |
|
528 } |
|
529 |
|
530 already_AddRefed<nsITreeColumn> |
|
531 nsCoreUtils::GetFirstSensibleColumn(nsITreeBoxObject *aTree) |
|
532 { |
|
533 nsCOMPtr<nsITreeColumns> cols; |
|
534 aTree->GetColumns(getter_AddRefs(cols)); |
|
535 if (!cols) |
|
536 return nullptr; |
|
537 |
|
538 nsCOMPtr<nsITreeColumn> column; |
|
539 cols->GetFirstColumn(getter_AddRefs(column)); |
|
540 if (column && IsColumnHidden(column)) |
|
541 return GetNextSensibleColumn(column); |
|
542 |
|
543 return column.forget(); |
|
544 } |
|
545 |
|
546 uint32_t |
|
547 nsCoreUtils::GetSensibleColumnCount(nsITreeBoxObject *aTree) |
|
548 { |
|
549 uint32_t count = 0; |
|
550 |
|
551 nsCOMPtr<nsITreeColumns> cols; |
|
552 aTree->GetColumns(getter_AddRefs(cols)); |
|
553 if (!cols) |
|
554 return count; |
|
555 |
|
556 nsCOMPtr<nsITreeColumn> column; |
|
557 cols->GetFirstColumn(getter_AddRefs(column)); |
|
558 |
|
559 while (column) { |
|
560 if (!IsColumnHidden(column)) |
|
561 count++; |
|
562 |
|
563 nsCOMPtr<nsITreeColumn> nextColumn; |
|
564 column->GetNext(getter_AddRefs(nextColumn)); |
|
565 column.swap(nextColumn); |
|
566 } |
|
567 |
|
568 return count; |
|
569 } |
|
570 |
|
571 already_AddRefed<nsITreeColumn> |
|
572 nsCoreUtils::GetSensibleColumnAt(nsITreeBoxObject *aTree, uint32_t aIndex) |
|
573 { |
|
574 uint32_t idx = aIndex; |
|
575 |
|
576 nsCOMPtr<nsITreeColumn> column = GetFirstSensibleColumn(aTree); |
|
577 while (column) { |
|
578 if (idx == 0) |
|
579 return column.forget(); |
|
580 |
|
581 idx--; |
|
582 column = GetNextSensibleColumn(column); |
|
583 } |
|
584 |
|
585 return nullptr; |
|
586 } |
|
587 |
|
588 already_AddRefed<nsITreeColumn> |
|
589 nsCoreUtils::GetNextSensibleColumn(nsITreeColumn *aColumn) |
|
590 { |
|
591 nsCOMPtr<nsITreeColumn> nextColumn; |
|
592 aColumn->GetNext(getter_AddRefs(nextColumn)); |
|
593 |
|
594 while (nextColumn && IsColumnHidden(nextColumn)) { |
|
595 nsCOMPtr<nsITreeColumn> tempColumn; |
|
596 nextColumn->GetNext(getter_AddRefs(tempColumn)); |
|
597 nextColumn.swap(tempColumn); |
|
598 } |
|
599 |
|
600 return nextColumn.forget(); |
|
601 } |
|
602 |
|
603 already_AddRefed<nsITreeColumn> |
|
604 nsCoreUtils::GetPreviousSensibleColumn(nsITreeColumn *aColumn) |
|
605 { |
|
606 nsCOMPtr<nsITreeColumn> prevColumn; |
|
607 aColumn->GetPrevious(getter_AddRefs(prevColumn)); |
|
608 |
|
609 while (prevColumn && IsColumnHidden(prevColumn)) { |
|
610 nsCOMPtr<nsITreeColumn> tempColumn; |
|
611 prevColumn->GetPrevious(getter_AddRefs(tempColumn)); |
|
612 prevColumn.swap(tempColumn); |
|
613 } |
|
614 |
|
615 return prevColumn.forget(); |
|
616 } |
|
617 |
|
618 bool |
|
619 nsCoreUtils::IsColumnHidden(nsITreeColumn *aColumn) |
|
620 { |
|
621 nsCOMPtr<nsIDOMElement> element; |
|
622 aColumn->GetElement(getter_AddRefs(element)); |
|
623 nsCOMPtr<nsIContent> content = do_QueryInterface(element); |
|
624 return content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden, |
|
625 nsGkAtoms::_true, eCaseMatters); |
|
626 } |
|
627 |
|
628 void |
|
629 nsCoreUtils::ScrollTo(nsIPresShell* aPresShell, nsIContent* aContent, |
|
630 uint32_t aScrollType) |
|
631 { |
|
632 nsIPresShell::ScrollAxis vertical, horizontal; |
|
633 ConvertScrollTypeToPercents(aScrollType, &vertical, &horizontal); |
|
634 aPresShell->ScrollContentIntoView(aContent, vertical, horizontal, |
|
635 nsIPresShell::SCROLL_OVERFLOW_HIDDEN); |
|
636 } |
|
637 |
|
638 bool |
|
639 nsCoreUtils::IsWhitespaceString(const nsSubstring& aString) |
|
640 { |
|
641 nsSubstring::const_char_iterator iterBegin, iterEnd; |
|
642 |
|
643 aString.BeginReading(iterBegin); |
|
644 aString.EndReading(iterEnd); |
|
645 |
|
646 while (iterBegin != iterEnd && IsWhitespace(*iterBegin)) |
|
647 ++iterBegin; |
|
648 |
|
649 return iterBegin == iterEnd; |
|
650 } |