Bug 624647 part 0: Don't use ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT flag if 'object-fit' and/or 'object-position' might make our drawing overflow. r=roc
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 14 Nov 2014 16:45:23 -0800
changeset 215875 a083cd9a7c8c645b4afe483871cf9f33ebe8cac7
parent 215874 ca6516a8ca1d5dcb13d9bab74f4dc3ea51ea4f7d
child 215876 39a32a0978f55f6ab4f7cb38af1e6cd05a5aa74a
push id27829
push usergszorc@mozilla.com
push dateSat, 15 Nov 2014 22:34:49 +0000
treeherdermozilla-central@19f75e1211e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs624647
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 624647 part 0: Don't use ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT flag if 'object-fit' and/or 'object-position' might make our drawing overflow. r=roc
layout/generic/nsImageFrame.cpp
layout/generic/nsVideoFrame.cpp
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -26,16 +26,17 @@
 #include "nsIPresShell.h"
 #include "nsGkAtoms.h"
 #include "nsIDocument.h"
 #include "nsContentUtils.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsStyleCoord.h"
+#include "nsStyleUtil.h"
 #include "nsTransform2D.h"
 #include "nsImageMap.h"
 #include "nsIIOService.h"
 #include "nsILoadGroup.h"
 #include "nsISupportsPriority.h"
 #include "nsNetUtil.h"
 #include "nsCSSRendering.h"
 #include "nsIDOMHTMLAnchorElement.h"
@@ -1523,18 +1524,22 @@ nsImageFrame::BuildDisplayList(nsDisplay
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   DisplayBorderBackgroundOutline(aBuilder, aLists);
 
+  uint32_t clipFlags =
+    nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition()) ?
+    0 : DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT;
+
   DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
