|
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 // |
|
7 // David Hyatt & Eric Vaughan |
|
8 // Netscape Communications |
|
9 // |
|
10 // See documentation in associated header file |
|
11 // |
|
12 |
|
13 #include "nsProgressMeterFrame.h" |
|
14 #include "nsCSSRendering.h" |
|
15 #include "nsIContent.h" |
|
16 #include "nsPresContext.h" |
|
17 #include "nsGkAtoms.h" |
|
18 #include "nsNameSpaceManager.h" |
|
19 #include "nsCOMPtr.h" |
|
20 #include "nsBoxLayoutState.h" |
|
21 #include "nsIReflowCallback.h" |
|
22 #include "nsContentUtils.h" |
|
23 #include "mozilla/Attributes.h" |
|
24 |
|
25 class nsReflowFrameRunnable : public nsRunnable |
|
26 { |
|
27 public: |
|
28 nsReflowFrameRunnable(nsIFrame* aFrame, |
|
29 nsIPresShell::IntrinsicDirty aIntrinsicDirty, |
|
30 nsFrameState aBitToAdd); |
|
31 |
|
32 NS_DECL_NSIRUNNABLE |
|
33 |
|
34 nsWeakFrame mWeakFrame; |
|
35 nsIPresShell::IntrinsicDirty mIntrinsicDirty; |
|
36 nsFrameState mBitToAdd; |
|
37 }; |
|
38 |
|
39 nsReflowFrameRunnable::nsReflowFrameRunnable(nsIFrame* aFrame, |
|
40 nsIPresShell::IntrinsicDirty aIntrinsicDirty, |
|
41 nsFrameState aBitToAdd) |
|
42 : mWeakFrame(aFrame), |
|
43 mIntrinsicDirty(aIntrinsicDirty), |
|
44 mBitToAdd(aBitToAdd) |
|
45 { |
|
46 } |
|
47 |
|
48 NS_IMETHODIMP |
|
49 nsReflowFrameRunnable::Run() |
|
50 { |
|
51 if (mWeakFrame.IsAlive()) { |
|
52 mWeakFrame->PresContext()->PresShell()-> |
|
53 FrameNeedsReflow(mWeakFrame, mIntrinsicDirty, mBitToAdd); |
|
54 } |
|
55 return NS_OK; |
|
56 } |
|
57 |
|
58 // |
|
59 // NS_NewToolbarFrame |
|
60 // |
|
61 // Creates a new Toolbar frame and returns it |
|
62 // |
|
63 nsIFrame* |
|
64 NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
65 { |
|
66 return new (aPresShell) nsProgressMeterFrame(aPresShell, aContext); |
|
67 } |
|
68 |
|
69 NS_IMPL_FRAMEARENA_HELPERS(nsProgressMeterFrame) |
|
70 |
|
71 // |
|
72 // nsProgressMeterFrame dstr |
|
73 // |
|
74 // Cleanup, if necessary |
|
75 // |
|
76 nsProgressMeterFrame :: ~nsProgressMeterFrame ( ) |
|
77 { |
|
78 } |
|
79 |
|
80 class nsAsyncProgressMeterInit MOZ_FINAL : public nsIReflowCallback |
|
81 { |
|
82 public: |
|
83 nsAsyncProgressMeterInit(nsIFrame* aFrame) : mWeakFrame(aFrame) {} |
|
84 |
|
85 virtual bool ReflowFinished() MOZ_OVERRIDE |
|
86 { |
|
87 bool shouldFlush = false; |
|
88 nsIFrame* frame = mWeakFrame.GetFrame(); |
|
89 if (frame) { |
|
90 nsAutoScriptBlocker scriptBlocker; |
|
91 frame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::mode, 0); |
|
92 shouldFlush = true; |
|
93 } |
|
94 delete this; |
|
95 return shouldFlush; |
|
96 } |
|
97 |
|
98 virtual void ReflowCallbackCanceled() MOZ_OVERRIDE |
|
99 { |
|
100 delete this; |
|
101 } |
|
102 |
|
103 nsWeakFrame mWeakFrame; |
|
104 }; |
|
105 |
|
106 NS_IMETHODIMP |
|
107 nsProgressMeterFrame::DoLayout(nsBoxLayoutState& aState) |
|
108 { |
|
109 if (mNeedsReflowCallback) { |
|
110 nsIReflowCallback* cb = new nsAsyncProgressMeterInit(this); |
|
111 if (cb) { |
|
112 PresContext()->PresShell()->PostReflowCallback(cb); |
|
113 } |
|
114 mNeedsReflowCallback = false; |
|
115 } |
|
116 return nsBoxFrame::DoLayout(aState); |
|
117 } |
|
118 |
|
119 nsresult |
|
120 nsProgressMeterFrame::AttributeChanged(int32_t aNameSpaceID, |
|
121 nsIAtom* aAttribute, |
|
122 int32_t aModType) |
|
123 { |
|
124 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), |
|
125 "Scripts not blocked in nsProgressMeterFrame::AttributeChanged!"); |
|
126 nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, |
|
127 aModType); |
|
128 if (NS_OK != rv) { |
|
129 return rv; |
|
130 } |
|
131 |
|
132 // did the progress change? |
|
133 bool undetermined = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mode, |
|
134 nsGkAtoms::undetermined, eCaseMatters); |
|
135 if (nsGkAtoms::mode == aAttribute || |
|
136 (!undetermined && |
|
137 (nsGkAtoms::value == aAttribute || nsGkAtoms::max == aAttribute))) { |
|
138 nsIFrame* barChild = GetFirstPrincipalChild(); |
|
139 if (!barChild) return NS_OK; |
|
140 nsIFrame* remainderChild = barChild->GetNextSibling(); |
|
141 if (!remainderChild) return NS_OK; |
|
142 nsCOMPtr<nsIContent> remainderContent = remainderChild->GetContent(); |
|
143 if (!remainderContent) return NS_OK; |
|
144 |
|
145 int32_t flex = 1, maxFlex = 1; |
|
146 if (!undetermined) { |
|
147 nsAutoString value, maxValue; |
|
148 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value); |
|
149 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxValue); |
|
150 |
|
151 nsresult error; |
|
152 flex = value.ToInteger(&error); |
|
153 maxFlex = maxValue.ToInteger(&error); |
|
154 if (NS_FAILED(error) || maxValue.IsEmpty()) { |
|
155 maxFlex = 100; |
|
156 } |
|
157 if (maxFlex < 1) { |
|
158 maxFlex = 1; |
|
159 } |
|
160 if (flex < 0) { |
|
161 flex = 0; |
|
162 } |
|
163 if (flex > maxFlex) { |
|
164 flex = maxFlex; |
|
165 } |
|
166 } |
|
167 |
|
168 nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( |
|
169 barChild->GetContent(), nsGkAtoms::flex, flex)); |
|
170 nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( |
|
171 remainderContent, nsGkAtoms::flex, maxFlex - flex)); |
|
172 nsContentUtils::AddScriptRunner(new nsReflowFrameRunnable( |
|
173 this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY)); |
|
174 } |
|
175 return NS_OK; |
|
176 } |
|
177 |
|
178 #ifdef DEBUG_FRAME_DUMP |
|
179 nsresult |
|
180 nsProgressMeterFrame::GetFrameName(nsAString& aResult) const |
|
181 { |
|
182 return MakeFrameName(NS_LITERAL_STRING("ProgressMeter"), aResult); |
|
183 } |
|
184 #endif |