From c6f6059f081a37b839703313b9f67c14648adf84 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 6 Jan 2015 20:56:03 +0000 Subject: [PATCH] Bug 1113684 - part 1 - Handle vertical writing modes when displaying alt-text alongside a broken-image icon. r=smontagu --- layout/generic/nsImageFrame.cpp | 107 +++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index f8a786fb00c6..f8d49fdadfa8 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1100,14 +1100,23 @@ nsImageFrame::DisplayAltText(nsPresContext* aPresContext, nscoord maxAscent = fm->MaxAscent(); nscoord maxDescent = fm->MaxDescent(); - nscoord height = fm->MaxHeight(); + nscoord lineHeight = fm->MaxHeight(); // line-relative, so an x-coordinate + // length if writing mode is vertical + + WritingMode wm = GetWritingMode(); + bool isVertical = wm.IsVertical(); + + fm->SetVertical(isVertical); + fm->SetTextOrientation(StyleVisibility()->mTextOrientation); // XXX It would be nice if there was a way to have the font metrics tell // use where to break the text given a maximum width. At a minimum we need // to be able to get the break character... const char16_t* str = aAltText.get(); - int32_t strLen = aAltText.Length(); - nscoord y = aRect.y; + int32_t strLen = aAltText.Length(); + nsPoint pt = wm.IsVerticalRL() ? aRect.TopRight() - nsPoint(lineHeight, 0) + : aRect.TopLeft(); + nscoord iSize = isVertical ? aRect.height : aRect.width; if (!aPresContext->BidiEnabled() && HasRTLChars(aAltText)) { aPresContext->SetBidiEnabled(); @@ -1115,38 +1124,71 @@ nsImageFrame::DisplayAltText(nsPresContext* aPresContext, // Always show the first line, even if we have to clip it below bool firstLine = true; - while ((strLen > 0) && (firstLine || (y + maxDescent) < aRect.YMost())) { + while (strLen > 0) { + if (!firstLine) { + // If we've run out of space, break out of the loop + if ((!isVertical && (pt.y + maxDescent) >= aRect.YMost()) || + (wm.IsVerticalRL() && (pt.x + maxDescent < aRect.x)) || + (wm.IsVerticalLR() && (pt.x + maxDescent >= aRect.XMost()))) { + break; + } + } + // Determine how much of the text to display on this line uint32_t maxFit; // number of characters that fit - nscoord strWidth = MeasureString(str, strLen, aRect.width, maxFit, + nscoord strWidth = MeasureString(str, strLen, iSize, maxFit, aRenderingContext, *fm); - + // Display the text nsresult rv = NS_ERROR_FAILURE; if (aPresContext->BidiEnabled()) { - const nsStyleVisibility* vis = StyleVisibility(); - if (vis->mDirection == NS_STYLE_DIRECTION_RTL) - rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_RTL, - aPresContext, aRenderingContext, - aRenderingContext, *fm, - aRect.XMost() - strWidth, y + maxAscent); - else - rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_LTR, - aPresContext, aRenderingContext, - aRenderingContext, *fm, - aRect.x, y + maxAscent); + nsBidiDirection dir; + nscoord x, y; + + if (isVertical) { + x = pt.x + maxDescent; // XXX will need update for sideways-left + if (wm.IsBidiLTR()) { + y = aRect.y; + dir = NSBIDI_LTR; + } else { + y = aRect.YMost() - strWidth; + dir = NSBIDI_RTL; + } + } else { + y = pt.y + maxAscent; + if (wm.IsBidiLTR()) { + x = aRect.x; + dir = NSBIDI_LTR; + } else { + x = aRect.XMost() - strWidth; + dir = NSBIDI_RTL; + } + } + + rv = nsBidiPresUtils::RenderText(str, maxFit, dir, + aPresContext, aRenderingContext, + aRenderingContext, *fm, x, y); } if (NS_FAILED(rv)) { nsLayoutUtils::DrawUniDirString(str, maxFit, - nsPoint(aRect.x, y + maxAscent), *fm, - aRenderingContext); + isVertical + ? nsPoint(pt.x + maxDescent, pt.y) + : nsPoint(pt.x, pt.y + maxAscent), + *fm, aRenderingContext); } // Move to the next line str += maxFit; strLen -= maxFit; - y += height; + if (wm.IsVerticalRL()) { + pt.x -= lineHeight; + } else if (wm.IsVerticalLR()) { + pt.x += lineHeight; + } else { + pt.y += lineHeight; + } + firstLine = false; } } @@ -1247,7 +1289,6 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, // Check if we should display image placeholders if (gIconLoad->mPrefShowPlaceholders) { - const nsStyleVisibility* vis = StyleVisibility(); nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE); bool iconUsed = false; @@ -1260,6 +1301,9 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, mDisplayingIcon = true; } + WritingMode wm = GetWritingMode(); + bool flushRight = + (!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL(); // If the icon in question is loaded and decoded, draw it uint32_t imageStatus = 0; @@ -1269,8 +1313,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, nsCOMPtr imgCon; aRequest->GetImage(getter_AddRefs(imgCon)); MOZ_ASSERT(imgCon, "Load complete, but no image container?"); - nsRect dest((vis->mDirection == NS_STYLE_DIRECTION_RTL) ? - inner.XMost() - size : inner.x, + nsRect dest(flushRight ? inner.XMost() - size : inner.x, inner.y, size, size); nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon, nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect, @@ -1283,8 +1326,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, if (!iconUsed) { ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f))); - nscoord iconXPos = (vis->mDirection == NS_STYLE_DIRECTION_RTL) ? - inner.XMost() - size : inner.x; + nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x; // stroked rect: nsRect rect(iconXPos, inner.y, size, size); @@ -1306,10 +1348,17 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, // Reduce the inner rect by the width of the icon, and leave an // additional ICON_PADDING pixels for padding - int32_t iconWidth = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING); - if (vis->mDirection != NS_STYLE_DIRECTION_RTL) - inner.x += iconWidth; - inner.width -= iconWidth; + int32_t paddedIconSize = + nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING); + if (wm.IsVertical()) { + inner.y += paddedIconSize; + inner.height -= paddedIconSize; + } else { + if (!flushRight) { + inner.x += paddedIconSize; + } + inner.width -= paddedIconSize; + } } // If there's still room, display the alt-text