Bug 1341703 - Part 3. Ensure full decode be triggered after style-image was downloaded,
In nsCSSRendering::PaintBorderWithStyleBorder:
DrawResult
nsCSSRendering::PaintBorderWithStyleBorder()
{
if (aStyleBorder.IsBorderImageLoaded()) {
(1)
}
(2)
}
At (1), we create a nsCSSBorderImageRenderer object. While creating it, we call
imgRenderer.PrepareImage() to ensure a full image decode at [1]. PrepareImage is
used in both bg-image/mask-image and border-image. The difference is, in
bg-image/mask-image painting path, we unconditionally use PrepareImage(in
nsCSSRendering::PrepareImageLayer), whereas in border-image painting path we
use it only after border-image was downloaded. This difference does cause a
problem. After border image was downloaded, the decoder will not do full decoding
since we did not ask for it, so there will be no repaint notification and no
chance to paint border-image again.
In this patch, I try to align the behavior between bg-image/mask-image and
border-image: always call nsImageRenderer::PrepareImage.
This is a generic fix for both stylo-enable and stylo-disable build. We do not
find this problem in reftest is because we use SYNC_DECODE in reftest harness, which
hides this race condition. When dairy using firefox, if
nsCSSRendering::PaintBorderWithStyleBorder is called after border-image was
loaded, your program run into (1), border-image will be drawn correctly; In the
case that nsCSSRendering::PaintBorderWithStyleBorder is called before
border-image is loaded, your program run into (2), and you can only see
border-color.
[1]
https://hg.mozilla.org/mozilla-central/file/a6f35285bd1e/layout/painting/nsCSSRenderingBorders.cpp#l3598
MozReview-Commit-ID: 6pidHJdPG8I
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -815,34 +815,36 @@ nsCSSRendering::PaintBorderWithStyleBord
nsITheme *theme = aPresContext->GetTheme();
if (theme &&
theme->ThemeSupportsWidget(aPresContext, aForFrame,
displayData->UsedAppearance())) {
return DrawResult::SUCCESS; // Let the theme handle it.
}
}
- if (aStyleBorder.IsBorderImageLoaded()) {
- DrawResult result;
+ if (!aStyleBorder.mBorderImageSource.IsEmpty()) {
+ DrawResult result = DrawResult::SUCCESS;
uint32_t irFlags = 0;
if (aFlags & PaintBorderFlags::SYNC_DECODE_IMAGES) {
irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
}
Maybe<nsCSSBorderImageRenderer> renderer =
nsCSSBorderImageRenderer::CreateBorderImageRenderer(aPresContext, aForFrame, aBorderArea,
aStyleBorder, aDirtyRect, aSkipSides,
irFlags, &result);
- if (!renderer) {
- return result;
+ if (aStyleBorder.IsBorderImageLoaded()) {
+ if (!renderer) {
+ return result;
+ }
+
+ return renderer->DrawBorderImage(aPresContext, aRenderingContext,
+ aForFrame, aDirtyRect);
}
-
- return renderer->DrawBorderImage(aPresContext, aRenderingContext,
- aForFrame, aDirtyRect);
}
DrawResult result = DrawResult::SUCCESS;
// If we had a border-image, but it wasn't loaded, then we should return
// DrawResult::NOT_READY; we'll want to try again if we do a paint with sync
// decoding enabled.
if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3580,18 +3580,16 @@ nsCSSBorderImageRenderer::CreateBorderIm
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleBorder& aStyleBorder,
const nsRect& aDirtyRect,
Sides aSkipSides,
uint32_t aFlags,
DrawResult* aDrawResult)
{
- NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
- "drawing border image that isn't successfully loaded");
MOZ_ASSERT(aDrawResult);
if (aDirtyRect.IsEmpty()) {
*aDrawResult = DrawResult::SUCCESS;
return Nothing();
}
nsImageRenderer imgRenderer(aForFrame, &aStyleBorder.mBorderImageSource, aFlags);