-    clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
+    clip(aBuilder, this, clipFlags);
 
   if (mComputedSize.width != 0 && mComputedSize.height != 0) {
     nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mContent);
     NS_ASSERTION(imageLoader, "Not an image loading content?");
 
     nsCOMPtr<imgIRequest> currentRequest;
     if (imageLoader) {
       imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -20,16 +20,17 @@
 #include "nsBoxLayoutState.h"
 #include "nsBoxFrame.h"
 #include "nsImageFrame.h"
 #include "nsIImageLoadingContent.h"
 #include "nsContentUtils.h"
 #include "ImageContainer.h"
 #include "ImageLayers.h"
 #include "nsContentList.h"
+#include "nsStyleUtil.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 nsIFrame*
@@ -427,31 +428,45 @@ nsVideoFrame::BuildDisplayList(nsDisplay
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   DO_GLOBAL_REFLOW_COUNT_DSP("nsVideoFrame");
 
   DisplayBorderBackgroundOutline(aBuilder, aLists);
 
+  const bool shouldDisplayPoster = ShouldDisplayPoster();
+
+  // NOTE: If we're displaying a poster image (instead of video data), we can
+  // trust the nsImageFrame to constrain its drawing to its content rect
+  // (which happens to be the same as our content rect).
+  uint32_t clipFlags;
+  if (shouldDisplayPoster ||
+      !nsStyleUtil::ObjectPropsMightCauseOverflow(StylePosition())) {
+    clipFlags =
+      DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT;
+  } else {
+    clipFlags = 0;
+  }
+
   DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox
-    clip(aBuilder, this, DisplayListClipState::ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT);
+    clip(aBuilder, this, clipFlags);
 
-  if (HasVideoElement() && !ShouldDisplayPoster()) {
+  if (HasVideoElement() && !shouldDisplayPoster) {
     aLists.Content()->AppendNewToTop(
       new (aBuilder) nsDisplayVideo(aBuilder, this));
   }
 
   // Add child frames to display list. We expect various children,
   // but only want to draw mPosterImage conditionally. Others we
   // always add to the display list.
   for (nsIFrame *child = mFrames.FirstChild();
        child;
        child = child->GetNextSibling()) {
-    if (child->GetContent() != mPosterImage || ShouldDisplayPoster()) {
+    if (child->GetContent() != mPosterImage || shouldDisplayPoster) {
       child->BuildDisplayListForStackingContext(aBuilder,
                                                 aDirtyRect - child->GetOffsetTo(this),
                                                 aLists.Content());
     } else if (child->GetType() == nsGkAtoms::boxFrame) {
       child->BuildDisplayListForStackingContext(aBuilder,
                                                 aDirtyRect - child->GetOffsetTo(this),
                                                 aLists.Content());
     }
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -5,16 +5,17 @@
 
 #include "nsStyleUtil.h"
 #include "nsStyleConsts.h"
 
 #include "nsIContent.h"
 #include "nsCSSProps.h"
 #include "nsRuleNode.h"
 #include "nsROCSSPrimitiveValue.h"
+#include "nsStyleStruct.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla;
 
 //------------------------------------------------------------------------------
@@ -614,16 +615,67 @@ nsStyleUtil::IsFlexBasisMainSize(const n
     // NOTE: Once we support intrinsic sizing keywords for "height",
     // we can remove this special-case.
     return true;
   }
 
   return aFlexBasis.GetIntValue() == NS_STYLE_FLEX_BASIS_MAIN_SIZE;
 }
 
+// For a replaced element whose concrete object size is no larger than the
+// element's content-box, this method checks whether the given
+// "object-position" coordinate might cause overflow in its dimension.
+typedef nsStyleBackground::Position::PositionCoord PositionCoord;
+static bool
+ObjectPositionCoordMightCauseOverflow(const PositionCoord& aCoord)
+{
+  // Any nonzero length in "object-position" can push us to overflow
+  // (particularly if our concrete object size is exactly the same size as the
+  // replaced element's content-box).
+  if (aCoord.mLength != 0) {
+    return true;
+  }
+
+  // Percentages are interpreted as a fraction of the extra space. So,
+  // percentages in the 0-100% range are safe, but values outside of that
+  // range could cause overflow.
+  if (aCoord.mHasPercent &&
+      (aCoord.mPercent < 0.0f || aCoord.mPercent > 1.0f)) {
+    return true;
+  }
+  return false;
+}
+
+
+/* static */ bool
+nsStyleUtil::ObjectPropsMightCauseOverflow(const nsStylePosition* aStylePos)
+{
+  auto objectFit = aStylePos->mObjectFit;
+
+  // "object-fit: cover" & "object-fit: none" can give us a render rect that's
+  // larger than our container element's content-box.
+  if (objectFit == NS_STYLE_OBJECT_FIT_COVER ||
+      objectFit == NS_STYLE_OBJECT_FIT_NONE) {
+    return true;
+  }
+  // (All other object-fit values produce a concrete object size that's no larger
+  // than the constraint region.)
+
+  // Check each of our "object-position" coords to see if it could cause
+  // overflow in its dimension:
+  const nsStyleBackground::Position& objectPosistion = aStylePos->mObjectPosition;
+  if (ObjectPositionCoordMightCauseOverflow(objectPosistion.mXPosition) ||
+      ObjectPositionCoordMightCauseOverflow(objectPosistion.mYPosition)) {
+    return true;
+  }
+
+  return false;
+}
+
+
 /* static */ bool
 nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
                                   nsIPrincipal* aPrincipal,
                                   nsIURI* aSourceURI,
                                   uint32_t aLineNumber,
                                   const nsSubstring& aStyleText,
                                   nsresult* aRv)
 {
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -15,16 +15,17 @@ class nsCSSValue;
 class nsStringComparator;
 class nsStyleCoord;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 struct gfxFontFeature;
 struct gfxAlternateValue;
 struct nsCSSValueList;
+struct nsStylePosition;
 
 // Style utility functions
 class nsStyleUtil {
 public:
 
  static bool DashMatchCompare(const nsAString& aAttributeValue,
                                 const nsAString& aSelectorValue,
                                 const nsStringComparator& aComparator);
@@ -125,16 +126,33 @@ public:
    * (and return true from this function), because we don't currently support
    * those other values for vertical/height-flavored properties. So, if we
    * encounter them, we fall back to behaving as if we had flex-basis's initial
    * value.
    */
   static bool IsFlexBasisMainSize(const nsStyleCoord& aFlexBasis,
                                   bool aIsMainAxisHorizontal);
 
+  /**
+   * Returns true if our object-fit & object-position properties might cause
+   * a replaced element's contents to overflow its content-box (requiring
+   * clipping), or false if we can be sure that this won't happen.
+   *
+   * This lets us optimize by skipping clipping when we can tell it's
+   * unnecessary (particularly with the default values of these properties).
+   *
+   * @param aStylePos The nsStylePosition whose object-fit & object-position
+   *                  properties should be checked for potential overflow.
+   * @return false if we can be sure that the object-fit & object-position
+   *         properties on 'aStylePos' cannot cause a replaced element's
+   *         contents to overflow its content-box. Otherwise (if overflow is
+   *         is possible), returns true.
+   */
+  static bool ObjectPropsMightCauseOverflow(const nsStylePosition* aStylePos);
+
   /*
    *  Does this principal have a CSP that blocks the application of
    *  inline styles? Returns false if application of the style should
    *  be blocked.
    *
    *  @param aContent
    *      The <style> element that the caller wants to know whether to honor.
    *      Included to check the nonce attribute if one is provided. Allowed to