Bug 567872 - Layout part of the progress element. r=roc,dbaron
authorMounir Lamouri <mounir.lamouri@gmail.com>
Tue, 10 May 2011 14:59:07 +0200
changeset 69472 97e11f940f25dad89ec7c724435abb98370add82
parent 69471 684cdf4a421246f9fa8503fb9de1c421703d4697
child 69473 dd09b7ba02ffde15f5411259d539dc21e0ce1131
push idunknown
push userunknown
push dateunknown
reviewersroc, dbaron
bugs567872
milestone6.0a1
Bug 567872 - Layout part of the progress element. r=roc,dbaron
layout/base/nsCSSFrameConstructor.cpp
layout/forms/Makefile.in
layout/forms/nsProgressFrame.cpp
layout/forms/nsProgressFrame.h
layout/generic/nsHTMLParts.h
layout/generic/nsQueryFrame.h
layout/reftests/forms/progress/margin-padding-ref.html
layout/reftests/forms/progress/margin-padding.html
layout/reftests/forms/progress/reftest.list
layout/reftests/forms/progress/style.css
layout/reftests/forms/progress/transformations-ref.html
layout/reftests/forms/progress/transformations.html
layout/reftests/forms/progress/values-ref.html
layout/reftests/forms/progress/values-rtl-ref.html
layout/reftests/forms/progress/values-rtl.html
layout/reftests/forms/progress/values.html
layout/reftests/forms/reftest.list
layout/style/forms.css
layout/style/html.css
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3543,17 +3543,18 @@ nsCSSFrameConstructor::FindHTMLData(Elem
     SIMPLE_TAG_CREATE(frameset, NS_NewHTMLFramesetFrame),
     SIMPLE_TAG_CREATE(iframe, NS_NewSubDocumentFrame),
     COMPLEX_TAG_CREATE(button, &nsCSSFrameConstructor::ConstructButtonFrame),
     SIMPLE_TAG_CREATE(canvas, NS_NewHTMLCanvasFrame),
 #if defined(MOZ_MEDIA)
     SIMPLE_TAG_CREATE(video, NS_NewHTMLVideoFrame),
     SIMPLE_TAG_CREATE(audio, NS_NewHTMLVideoFrame),
 #endif
-    SIMPLE_TAG_CREATE(isindex, NS_NewIsIndexFrame)
+    SIMPLE_TAG_CREATE(isindex, NS_NewIsIndexFrame),
+    SIMPLE_TAG_CREATE(progress, NS_NewProgressFrame)
   };
 
   return FindDataByTag(aTag, aElement, aStyleContext, sHTMLData,
                        NS_ARRAY_LENGTH(sHTMLData));
 }
 
 /* static */
 const nsCSSFrameConstructor::FrameConstructionData*
--- a/layout/forms/Makefile.in
+++ b/layout/forms/Makefile.in
@@ -67,16 +67,17 @@ CPPSRCS		= \
 		nsButtonFrameRenderer.cpp \
 		nsComboboxControlFrame.cpp \
 		nsFieldSetFrame.cpp \
 		nsFileControlFrame.cpp \
 		nsFormControlFrame.cpp \
 		nsGfxButtonControlFrame.cpp \
 		nsGfxCheckboxControlFrame.cpp \
 		nsGfxRadioControlFrame.cpp \
