michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // michael@0: // David Hyatt & Eric Vaughan michael@0: // Netscape Communications michael@0: // michael@0: // See documentation in associated header file michael@0: // michael@0: michael@0: #include "nsProgressMeterFrame.h" michael@0: #include "nsCSSRendering.h" michael@0: #include "nsIContent.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsBoxLayoutState.h" michael@0: #include "nsIReflowCallback.h" michael@0: #include "nsContentUtils.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: class nsReflowFrameRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: nsReflowFrameRunnable(nsIFrame* aFrame, michael@0: nsIPresShell::IntrinsicDirty aIntrinsicDirty, michael@0: nsFrameState aBitToAdd); michael@0: michael@0: NS_DECL_NSIRUNNABLE michael@0: michael@0: nsWeakFrame mWeakFrame; michael@0: nsIPresShell::IntrinsicDirty mIntrinsicDirty; michael@0: nsFrameState mBitToAdd; michael@0: }; michael@0: michael@0: nsReflowFrameRunnable::nsReflowFrameRunnable(nsIFrame* aFrame, michael@0: nsIPresShell::IntrinsicDirty aIntrinsicDirty, michael@0: nsFrameState aBitToAdd) michael@0: : mWeakFrame(aFrame), michael@0: mIntrinsicDirty(aIntrinsicDirty), michael@0: mBitToAdd(aBitToAdd) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsReflowFrameRunnable::Run() michael@0: { michael@0: if (mWeakFrame.IsAlive()) { michael@0: mWeakFrame->PresContext()->PresShell()-> michael@0: FrameNeedsReflow(mWeakFrame, mIntrinsicDirty, mBitToAdd); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: // NS_NewToolbarFrame michael@0: // michael@0: // Creates a new Toolbar frame and returns it michael@0: // michael@0: nsIFrame* michael@0: NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) michael@0: { michael@0: return new (aPresShell) nsProgressMeterFrame(aPresShell, aContext); michael@0: } michael@0: michael@0: NS_IMPL_FRAMEARENA_HELPERS(nsProgressMeterFrame) michael@0: michael@0: // michael@0: // nsProgressMeterFrame dstr michael@0: // michael@0: // Cleanup, if necessary michael@0: // michael@0: nsProgressMeterFrame :: ~nsProgressMeterFrame ( ) michael@0: { michael@0: } michael@0: michael@0: class nsAsyncProgressMeterInit MOZ_FINAL : public nsIReflowCallback michael@0: { michael@0: public: michael@0: nsAsyncProgressMeterInit(nsIFrame* aFrame) : mWeakFrame(aFrame) {} michael@0: michael@0: virtual bool ReflowFinished() MOZ_OVERRIDE michael@0: { michael@0: bool shouldFlush = false; michael@0: nsIFrame* frame = mWeakFrame.GetFrame(); michael@0: if (frame) { michael@0: nsAutoScriptBlocker scriptBlocker; michael@0: frame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::mode, 0); michael@0: shouldFlush = true; michael@0: } michael@0: delete this; michael@0: return shouldFlush; michael@0: } michael@0: michael@0: virtual void ReflowCallbackCanceled() MOZ_OVERRIDE michael@0: { michael@0: delete this; michael@0: } michael@0: michael@0: nsWeakFrame mWeakFrame; michael@0: }; michael@0: michael@0: NS_IMETHODIMP michael@0: nsProgressMeterFrame::DoLayout(nsBoxLayoutState& aState) michael@0: { michael@0: if (mNeedsReflowCallback) { michael@0: nsIReflowCallback* cb = new nsAsyncProgressMeterInit(this); michael@0: if (cb) { michael@0: PresContext()->PresShell()->PostReflowCallback(cb); michael@0: } michael@0: mNeedsReflowCallback = false; michael@0: } michael@0: return nsBoxFrame::DoLayout(aState); michael@0: } michael@0: michael@0: nsresult michael@0: nsProgressMeterFrame::AttributeChanged(int32_t aNameSpaceID, michael@0: nsIAtom* aAttribute, michael@0: int32_t aModType) michael@0: { michael@0: NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), michael@0: "Scripts not blocked in nsProgressMeterFrame::AttributeChanged!"); michael@0: nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute, michael@0: aModType); michael@0: if (NS_OK != rv) { michael@0: return rv; michael@0: } michael@0: michael@0: // did the progress change? michael@0: bool undetermined = mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mode, michael@0: nsGkAtoms::undetermined, eCaseMatters); michael@0: if (nsGkAtoms::mode == aAttribute || michael@0: (!undetermined && michael@0: (nsGkAtoms::value == aAttribute || nsGkAtoms::max == aAttribute))) { michael@0: nsIFrame* barChild = GetFirstPrincipalChild(); michael@0: if (!barChild) return NS_OK; michael@0: nsIFrame* remainderChild = barChild->GetNextSibling(); michael@0: if (!remainderChild) return NS_OK; michael@0: nsCOMPtr remainderContent = remainderChild->GetContent(); michael@0: if (!remainderContent) return NS_OK; michael@0: michael@0: int32_t flex = 1, maxFlex = 1; michael@0: if (!undetermined) { michael@0: nsAutoString value, maxValue; michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, value); michael@0: mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxValue); michael@0: michael@0: nsresult error; michael@0: flex = value.ToInteger(&error); michael@0: maxFlex = maxValue.ToInteger(&error); michael@0: if (NS_FAILED(error) || maxValue.IsEmpty()) { michael@0: maxFlex = 100; michael@0: } michael@0: if (maxFlex < 1) { michael@0: maxFlex = 1; michael@0: } michael@0: if (flex < 0) { michael@0: flex = 0; michael@0: } michael@0: if (flex > maxFlex) { michael@0: flex = maxFlex; michael@0: } michael@0: } michael@0: michael@0: nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( michael@0: barChild->GetContent(), nsGkAtoms::flex, flex)); michael@0: nsContentUtils::AddScriptRunner(new nsSetAttrRunnable( michael@0: remainderContent, nsGkAtoms::flex, maxFlex - flex)); michael@0: nsContentUtils::AddScriptRunner(new nsReflowFrameRunnable( michael@0: this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY)); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef DEBUG_FRAME_DUMP michael@0: nsresult michael@0: nsProgressMeterFrame::GetFrameName(nsAString& aResult) const michael@0: { michael@0: return MakeFrameName(NS_LITERAL_STRING("ProgressMeter"), aResult); michael@0: } michael@0: #endif