Bug 1113684 - part 1 - Handle vertical writing modes when displaying alt-text alongside a broken-image icon. r=smontagu

This commit is contained in:
Jonathan Kew 2015-01-06 20:56:03 +00:00
Родитель b1289a8906
Коммит c6f6059f08
1 изменённых файлов: 78 добавлений и 29 удалений

Просмотреть файл

@ -1100,14 +1100,23 @@ nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
nscoord maxAscent = fm->MaxAscent(); nscoord maxAscent = fm->MaxAscent();
nscoord maxDescent = fm->MaxDescent(); 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 // 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 // use where to break the text given a maximum width. At a minimum we need
// to be able to get the break character... // to be able to get the break character...
const char16_t* str = aAltText.get(); const char16_t* str = aAltText.get();
int32_t strLen = aAltText.Length(); int32_t strLen = aAltText.Length();
nscoord y = aRect.y; nsPoint pt = wm.IsVerticalRL() ? aRect.TopRight() - nsPoint(lineHeight, 0)
: aRect.TopLeft();
nscoord iSize = isVertical ? aRect.height : aRect.width;
if (!aPresContext->BidiEnabled() && HasRTLChars(aAltText)) { if (!aPresContext->BidiEnabled() && HasRTLChars(aAltText)) {
aPresContext->SetBidiEnabled(); aPresContext->SetBidiEnabled();
@ -1115,38 +1124,71 @@ nsImageFrame::DisplayAltText(nsPresContext* aPresContext,
// Always show the first line, even if we have to clip it below // Always show the first line, even if we have to clip it below
bool firstLine = true; 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 // Determine how much of the text to display on this line
uint32_t maxFit; // number of characters that fit 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); aRenderingContext, *fm);
// Display the text // Display the text
nsresult rv = NS_ERROR_FAILURE; nsresult rv = NS_ERROR_FAILURE;
if (aPresContext->BidiEnabled()) { if (aPresContext->BidiEnabled()) {
const nsStyleVisibility* vis = StyleVisibility(); nsBidiDirection dir;
if (vis->mDirection == NS_STYLE_DIRECTION_RTL) nscoord x, y;
rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_RTL,
aPresContext, aRenderingContext, if (isVertical) {
aRenderingContext, *fm, x = pt.x + maxDescent; // XXX will need update for sideways-left
aRect.XMost() - strWidth, y + maxAscent); if (wm.IsBidiLTR()) {
else y = aRect.y;
rv = nsBidiPresUtils::RenderText(str, maxFit, NSBIDI_LTR, dir = NSBIDI_LTR;
aPresContext, aRenderingContext, } else {
aRenderingContext, *fm, y = aRect.YMost() - strWidth;
aRect.x, y + maxAscent); 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)) { if (NS_FAILED(rv)) {
nsLayoutUtils::DrawUniDirString(str, maxFit, nsLayoutUtils::DrawUniDirString(str, maxFit,
nsPoint(aRect.x, y + maxAscent), *fm, isVertical
aRenderingContext); ? nsPoint(pt.x + maxDescent, pt.y)
: nsPoint(pt.x, pt.y + maxAscent),
*fm, aRenderingContext);
} }
// Move to the next line // Move to the next line
str += maxFit; str += maxFit;
strLen -= maxFit; strLen -= maxFit;
y += height; if (wm.IsVerticalRL()) {
pt.x -= lineHeight;
} else if (wm.IsVerticalLR()) {
pt.x += lineHeight;
} else {
pt.y += lineHeight;
}
firstLine = false; firstLine = false;
} }
} }
@ -1247,7 +1289,6 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
// Check if we should display image placeholders // Check if we should display image placeholders
if (gIconLoad->mPrefShowPlaceholders) { if (gIconLoad->mPrefShowPlaceholders) {
const nsStyleVisibility* vis = StyleVisibility();
nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE); nscoord size = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE);
bool iconUsed = false; bool iconUsed = false;
@ -1260,6 +1301,9 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
mDisplayingIcon = true; mDisplayingIcon = true;
} }
WritingMode wm = GetWritingMode();
bool flushRight =
(!wm.IsVertical() && !wm.IsBidiLTR()) || wm.IsVerticalRL();
// If the icon in question is loaded and decoded, draw it // If the icon in question is loaded and decoded, draw it
uint32_t imageStatus = 0; uint32_t imageStatus = 0;
@ -1269,8 +1313,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
nsCOMPtr<imgIContainer> imgCon; nsCOMPtr<imgIContainer> imgCon;
aRequest->GetImage(getter_AddRefs(imgCon)); aRequest->GetImage(getter_AddRefs(imgCon));
MOZ_ASSERT(imgCon, "Load complete, but no image container?"); MOZ_ASSERT(imgCon, "Load complete, but no image container?");
nsRect dest((vis->mDirection == NS_STYLE_DIRECTION_RTL) ? nsRect dest(flushRight ? inner.XMost() - size : inner.x,
inner.XMost() - size : inner.x,
inner.y, size, size); inner.y, size, size);
nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon, nsLayoutUtils::DrawSingleImage(*gfx, PresContext(), imgCon,
nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect, nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
@ -1283,8 +1326,7 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext,
if (!iconUsed) { if (!iconUsed) {
ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f))); ColorPattern color(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
nscoord iconXPos = (vis->mDirection == NS_STYLE_DIRECTION_RTL) ? nscoord iconXPos = flushRight ? inner.XMost() - size : inner.x;
inner.XMost() - size : inner.x;
// stroked rect: // stroked rect:
nsRect rect(iconXPos, inner.y, size, size); 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 // Reduce the inner rect by the width of the icon, and leave an
// additional ICON_PADDING pixels for padding // additional ICON_PADDING pixels for padding
int32_t iconWidth = nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING); int32_t paddedIconSize =
if (vis->mDirection != NS_STYLE_DIRECTION_RTL) nsPresContext::CSSPixelsToAppUnits(ICON_SIZE + ICON_PADDING);
inner.x += iconWidth; if (wm.IsVertical()) {
inner.width -= iconWidth; inner.y += paddedIconSize;
inner.height -= paddedIconSize;
} else {
if (!flushRight) {
inner.x += paddedIconSize;
}
inner.width -= paddedIconSize;
}
} }
// If there's still room, display the alt-text // If there's still room, display the alt-text