+		nsProgressFrame.cpp \
 		nsTextControlFrame.cpp \
 		nsHTMLButtonControlFrame.cpp \
 		nsImageControlFrame.cpp \
 		nsLegendFrame.cpp \
 		nsListControlFrame.cpp \
 		nsIsIndexFrame.cpp \
 		nsSelectsAreaFrame.cpp \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/layout/forms/nsProgressFrame.cpp
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsProgressFrame.h"
+
+#include "nsIDOMHTMLProgressElement.h"
+#include "nsIContent.h"
+#include "prtypes.h"
+#include "nsPresContext.h"
+#include "nsGkAtoms.h"
+#include "nsINameSpaceManager.h"
+#include "nsIDocument.h"
+#include "nsIPresShell.h"
+#include "nsNodeInfoManager.h"
+#include "nsINodeInfo.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsContentUtils.h"
+#include "nsFormControlFrame.h"
+#include "nsFontMetrics.h"
+
+
+nsIFrame*
+NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+  return new (aPresShell) nsProgressFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsProgressFrame)
+
+nsProgressFrame::nsProgressFrame(nsStyleContext* aContext)
+  : nsHTMLContainerFrame(aContext)
+  , mBarDiv(nsnull)
+{
+}
+
+nsProgressFrame::~nsProgressFrame()
+{
+}
+
+void
+nsProgressFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+  NS_ASSERTION(!GetPrevContinuation(),
+               "nsProgressFrame should not have continuations; if it does we "
+               "need to call RegUnregAccessKey only for the first.");
+  nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), PR_FALSE);
+  nsContentUtils::DestroyAnonymousContent(&mBarDiv);
+  nsHTMLContainerFrame::DestroyFrom(aDestructRoot);
+}
+
+nsresult
+nsProgressFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
+{
+  // Get the NodeInfoManager and tag necessary to create the progress bar div.
+  nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
+
+  nsCOMPtr<nsINodeInfo> nodeInfo;
+  nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::div, nsnull,
+                                                 kNameSpaceID_XHTML);
+  NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
+
+  // Create the div.
+  nsresult rv = NS_NewHTMLElement(getter_AddRefs(mBarDiv), nodeInfo.forget(),
+                                  mozilla::dom::NOT_FROM_PARSER);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!aElements.AppendElement(mBarDiv)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  return NS_OK;
+}
+
+void
+nsProgressFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
+                                          PRUint32 aFilter)
+{
+  aElements.MaybeAppendElement(mBarDiv);
+}
+
+NS_QUERYFRAME_HEAD(nsProgressFrame)
+  NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+NS_QUERYFRAME_TAIL_INHERITING(nsHTMLContainerFrame)
+
+
+NS_IMETHODIMP nsProgressFrame::Reflow(nsPresContext*           aPresContext,
+                                      nsHTMLReflowMetrics&     aDesiredSize,
+                                      const nsHTMLReflowState& aReflowState,
+                                      nsReflowStatus&          aStatus)
+{
+  DO_GLOBAL_REFLOW_COUNT("nsProgressFrame");
+  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
+
+  NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
+  NS_ASSERTION(!GetPrevContinuation(),
+               "nsProgressFrame should not have continuations; if it does we "
+               "need to call RegUnregAccessKey only for the first.");
+
+  if (mState & NS_FRAME_FIRST_REFLOW) {
+    nsFormControlFrame::RegUnRegAccessKey(this, PR_TRUE);
+  }
+
+  nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
+  NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
+
+  ReflowBarFrame(barFrame, aPresContext, aReflowState, aStatus);
+
+  aDesiredSize.width = aReflowState.ComputedWidth() +
+                       aReflowState.mComputedBorderPadding.LeftRight();
+  aDesiredSize.height = aReflowState.ComputedHeight() +
+                        aReflowState.mComputedBorderPadding.TopBottom();
+  aDesiredSize.height = NS_CSS_MINMAX(aDesiredSize.height,
+                                      aReflowState.mComputedMinHeight,
+                                      aReflowState.mComputedMaxHeight);
+
+  aDesiredSize.SetOverflowAreasToDesiredBounds();
+  ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
+  FinishAndStoreOverflow(&aDesiredSize);
+
+  aStatus = NS_FRAME_COMPLETE;
+
+  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
+
+  return NS_OK;
+}
+
+void
+nsProgressFrame::ReflowBarFrame(nsIFrame*                aBarFrame,
+                                nsPresContext*           aPresContext,
+                                const nsHTMLReflowState& aReflowState,
+                                nsReflowStatus&          aStatus)
+{
+  nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame,
+                                nsSize(aReflowState.ComputedWidth(),
+                                       NS_UNCONSTRAINEDSIZE));
+  nscoord width = aReflowState.ComputedWidth();
+  nscoord xoffset = aReflowState.mComputedBorderPadding.left;
+  nscoord yoffset = aReflowState.mComputedBorderPadding.top;
+
+  double position;
+  nsCOMPtr<nsIDOMHTMLProgressElement> progressElement =
+    do_QueryInterface(mContent);
+  progressElement->GetPosition(&position);
+
+  // Force the bar's width to match the current progress.
+  // When indeterminate, the progress' width will be 100%.
+  if (position >= 0.0) {
+    width *= position;
+  }
+
+  if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
+    xoffset += aReflowState.ComputedWidth() - width;
+  }
+
+  // We want the frame to take all the available size.
+  width -= reflowState.mComputedMargin.LeftRight() +
+           reflowState.mComputedBorderPadding.LeftRight();
+  width = NS_MAX(width, 0);
+  reflowState.SetComputedWidth(width);
+
+  xoffset += reflowState.mComputedMargin.left;
+  yoffset += reflowState.mComputedMargin.top;
+
+  nsHTMLReflowMetrics barDesiredSize;
+  ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
+              yoffset, 0, aStatus);
+  FinishReflowChild(aBarFrame, aPresContext, &reflowState, barDesiredSize,
+                    xoffset, yoffset, 0);
+}
+
+NS_IMETHODIMP
+nsProgressFrame::AttributeChanged(PRInt32  aNameSpaceID,
+                                  nsIAtom* aAttribute,
+                                  PRInt32  aModType)
+{
+  NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
+
+  if (aNameSpaceID == kNameSpaceID_None &&
+      (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max)) {
+    nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
+    NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
+    PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
+                                                 NS_FRAME_IS_DIRTY);
+  }
+
+  return nsHTMLContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
+                                                aModType);
+}
+
+nsSize
+nsProgressFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
+                                 nsSize aCBSize, nscoord aAvailableWidth,
+                                 nsSize aMargin, nsSize aBorder,
+                                 nsSize aPadding, PRBool aShrinkWrap)
+{
+  nsRefPtr<nsFontMetrics> fontMet;
+  NS_ENSURE_SUCCESS(nsLayoutUtils::GetFontMetricsForFrame(this,
+                                                          getter_AddRefs(fontMet)),
+                    nsSize(0, 0));
+
+  nsSize autoSize;
+  autoSize.height = autoSize.width = fontMet->Font().size; // 1em
+  autoSize.width *= 10; // 10em
+
+  return autoSize;
+}
+
new file mode 100644
--- /dev/null
+++ b/layout/forms/nsProgressFrame.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mounir Lamouri <mounir.lamouri@mozilla.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsProgressFrame_h___
+#define nsProgressFrame_h___
+
+#include "nsHTMLContainerFrame.h"
+#include "nsIAnonymousContentCreator.h"
+#include "nsCOMPtr.h"
+
+
+class nsProgressFrame : public nsHTMLContainerFrame,
+                        public nsIAnonymousContentCreator
+{
+public:
+  NS_DECL_QUERYFRAME_TARGET(nsProgressFrame)
+  NS_DECL_QUERYFRAME
+  NS_DECL_FRAMEARENA_HELPERS
+
+  nsProgressFrame(nsStyleContext* aContext);
+  virtual ~nsProgressFrame();
+
+  virtual void DestroyFrom(nsIFrame* aDestructRoot);
+
+  NS_IMETHOD Reflow(nsPresContext*           aCX,
+                    nsHTMLReflowMetrics&     aDesiredSize,
+                    const nsHTMLReflowState& aReflowState,
+                    nsReflowStatus&          aStatus);
+
+#ifdef NS_DEBUG
+  NS_IMETHOD GetFrameName(nsAString& aResult) const {
+    return MakeFrameName(NS_LITERAL_STRING("Progress"), aResult);
+  }
+#endif
+
+  virtual PRBool IsLeaf() const { return PR_TRUE; }
+
+  // nsIAnonymousContentCreator
+  virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements);
+  virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
+                                        PRUint32 aFilter);
+
+  NS_IMETHOD AttributeChanged(PRInt32  aNameSpaceID,
+                              nsIAtom* aAttribute,
+                              PRInt32  aModType);
+
+  virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
+                                 nsSize aCBSize, nscoord aAvailableWidth,
+                                 nsSize aMargin, nsSize aBorder,
+                                 nsSize aPadding, PRBool aShrinkWrap);
+
+  virtual PRBool IsFrameOfType(PRUint32 aFlags) const
+  {
+    return nsHTMLContainerFrame::IsFrameOfType(aFlags &
+      ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock));
+  }
+
+protected:
+  // Helper function which reflow the anonymous div frame.
+  void ReflowBarFrame(nsIFrame*                aBarFrame,
+                      nsPresContext*           aPresContext,
+                      const nsHTMLReflowState& aReflowState,
+                      nsReflowStatus&          aStatus);
+
+  /**
+   * The div used to show the progress bar.
+   * @see nsProgressFrame::CreateAnonymousContent
+   */
+  nsCOMPtr<nsIContent> mBarDiv;
+};
+
+#endif
+
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -199,16 +199,18 @@ NS_NewNativeRadioControlFrame(nsIPresShe
 nsIFrame*
 NS_NewNativeSelectControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 nsIFrame*
 NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 nsIFrame*
 NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
 nsIFrame*
 NS_NewIsIndexFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+nsIFrame*
+NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 // Table frame factories
 nsIFrame*
 NS_NewTableOuterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 nsIFrame*
 NS_NewTableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 nsIFrame*
 NS_NewTableCaptionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
--- a/layout/generic/nsQueryFrame.h
+++ b/layout/generic/nsQueryFrame.h
@@ -180,16 +180,17 @@ public:
     nsMenuFrame_id,
     nsMenuPopupFrame_id,
     nsObjectFrame_id,
     nsPageBreakFrame_id,
     nsPageContentFrame_id,
     nsPageFrame_id,
     nsPlaceholderFrame_id,
     nsPopupSetFrame_id,
+    nsProgressFrame_id,
     nsProgressMeterFrame_id,
     nsResizerFrame_id,
     nsRootBoxFrame_id,
     nsScrollbarButtonFrame_id,
     nsScrollbarFrame_id,
     nsSelectsAreaFrame_id,
     nsSimplePageSequenceFrame_id,
     nsSliderFrame_id,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/margin-padding-ref.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    body > div:nth-child(1) { margin: 10px; padding: 0px; }
+    body > div:nth-child(2) { margin: 0px; padding: 10px; }
+    body > div:nth-child(3) { margin: 10px; padding: 10px; }
+    body > div:nth-child(4) { margin: 5px; padding: 5px; }
+    body > div:nth-child(5) { margin: 50px; padding: 50px; }
+    body > div:nth-child(6) { margin: 100px; padding: 100px; }
+    body > div:nth-child(7) { margin: 10px 0px 0px 0px; padding: 0px; }
+    body > div:nth-child(8) { margin: 0px 10px 0px 0px; padding: 0px; }
+    body > div:nth-child(9) { margin: 0px 0px 10px 0px; padding: 0px; }
+    body > div:nth-child(10) { margin: 0px 0px 0px 10px; padding: 0px; }
+    body > div:nth-child(11) { margin: 0px; padding: 10px 0px 0px 0px; }
+    body > div:nth-child(12) { margin: 0px; padding: 0px 10px 0px 0px; }
+    body > div:nth-child(13) { margin: 0px; padding: 0px 0px 10px 0px; }
+    body > div:nth-child(14) { margin: 0px; padding: 0px 0px 0px 10px; }
+    body > div:nth-child(15) { margin: 0px; padding: 2px 4px 6px 8px; }
+    body > div:nth-child(16) { margin: 2px 4px 6px 8px; padding: 0px; }
+  </style>
+  <body>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/margin-padding.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+  <style>
+    progress:nth-child(1) { margin: 10px; padding: 0px; }
+    progress:nth-child(2) { margin: 0px; padding: 10px; }
+    progress:nth-child(3) { margin: 10px; padding: 10px; }
+    progress:nth-child(4) { margin: 5px; padding: 5px; }
+    progress:nth-child(5) { margin: 50px; padding: 50px; }
+    progress:nth-child(6) { margin: 100px; padding: 100px; }
+    progress:nth-child(7) { margin: 10px 0px 0px 0px; padding: 0px; }
+    progress:nth-child(8) { margin: 0px 10px 0px 0px; padding: 0px; }
+    progress:nth-child(9) { margin: 0px 0px 10px 0px; padding: 0px; }
+    progress:nth-child(10) { margin: 0px 0px 0px 10px; padding: 0px; }
+    progress:nth-child(11) { margin: 0px; padding: 10px 0px 0px 0px; }
+    progress:nth-child(12) { margin: 0px; padding: 0px 10px 0px 0px; }
+    progress:nth-child(13) { margin: 0px; padding: 0px 0px 10px 0px; }
+    progress:nth-child(14) { margin: 0px; padding: 0px 0px 0px 10px; }
+    progress:nth-child(15) { margin: 0px; padding: 2px 4px 6px 8px; }
+    progress:nth-child(16) { margin: 2px 4px 6px 8px; padding: 0px; }
+  </style>
+  <body>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/reftest.list
@@ -0,0 +1,9 @@
+# For the moment, none of these tests will work on MacOS X.
+skip-if(cocoaWidget) == values.html values-ref.html
+skip-if(cocoaWidget) == values-rtl.html values-rtl-ref.html
+skip-if(cocoaWidget) == margin-padding.html margin-padding-ref.html
+
+# The following test is disabled but kept in the repository because the
+# transformations will not behave exactly the same for <progress> and two divs.
+# However, it would be possible to manually check those.
+# == transformations.html transformations-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/style.css
@@ -0,0 +1,26 @@
+div.progress-element {
+  -moz-appearance: progressbar;
+  display: inline-block;
+  height: 1em;
+  width: 10em;
+  vertical-align: -0.2em;
+
+  /* TODO: this is a workaround for bug 568825 */
+  overflow: hidden;
+
+  /* Default style in case of there is -moz-appearance: none; */
+  border: 2px solid;
+  -moz-border-top-colors: ThreeDShadow -moz-Dialog;
+  -moz-border-right-colors: ThreeDHighlight -moz-Dialog;
+  -moz-border-bottom-colors: ThreeDHighlight -moz-Dialog;
+  -moz-border-left-colors: ThreeDShadow -moz-Dialog;
+  background-color: -moz-Dialog;
+}
+
+div.progress-bar {
+  -moz-appearance: progresschunk;
+  height: 100%;
+
+  /* Default style in case of there is -moz-appearance: none; */
+  background-color: ThreeDShadow;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/transformations-ref.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    body > div:nth-child(1) { -moz-transform: matrix(1, -0.2, 0, 1, 0, 0); }
+    body > div:nth-child(2) { -moz-transform: matrix(1, 0, 0.6, 1, 15em, 0); }
+    body > div:nth-child(3) { -moz-transform: rotate(30deg); }
+    body > div:nth-child(4) { -moz-transform: scale(2, 4); }
+    body > div:nth-child(5) { -moz-transform: scale(0.1, 0.4); }
+    body > div:nth-child(6) { -moz-transform: scale(1, 0.4); }
+    body > div:nth-child(7) { -moz-transform: scale(0.1, 1); }
+    body > div:nth-child(8) { -moz-transform: skew(30deg, -10deg); }
+    body > div:nth-child(9) { -moz-transform: skew(-30deg, 10deg); }
+    body > div:nth-child(10) { -moz-transform: translate(10px, 30px); }
+    body > div:nth-child(11) { -moz-transform: translate(30px, 10px); }
+    body > div:nth-child(12) { -moz-transform: translate(-10px, 30px); }
+    body > div:nth-child(13) { -moz-transform: translate(30px, -10px); }
+    body > div:nth-child(14) { -moz-transform: scale(0, 0); }
+  </style>
+  <body>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/transformations.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+  <style>
+    progress:nth-child(1) { -moz-transform: matrix(1, -0.2, 0, 1, 0, 0); }
+    progress:nth-child(2) { -moz-transform: matrix(1, 0, 0.6, 1, 15em, 0); }
+    progress:nth-child(3) { -moz-transform: rotate(30deg); }
+    progress:nth-child(4) { -moz-transform: scale(2, 4); }
+    progress:nth-child(5) { -moz-transform: scale(0.1, 0.4); }
+    progress:nth-child(6) { -moz-transform: scale(1, 0.4); }
+    progress:nth-child(7) { -moz-transform: scale(0.1, 1); }
+    progress:nth-child(8) { -moz-transform: skew(30deg, -10deg); }
+    progress:nth-child(9) { -moz-transform: skew(-30deg, 10deg); }
+    progress:nth-child(10) { -moz-transform: translate(10px, 30px); }
+    progress:nth-child(11) { -moz-transform: translate(30px, 10px); }
+    progress:nth-child(12) { -moz-transform: translate(-10px, 30px); }
+    progress:nth-child(13) { -moz-transform: translate(30px, -10px); }
+    progress:nth-child(14) { -moz-transform: scale(0, 0); }
+  </style>
+  <body>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+    <progress value='1'></progress>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/values-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    div:nth-child(1) > .progress-bar { width: 100%; }
+    div:nth-child(2) > .progress-bar { width: 0%; }
+    div:nth-child(3) > .progress-bar { width: 10%; }
+    div:nth-child(4) > .progress-bar { width: 50%; }
+    div:nth-child(5) > .progress-bar { width: 0%; }
+    div:nth-child(6) > .progress-bar { width: 100%; }
+    div:nth-child(7) > .progress-bar { width: 42%; }
+    div:nth-child(8) > .progress-bar { width: 100%; }
+    div:nth-child(9) > .progress-bar { width: 100%; }
+    div:nth-child(10) > .progress-bar { width: 10%; }
+  </style>
+  <body>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/values-rtl-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+  <link rel='stylesheet' type='text/css' href='style.css'>
+  <style>
+    div:nth-child(1) > .progress-bar { width: 100%; }
+    div:nth-child(2) > .progress-bar { width: 0%; }
+    div:nth-child(3) > .progress-bar { width: 10%; }
+    div:nth-child(4) > .progress-bar { width: 50%; }
+    div:nth-child(5) > .progress-bar { width: 0%; }
+    div:nth-child(6) > .progress-bar { width: 100%; }
+    div:nth-child(7) > .progress-bar { width: 42%; }
+    div:nth-child(8) > .progress-bar { width: 100%; }
+    div:nth-child(9) > .progress-bar { width: 100%; }
+    div:nth-child(10) > .progress-bar { width: 10%; }
+  </style>
+  <body dir='rtl'>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+    <div class="progress-element">
+      <div class="progress-bar">
+      </div>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/values-rtl.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <body dir='rtl'>
+    <progress value="1.0"></progress>
+    <progress value="0.0"></progress>
+    <progress value="0.1"></progress>
+    <progress value="0.5"></progress>
+    <progress value="-1"></progress>
+    <progress value="42"></progress>
+    <progress value="42" max="100"></progress>
+    <progress value="42" max="1"></progress>
+    <progress value="42" max="-1"></progress>
+    <progress value="0.1" max="-1"></progress>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/forms/progress/values.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <progress value="1.0"></progress>
+    <progress value="0.0"></progress>
+    <progress value="0.1"></progress>
+    <progress value="0.5"></progress>
+    <progress value="-1"></progress>
+    <progress value="42"></progress>
+    <progress value="42" max="100"></progress>
+    <progress value="42" max="1"></progress>
+    <progress value="42" max="-1"></progress>
+    <progress value="0.1" max="-1"></progress>
+  </body>
+</html>
--- a/layout/reftests/forms/reftest.list
+++ b/layout/reftests/forms/reftest.list
@@ -54,8 +54,11 @@ fails-if(Android) != textarea-rtl.html t
 # placeholder
 include placeholder/reftest.list
 
 # input
 include input/reftest.list
 
 # output element
 include output/reftest.list
+
+# progress element
+include progress/reftest.list
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -663,16 +663,41 @@ output:-moz-ui-invalid {
 @media print {
   input, textarea, select, button {
     -moz-user-input: none !important;
   }
 
   input[type="file"] { height: 2em; }
 }
 
+progress {
+  -moz-appearance: progressbar;
+  display: inline-block;
+  vertical-align: -0.2em;
+
+  /* TODO: this is a workaround for bug 568825 */
+  overflow: hidden;
+
+  /* Default style in case of there is -moz-appearance: none; */
+  border: 2px solid;
+  -moz-border-top-colors: ThreeDShadow -moz-Dialog;
+  -moz-border-right-colors: ThreeDHighlight -moz-Dialog;
+  -moz-border-bottom-colors: ThreeDHighlight -moz-Dialog;
+  -moz-border-left-colors: ThreeDShadow -moz-Dialog;
+  background-color: -moz-Dialog;
+}
+
+progress > div {
+  -moz-appearance: progresschunk;
+  height: 100%;
+
+  /* Default style in case of there is -moz-appearance: none; */
+  background-color: ThreeDShadow;
+}
+
 %if OSARCH==OS2
 input {
   font: medium serif; font-family: inherit
 }
 
 select {
   font: medium serif; font-family: inherit
 }
--- a/layout/style/html.css
+++ b/layout/style/html.css
@@ -690,42 +690,85 @@ spacer {
   float: none ! important;
 }
 
 canvas {
   -moz-user-select: none;
 }
 
 /* focusable content: anything w/ tabindex >=0 is focusable */
-abbr:-moz-focusring, acronym:-moz-focusring, address:-moz-focusring,
+abbr:-moz-focusring,
+acronym:-moz-focusring,
+address:-moz-focusring,
 applet:-moz-focusring,
-b:-moz-focusring, base:-moz-focusring, big:-moz-focusring,
-blockquote:-moz-focusring, br:-moz-focusring, canvas:-moz-focusring,
-caption:-moz-focusring, center:-moz-focusring, cite:-moz-focusring,
-code:-moz-focusring, col:-moz-focusring, colgroup:-moz-focusring,
-dd:-moz-focusring, del:-moz-focusring, dfn:-moz-focusring, dir:-moz-focusring,
-div:-moz-focusring, dl:-moz-focusring, dt:-moz-focusring, em:-moz-focusring,
+b:-moz-focusring,
+base:-moz-focusring,
+big:-moz-focusring,
+blockquote:-moz-focusring,
+br:-moz-focusring,
+canvas:-moz-focusring,
+caption:-moz-focusring,
+center:-moz-focusring,
+cite:-moz-focusring,
+code:-moz-focusring,
+col:-moz-focusring,
+colgroup:-moz-focusring,
+dd:-moz-focusring,
+del:-moz-focusring,
+dfn:-moz-focusring,
+dir:-moz-focusring,
+div:-moz-focusring,
+dl:-moz-focusring,
+dt:-moz-focusring,
+em:-moz-focusring,
 embed:-moz-focusring,
-fieldset:-moz-focusring, font:-moz-focusring, form:-moz-focusring,
-h1:-moz-focusring, h2:-moz-focusring, h3:-moz-focusring, h4:-moz-focusring,
-h5:-moz-focusring, h6:-moz-focusring, hr:-moz-focusring, i:-moz-focusring,
-img:-moz-focusring, ins:-moz-focusring, kbd:-moz-focusring,
-label:-moz-focusring, legend:-moz-focusring, li:-moz-focusring,
+fieldset:-moz-focusring,
+font:-moz-focusring,
+form:-moz-focusring,
+h1:-moz-focusring,
+h2:-moz-focusring,
+h3:-moz-focusring,
+h4:-moz-focusring,
+h5:-moz-focusring,
+h6:-moz-focusring,
+hr:-moz-focusring,
+i:-moz-focusring,
+img:-moz-focusring,
+ins:-moz-focusring,
+kbd:-moz-focusring,
+label:-moz-focusring,
+legend:-moz-focusring,
+li:-moz-focusring,
 link:-moz-focusring,
 menu:-moz-focusring,
 object:-moz-focusring,
 ol:-moz-focusring,
 p:-moz-focusring,
-pre:-moz-focusring, q:-moz-focusring, s:-moz-focusring, samp:-moz-focusring,
-small:-moz-focusring, span:-moz-focusring, strike:-moz-focusring,
-strong:-moz-focusring, sub:-moz-focusring, sup:-moz-focusring,
-table:-moz-focusring, tbody:-moz-focusring, td:-moz-focusring,
-tfoot:-moz-focusring, th:-moz-focusring, thead:-moz-focusring, 
-tr:-moz-focusring, tt:-moz-focusring, u:-moz-focusring,
-ul:-moz-focusring, var:-moz-focusring {
+pre:-moz-focusring,
+progress:-moz-focusring,
+q:-moz-focusring,
+s:-moz-focusring,
+samp:-moz-focusring,
+small:-moz-focusring,
+span:-moz-focusring,
+strike:-moz-focusring,
+strong:-moz-focusring,
+sub:-moz-focusring,
+sup:-moz-focusring,
+table:-moz-focusring,
+tbody:-moz-focusring,
+td:-moz-focusring,
+tfoot:-moz-focusring,
+th:-moz-focusring,
+thead:-moz-focusring,
+tr:-moz-focusring,
+tt:-moz-focusring,
+u:-moz-focusring,
+ul:-moz-focusring,
+var:-moz-focusring {
   /* Don't specify the outline-color, we should always use initial value. */
    outline: 1px dotted;
 }
 
 /* hidden elements */
 base, basefont, datalist, head, meta, script, style, title,
 noembed, param {
    display: none;