1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2002
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Brian Ryner <bryner@brianryner.com> (Original Author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsNativeTheme.h"
40 : #include "nsIWidget.h"
41 : #include "nsIDocument.h"
42 : #include "nsIContent.h"
43 : #include "nsIFrame.h"
44 : #include "nsIPresShell.h"
45 : #include "nsPresContext.h"
46 : #include "nsEventStateManager.h"
47 : #include "nsString.h"
48 : #include "nsINameSpaceManager.h"
49 : #include "nsIDOMHTMLInputElement.h"
50 : #include "nsIDOMXULMenuListElement.h"
51 : #include "nsThemeConstants.h"
52 : #include "nsIComponentManager.h"
53 : #include "nsPIDOMWindow.h"
54 : #include "nsProgressFrame.h"
55 : #include "nsMenuFrame.h"
56 : #include "mozilla/dom/Element.h"
57 :
58 0 : nsNativeTheme::nsNativeTheme()
59 0 : : mAnimatedContentTimeout(PR_UINT32_MAX)
60 : {
61 0 : }
62 :
63 0 : NS_IMPL_ISUPPORTS1(nsNativeTheme, nsITimerCallback)
64 :
65 : nsIPresShell *
66 0 : nsNativeTheme::GetPresShell(nsIFrame* aFrame)
67 : {
68 0 : if (!aFrame)
69 0 : return nsnull;
70 :
71 : // this is a workaround for the egcs 1.1.2 not inliningg
72 : // aFrame->GetPresContext(), which causes an undefined symbol
73 0 : nsPresContext *context = aFrame->GetStyleContext()->GetRuleNode()->GetPresContext();
74 0 : return context ? context->GetPresShell() : nsnull;
75 : }
76 :
77 : nsEventStates
78 0 : nsNativeTheme::GetContentState(nsIFrame* aFrame, PRUint8 aWidgetType)
79 : {
80 0 : if (!aFrame)
81 0 : return nsEventStates();
82 :
83 : bool isXULCheckboxRadio =
84 : (aWidgetType == NS_THEME_CHECKBOX ||
85 : aWidgetType == NS_THEME_RADIO) &&
86 0 : aFrame->GetContent()->IsXUL();
87 0 : if (isXULCheckboxRadio)
88 0 : aFrame = aFrame->GetParent();
89 :
90 0 : if (!aFrame->GetContent())
91 0 : return nsEventStates();
92 :
93 0 : nsIPresShell *shell = GetPresShell(aFrame);
94 0 : if (!shell)
95 0 : return nsEventStates();
96 :
97 0 : nsIContent* frameContent = aFrame->GetContent();
98 0 : nsEventStates flags;
99 0 : if (frameContent->IsElement()) {
100 0 : flags = frameContent->AsElement()->State();
101 : }
102 :
103 0 : if (isXULCheckboxRadio && aWidgetType == NS_THEME_RADIO) {
104 0 : if (IsFocused(aFrame))
105 0 : flags |= NS_EVENT_STATE_FOCUS;
106 : }
107 :
108 : // On Windows and Mac, only draw focus rings if they should be shown. This
109 : // means that focus rings are only shown once the keyboard has been used to
110 : // focus something in the window.
111 : #if defined(XP_MACOSX)
112 : // Mac always draws focus rings for textboxes and lists.
113 : if (aWidgetType == NS_THEME_TEXTFIELD ||
114 : aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
115 : aWidgetType == NS_THEME_SEARCHFIELD ||
116 : aWidgetType == NS_THEME_LISTBOX) {
117 : return flags;
118 : }
119 : #endif
120 : #if defined(XP_WIN)
121 : // On Windows, focused buttons are always drawn as such by the native theme.
122 : if (aWidgetType == NS_THEME_BUTTON)
123 : return flags;
124 : #endif
125 : #if defined(XP_MACOSX) || defined(XP_WIN)
126 : nsIDocument* doc = aFrame->GetContent()->OwnerDoc();
127 : nsPIDOMWindow* window = doc->GetWindow();
128 : if (window && !window->ShouldShowFocusRing())
129 : flags &= ~NS_EVENT_STATE_FOCUS;
130 : #endif
131 :
132 0 : return flags;
133 : }
134 :
135 : bool
136 0 : nsNativeTheme::CheckBooleanAttr(nsIFrame* aFrame, nsIAtom* aAtom)
137 : {
138 0 : if (!aFrame)
139 0 : return false;
140 :
141 0 : nsIContent* content = aFrame->GetContent();
142 0 : if (!content)
143 0 : return false;
144 :
145 0 : if (content->IsHTML())
146 0 : return content->HasAttr(kNameSpaceID_None, aAtom);
147 :
148 : // For XML/XUL elements, an attribute must be equal to the literal
149 : // string "true" to be counted as true. An empty string should _not_
150 : // be counted as true.
151 : return content->AttrValueIs(kNameSpaceID_None, aAtom,
152 0 : NS_LITERAL_STRING("true"), eCaseMatters);
153 : }
154 :
155 : PRInt32
156 0 : nsNativeTheme::CheckIntAttr(nsIFrame* aFrame, nsIAtom* aAtom, PRInt32 defaultValue)
157 : {
158 0 : if (!aFrame)
159 0 : return defaultValue;
160 :
161 0 : nsAutoString attr;
162 0 : aFrame->GetContent()->GetAttr(kNameSpaceID_None, aAtom, attr);
163 0 : PRInt32 err, value = attr.ToInteger(&err);
164 0 : if (attr.IsEmpty() || NS_FAILED(err))
165 0 : return defaultValue;
166 :
167 0 : return value;
168 : }
169 :
170 : bool
171 0 : nsNativeTheme::GetCheckedOrSelected(nsIFrame* aFrame, bool aCheckSelected)
172 : {
173 0 : if (!aFrame)
174 0 : return false;
175 :
176 0 : nsIContent* content = aFrame->GetContent();
177 :
178 0 : if (content->IsXUL()) {
179 : // For a XUL checkbox or radio button, the state of the parent determines
180 : // the checked state
181 0 : aFrame = aFrame->GetParent();
182 : } else {
183 : // Check for an HTML input element
184 0 : nsCOMPtr<nsIDOMHTMLInputElement> inputElt = do_QueryInterface(content);
185 0 : if (inputElt) {
186 : bool checked;
187 0 : inputElt->GetChecked(&checked);
188 0 : return checked;
189 : }
190 : }
191 :
192 : return CheckBooleanAttr(aFrame, aCheckSelected ? nsGkAtoms::selected
193 0 : : nsGkAtoms::checked);
194 : }
195 :
196 : bool
197 0 : nsNativeTheme::IsButtonTypeMenu(nsIFrame* aFrame)
198 : {
199 0 : if (!aFrame)
200 0 : return false;
201 :
202 0 : nsIContent* content = aFrame->GetContent();
203 : return content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
204 0 : NS_LITERAL_STRING("menu"), eCaseMatters);
205 : }
206 :
207 : bool
208 0 : nsNativeTheme::IsPressedButton(nsIFrame* aFrame)
209 : {
210 0 : nsEventStates eventState = GetContentState(aFrame, NS_THEME_TOOLBAR_BUTTON);
211 0 : if (IsDisabled(aFrame, eventState))
212 0 : return false;
213 :
214 0 : return IsOpenButton(aFrame) ||
215 0 : eventState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER);
216 : }
217 :
218 :
219 : bool
220 0 : nsNativeTheme::GetIndeterminate(nsIFrame* aFrame)
221 : {
222 0 : if (!aFrame)
223 0 : return false;
224 :
225 0 : nsIContent* content = aFrame->GetContent();
226 :
227 0 : if (content->IsXUL()) {
228 : // For a XUL checkbox or radio button, the state of the parent determines
229 : // the state
230 0 : return CheckBooleanAttr(aFrame->GetParent(), nsGkAtoms::indeterminate);
231 : }
232 :
233 : // Check for an HTML input element
234 0 : nsCOMPtr<nsIDOMHTMLInputElement> inputElt = do_QueryInterface(content);
235 0 : if (inputElt) {
236 : bool indeterminate;
237 0 : inputElt->GetIndeterminate(&indeterminate);
238 0 : return indeterminate;
239 : }
240 :
241 0 : return false;
242 : }
243 :
244 : bool
245 0 : nsNativeTheme::IsWidgetStyled(nsPresContext* aPresContext, nsIFrame* aFrame,
246 : PRUint8 aWidgetType)
247 : {
248 : // Check for specific widgets to see if HTML has overridden the style.
249 0 : if (!aFrame)
250 0 : return false;
251 :
252 : // Resizers have some special handling, dependent on whether in a scrollable
253 : // container or not. If so, use the scrollable container's to determine
254 : // whether the style is overriden instead of the resizer. This allows a
255 : // non-native transparent resizer to be used instead. Otherwise, we just
256 : // fall through and return false.
257 0 : if (aWidgetType == NS_THEME_RESIZER) {
258 0 : nsIFrame* parentFrame = aFrame->GetParent();
259 0 : if (parentFrame && parentFrame->GetType() == nsGkAtoms::scrollFrame) {
260 : // if the parent is a scrollframe, the resizer should be native themed
261 : // only if the scrollable area doesn't override the widget style.
262 0 : parentFrame = parentFrame->GetParent();
263 0 : if (parentFrame) {
264 : return IsWidgetStyled(aPresContext, parentFrame,
265 0 : parentFrame->GetStyleDisplay()->mAppearance);
266 : }
267 : }
268 : }
269 :
270 : /**
271 : * Progress bar appearance should be the same for the bar and the container
272 : * frame. nsProgressFrame owns the logic and will tell us what we should do.
273 : */
274 0 : if (aWidgetType == NS_THEME_PROGRESSBAR_CHUNK ||
275 : aWidgetType == NS_THEME_PROGRESSBAR) {
276 : nsProgressFrame* progressFrame = do_QueryFrame(aWidgetType == NS_THEME_PROGRESSBAR_CHUNK
277 0 : ? aFrame->GetParent() : aFrame);
278 0 : if (progressFrame) {
279 0 : return !progressFrame->ShouldUseNativeStyle();
280 : }
281 : }
282 :
283 : return (aWidgetType == NS_THEME_BUTTON ||
284 : aWidgetType == NS_THEME_TEXTFIELD ||
285 : aWidgetType == NS_THEME_TEXTFIELD_MULTILINE ||
286 : aWidgetType == NS_THEME_LISTBOX ||
287 : aWidgetType == NS_THEME_DROPDOWN) &&
288 0 : aFrame->GetContent()->IsHTML() &&
289 : aPresContext->HasAuthorSpecifiedRules(aFrame,
290 : NS_AUTHOR_SPECIFIED_BORDER |
291 0 : NS_AUTHOR_SPECIFIED_BACKGROUND);
292 : }
293 :
294 : bool
295 0 : nsNativeTheme::IsDisabled(nsIFrame* aFrame, nsEventStates aEventStates)
296 : {
297 0 : if (!aFrame) {
298 0 : return false;
299 : }
300 :
301 0 : nsIContent* content = aFrame->GetContent();
302 0 : if (!content) {
303 0 : return false;
304 : }
305 :
306 0 : if (content->IsHTML()) {
307 0 : return aEventStates.HasState(NS_EVENT_STATE_DISABLED);
308 : }
309 :
310 : // For XML/XUL elements, an attribute must be equal to the literal
311 : // string "true" to be counted as true. An empty string should _not_
312 : // be counted as true.
313 : return content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
314 0 : NS_LITERAL_STRING("true"), eCaseMatters);
315 : }
316 :
317 : bool
318 0 : nsNativeTheme::IsFrameRTL(nsIFrame* aFrame)
319 : {
320 0 : return aFrame && aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
321 : }
322 :
323 : // scrollbar button:
324 : PRInt32
325 0 : nsNativeTheme::GetScrollbarButtonType(nsIFrame* aFrame)
326 : {
327 0 : if (!aFrame)
328 0 : return 0;
329 :
330 : static nsIContent::AttrValuesArray strings[] =
331 : {&nsGkAtoms::scrollbarDownBottom, &nsGkAtoms::scrollbarDownTop,
332 : &nsGkAtoms::scrollbarUpBottom, &nsGkAtoms::scrollbarUpTop,
333 : nsnull};
334 :
335 0 : switch (aFrame->GetContent()->FindAttrValueIn(kNameSpaceID_None,
336 : nsGkAtoms::sbattr,
337 0 : strings, eCaseMatters)) {
338 0 : case 0: return eScrollbarButton_Down | eScrollbarButton_Bottom;
339 0 : case 1: return eScrollbarButton_Down;
340 0 : case 2: return eScrollbarButton_Bottom;
341 0 : case 3: return eScrollbarButton_UpTop;
342 : }
343 :
344 0 : return 0;
345 : }
346 :
347 : // treeheadercell:
348 : nsNativeTheme::TreeSortDirection
349 0 : nsNativeTheme::GetTreeSortDirection(nsIFrame* aFrame)
350 : {
351 0 : if (!aFrame || !aFrame->GetContent())
352 0 : return eTreeSortDirection_Natural;
353 :
354 : static nsIContent::AttrValuesArray strings[] =
355 : {&nsGkAtoms::descending, &nsGkAtoms::ascending, nsnull};
356 0 : switch (aFrame->GetContent()->FindAttrValueIn(kNameSpaceID_None,
357 : nsGkAtoms::sortDirection,
358 0 : strings, eCaseMatters)) {
359 0 : case 0: return eTreeSortDirection_Descending;
360 0 : case 1: return eTreeSortDirection_Ascending;
361 : }
362 :
363 0 : return eTreeSortDirection_Natural;
364 : }
365 :
366 : bool
367 0 : nsNativeTheme::IsLastTreeHeaderCell(nsIFrame* aFrame)
368 : {
369 0 : if (!aFrame)
370 0 : return false;
371 :
372 : // A tree column picker is always the last header cell.
373 0 : if (aFrame->GetContent()->Tag() == nsGkAtoms::treecolpicker)
374 0 : return true;
375 :
376 : // Find the parent tree.
377 0 : nsIContent* parent = aFrame->GetContent()->GetParent();
378 0 : while (parent && parent->Tag() != nsGkAtoms::tree) {
379 0 : parent = parent->GetParent();
380 : }
381 :
382 : // If the column picker is visible, this can't be the last column.
383 0 : if (parent && !parent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidecolumnpicker,
384 0 : NS_LITERAL_STRING("true"), eCaseMatters))
385 0 : return false;
386 :
387 0 : while ((aFrame = aFrame->GetNextSibling())) {
388 0 : if (aFrame->GetRect().width > 0)
389 0 : return false;
390 : }
391 0 : return true;
392 : }
393 :
394 : // tab:
395 : bool
396 0 : nsNativeTheme::IsBottomTab(nsIFrame* aFrame)
397 : {
398 0 : if (!aFrame)
399 0 : return false;
400 :
401 0 : nsAutoString classStr;
402 0 : aFrame->GetContent()->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, classStr);
403 0 : return !classStr.IsEmpty() && classStr.Find("tab-bottom") != kNotFound;
404 : }
405 :
406 : bool
407 0 : nsNativeTheme::IsFirstTab(nsIFrame* aFrame)
408 : {
409 0 : if (!aFrame)
410 0 : return false;
411 :
412 0 : nsIFrame* first = aFrame->GetParent()->GetFirstPrincipalChild();
413 0 : while (first) {
414 0 : if (first->GetRect().width > 0 && first->GetContent()->Tag() == nsGkAtoms::tab)
415 0 : return (first == aFrame);
416 0 : first = first->GetNextSibling();
417 : }
418 0 : return false;
419 : }
420 :
421 : bool
422 0 : nsNativeTheme::IsHorizontal(nsIFrame* aFrame)
423 : {
424 0 : if (!aFrame)
425 0 : return false;
426 :
427 0 : return !aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
428 : nsGkAtoms::vertical,
429 0 : eCaseMatters);
430 : }
431 :
432 : bool
433 0 : nsNativeTheme::IsNextToSelectedTab(nsIFrame* aFrame, PRInt32 aOffset)
434 : {
435 0 : if (!aFrame)
436 0 : return false;
437 :
438 0 : if (aOffset == 0)
439 0 : return IsSelectedTab(aFrame);
440 :
441 0 : PRInt32 thisTabIndex = -1, selectedTabIndex = -1;
442 :
443 0 : nsIFrame* currentTab = aFrame->GetParent()->GetFirstPrincipalChild();
444 0 : for (PRInt32 i = 0; currentTab; currentTab = currentTab->GetNextSibling()) {
445 0 : if (currentTab->GetRect().width == 0)
446 0 : continue;
447 0 : if (aFrame == currentTab)
448 0 : thisTabIndex = i;
449 0 : if (IsSelectedTab(currentTab))
450 0 : selectedTabIndex = i;
451 0 : ++i;
452 : }
453 :
454 0 : if (thisTabIndex == -1 || selectedTabIndex == -1)
455 0 : return false;
456 :
457 0 : return (thisTabIndex - selectedTabIndex == aOffset);
458 : }
459 :
460 : // progressbar:
461 : bool
462 0 : nsNativeTheme::IsIndeterminateProgress(nsIFrame* aFrame,
463 : nsEventStates aEventStates)
464 : {
465 0 : if (!aFrame || !aFrame->GetContent())
466 0 : return false;
467 :
468 0 : if (aFrame->GetContent()->IsHTML(nsGkAtoms::progress)) {
469 0 : return aEventStates.HasState(NS_EVENT_STATE_INDETERMINATE);
470 : }
471 :
472 0 : return aFrame->GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mode,
473 0 : NS_LITERAL_STRING("undetermined"),
474 0 : eCaseMatters);
475 : }
476 :
477 : bool
478 0 : nsNativeTheme::IsVerticalProgress(nsIFrame* aFrame)
479 : {
480 : return aFrame &&
481 0 : aFrame->GetStyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
482 : }
483 :
484 : // menupopup:
485 : bool
486 0 : nsNativeTheme::IsSubmenu(nsIFrame* aFrame, bool* aLeftOfParent)
487 : {
488 0 : if (!aFrame)
489 0 : return false;
490 :
491 0 : nsIContent* parentContent = aFrame->GetContent()->GetParent();
492 0 : if (!parentContent || parentContent->Tag() != nsGkAtoms::menu)
493 0 : return false;
494 :
495 0 : nsIFrame* parent = aFrame;
496 0 : while ((parent = parent->GetParent())) {
497 0 : if (parent->GetContent() == parentContent) {
498 0 : if (aLeftOfParent) {
499 0 : nsIntRect selfBounds, parentBounds;
500 0 : aFrame->GetNearestWidget()->GetScreenBounds(selfBounds);
501 0 : parent->GetNearestWidget()->GetScreenBounds(parentBounds);
502 0 : *aLeftOfParent = selfBounds.x < parentBounds.x;
503 : }
504 0 : return true;
505 : }
506 : }
507 :
508 0 : return false;
509 : }
510 :
511 : bool
512 0 : nsNativeTheme::IsRegularMenuItem(nsIFrame *aFrame)
513 : {
514 0 : nsMenuFrame *menuFrame = do_QueryFrame(aFrame);
515 0 : return !(menuFrame && (menuFrame->IsOnMenuBar() ||
516 0 : menuFrame->GetParentMenuListType() != eNotMenuList));
517 : }
518 :
519 : bool
520 0 : nsNativeTheme::IsMenuListEditable(nsIFrame *aFrame)
521 : {
522 0 : bool isEditable = false;
523 0 : nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aFrame->GetContent());
524 0 : if (menulist)
525 0 : menulist->GetEditable(&isEditable);
526 0 : return isEditable;
527 : }
528 :
529 : bool
530 0 : nsNativeTheme::QueueAnimatedContentForRefresh(nsIContent* aContent,
531 : PRUint32 aMinimumFrameRate)
532 : {
533 0 : NS_ASSERTION(aContent, "Null pointer!");
534 0 : NS_ASSERTION(aMinimumFrameRate, "aMinimumFrameRate must be non-zero!");
535 0 : NS_ASSERTION(aMinimumFrameRate <= 1000,
536 : "aMinimumFrameRate must be less than 1000!");
537 :
538 0 : PRUint32 timeout = 1000 / aMinimumFrameRate;
539 0 : timeout = NS_MIN(mAnimatedContentTimeout, timeout);
540 :
541 0 : if (!mAnimatedContentTimer) {
542 0 : mAnimatedContentTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
543 0 : NS_ENSURE_TRUE(mAnimatedContentTimer, false);
544 : }
545 :
546 0 : if (mAnimatedContentList.IsEmpty() || timeout != mAnimatedContentTimeout) {
547 : nsresult rv;
548 0 : if (!mAnimatedContentList.IsEmpty()) {
549 0 : rv = mAnimatedContentTimer->Cancel();
550 0 : NS_ENSURE_SUCCESS(rv, false);
551 : }
552 :
553 0 : rv = mAnimatedContentTimer->InitWithCallback(this, timeout,
554 0 : nsITimer::TYPE_ONE_SHOT);
555 0 : NS_ENSURE_SUCCESS(rv, false);
556 :
557 0 : mAnimatedContentTimeout = timeout;
558 : }
559 :
560 0 : if (!mAnimatedContentList.AppendElement(aContent)) {
561 0 : NS_WARNING("Out of memory!");
562 0 : return false;
563 : }
564 :
565 0 : return true;
566 : }
567 :
568 : NS_IMETHODIMP
569 0 : nsNativeTheme::Notify(nsITimer* aTimer)
570 : {
571 0 : NS_ASSERTION(aTimer == mAnimatedContentTimer, "Wrong timer!");
572 :
573 : // XXX Assumes that calling nsIFrame::Invalidate won't reenter
574 : // QueueAnimatedContentForRefresh.
575 :
576 0 : PRUint32 count = mAnimatedContentList.Length();
577 0 : for (PRUint32 index = 0; index < count; index++) {
578 0 : nsIFrame* frame = mAnimatedContentList[index]->GetPrimaryFrame();
579 0 : if (frame) {
580 0 : frame->InvalidateOverflowRect();
581 : }
582 : }
583 :
584 0 : mAnimatedContentList.Clear();
585 0 : mAnimatedContentTimeout = PR_UINT32_MAX;
586 0 : return NS_OK;
587 : }
588 :
589 : nsIFrame*
590 0 : nsNativeTheme::GetAdjacentSiblingFrameWithSameAppearance(nsIFrame* aFrame,
591 : bool aNextSibling)
592 : {
593 0 : if (!aFrame)
594 0 : return nsnull;
595 :
596 : // Find the next visible sibling.
597 0 : nsIFrame* sibling = aFrame;
598 0 : do {
599 0 : sibling = aNextSibling ? sibling->GetNextSibling() : sibling->GetPrevSibling();
600 0 : } while (sibling && sibling->GetRect().width == 0);
601 :
602 : // Check same appearance and adjacency.
603 0 : if (!sibling ||
604 0 : sibling->GetStyleDisplay()->mAppearance != aFrame->GetStyleDisplay()->mAppearance ||
605 0 : (sibling->GetRect().XMost() != aFrame->GetRect().x &&
606 0 : aFrame->GetRect().XMost() != sibling->GetRect().x))
607 0 : return nsnull;
608 0 : return sibling;
609 : }
|