void nsTextBoxFrame::CalculateUnderline(nsIRenderingContext& aRenderingContext) { if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { // Calculate all fields of mAccessKeyInfo which // are the same for both BiDi and non-BiDi frames. const PRUnichar *titleString = mCroppedTitle.get(); aRenderingContext.SetTextRunRTL(PR_FALSE); aRenderingContext.GetWidth(titleString[mAccessKeyInfo->mAccesskeyIndex], mAccessKeyInfo->mAccessWidth); nscoord offset, baseline; nsIFontMetrics *metrics; aRenderingContext.GetFontMetrics(metrics); metrics->GetUnderline(offset, mAccessKeyInfo->mAccessUnderlineSize); metrics->GetMaxAscent(baseline); NS_RELEASE(metrics); mAccessKeyInfo->mAccessOffset = baseline - offset; } }
void nsTextBoxFrame::CalculateTitleForWidth(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, nscoord aWidth) { if (mTitle.IsEmpty()) return; nsLayoutUtils::SetFontFromStyle(&aRenderingContext, GetStyleContext()); // see if the text will completely fit in the width given mTitleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, mTitle.get(), mTitle.Length()); if (mTitleWidth <= aWidth) { mCroppedTitle = mTitle; #ifdef IBMBIDI if (HasRTLChars(mTitle)) { mState |= NS_FRAME_IS_BIDI; } #endif // IBMBIDI return; // fits, done. } const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis(); // start with an ellipsis mCroppedTitle.Assign(kEllipsis); // see if the width is even smaller than the ellipsis // if so, clear the text (XXX set as many '.' as we can?). aRenderingContext.SetTextRunRTL(PR_FALSE); aRenderingContext.GetWidth(kEllipsis, mTitleWidth); if (mTitleWidth > aWidth) { mCroppedTitle.SetLength(0); mTitleWidth = 0; return; } // if the ellipsis fits perfectly, no use in trying to insert if (mTitleWidth == aWidth) return; aWidth -= mTitleWidth; // XXX: This whole block should probably take surrogates into account // XXX and clusters! // ok crop things switch (mCropType) { case CropNone: case CropRight: { nscoord cwidth; nscoord twidth = 0; int length = mTitle.Length(); int i; for (i = 0; i < length; ++i) { PRUnichar ch = mTitle.CharAt(i); // still in LTR mode aRenderingContext.GetWidth(ch,cwidth); if (twidth + cwidth > aWidth) break; twidth += cwidth; #ifdef IBMBIDI if (UCS2_CHAR_IS_BIDI(ch) ) { mState |= NS_FRAME_IS_BIDI; } #endif // IBMBIDI } if (i == 0) return; // insert what character we can in. nsAutoString title( mTitle ); title.Truncate(i); mCroppedTitle.Insert(title, 0); } break; case CropLeft: { nscoord cwidth; nscoord twidth = 0; int length = mTitle.Length(); int i; for (i=length-1; i >= 0; --i) { PRUnichar ch = mTitle.CharAt(i); aRenderingContext.GetWidth(ch,cwidth); if (twidth + cwidth > aWidth) break; twidth += cwidth; #ifdef IBMBIDI if (UCS2_CHAR_IS_BIDI(ch) ) { mState |= NS_FRAME_IS_BIDI; } #endif // IBMBIDI } if (i == length-1) return; nsAutoString copy; mTitle.Right(copy, length-1-i); mCroppedTitle += copy; } break; case CropCenter: { nscoord stringWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, mTitle.get(), mTitle.Length()); if (stringWidth <= aWidth) { // the entire string will fit in the maximum width mCroppedTitle.Insert(mTitle, 0); break; } // determine how much of the string will fit in the max width nscoord charWidth = 0; nscoord totalWidth = 0; PRUnichar ch; int leftPos, rightPos; nsAutoString leftString, rightString; rightPos = mTitle.Length() - 1; aRenderingContext.SetTextRunRTL(PR_FALSE); for (leftPos = 0; leftPos <= rightPos;) { // look at the next character on the left end ch = mTitle.CharAt(leftPos); aRenderingContext.GetWidth(ch, charWidth); totalWidth += charWidth; if (totalWidth > aWidth) // greater than the allowable width break; leftString.Insert(ch, leftString.Length()); #ifdef IBMBIDI if (UCS2_CHAR_IS_BIDI(ch)) mState |= NS_FRAME_IS_BIDI; #endif // look at the next character on the right end if (rightPos > leftPos) { // haven't looked at this character yet ch = mTitle.CharAt(rightPos); aRenderingContext.GetWidth(ch, charWidth); totalWidth += charWidth; if (totalWidth > aWidth) // greater than the allowable width break; rightString.Insert(ch, 0); #ifdef IBMBIDI if (UCS2_CHAR_IS_BIDI(ch)) mState |= NS_FRAME_IS_BIDI; #endif } // look at the next two characters leftPos++; rightPos--; } mCroppedTitle = leftString + kEllipsis + rightString; } break; } mTitleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext, mCroppedTitle.get(), mCroppedTitle.Length()); }
void nsTextBoxFrame::DrawText(nsIRenderingContext& aRenderingContext, const nsRect& aTextRect, const nscolor* aOverrideColor) { nsPresContext* presContext = PresContext(); // paint the title nscolor overColor; nscolor underColor; nscolor strikeColor; nsStyleContext* context = mStyleContext; PRUint8 decorations = NS_STYLE_TEXT_DECORATION_NONE; // Begin with no decorations PRUint8 decorMask = NS_STYLE_TEXT_DECORATION_UNDERLINE | NS_STYLE_TEXT_DECORATION_OVERLINE | NS_STYLE_TEXT_DECORATION_LINE_THROUGH; // A mask of all possible decorations. PRBool hasDecorations = context->HasTextDecorations(); do { // find decoration colors const nsStyleTextReset* styleText = context->GetStyleTextReset(); if (decorMask & styleText->mTextDecoration) { // a decoration defined here nscolor color = aOverrideColor ? *aOverrideColor : context->GetStyleColor()->mColor; if (NS_STYLE_TEXT_DECORATION_UNDERLINE & decorMask & styleText->mTextDecoration) { underColor = color; decorMask &= ~NS_STYLE_TEXT_DECORATION_UNDERLINE; decorations |= NS_STYLE_TEXT_DECORATION_UNDERLINE; } if (NS_STYLE_TEXT_DECORATION_OVERLINE & decorMask & styleText->mTextDecoration) { overColor = color; decorMask &= ~NS_STYLE_TEXT_DECORATION_OVERLINE; decorations |= NS_STYLE_TEXT_DECORATION_OVERLINE; } if (NS_STYLE_TEXT_DECORATION_LINE_THROUGH & decorMask & styleText->mTextDecoration) { strikeColor = color; decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_THROUGH; decorations |= NS_STYLE_TEXT_DECORATION_LINE_THROUGH; } } if (0 != decorMask) { context = context->GetParent(); if (context) { hasDecorations = context->HasTextDecorations(); } } } while (context && hasDecorations && (0 != decorMask)); nsCOMPtr<nsIFontMetrics> fontMet; nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)); nscoord offset; nscoord size; nscoord ascent; fontMet->GetMaxAscent(ascent); nscoord baseline = presContext->RoundAppUnitsToNearestDevPixels(aTextRect.y + ascent); nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext(); gfxPoint pt(presContext->AppUnitsToGfxUnits(aTextRect.x), presContext->AppUnitsToGfxUnits(aTextRect.y)); gfxFloat width = presContext->AppUnitsToGfxUnits(aTextRect.width); gfxFloat ascentPixel = presContext->AppUnitsToGfxUnits(ascent); // Underlines are drawn before overlines, and both before the text // itself, per http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1. // (We don't apply this rule to the access-key underline because we only // find out where that is as a side effect of drawing the text, in the // general case -- see below.) if (decorations & (NS_FONT_DECORATION_OVERLINE | NS_FONT_DECORATION_UNDERLINE)) { fontMet->GetUnderline(offset, size); gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset); gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size); if (decorations & NS_FONT_DECORATION_UNDERLINE) { nsCSSRendering::PaintDecorationLine(ctx, underColor, pt, gfxSize(width, sizePixel), ascentPixel, offsetPixel, NS_STYLE_TEXT_DECORATION_UNDERLINE, nsCSSRendering::DECORATION_STYLE_SOLID); } if (decorations & NS_FONT_DECORATION_OVERLINE) { nsCSSRendering::PaintDecorationLine(ctx, overColor, pt, gfxSize(width, sizePixel), ascentPixel, ascentPixel, NS_STYLE_TEXT_DECORATION_OVERLINE, nsCSSRendering::DECORATION_STYLE_SOLID); } } aRenderingContext.SetFont(fontMet); CalculateUnderline(aRenderingContext); aRenderingContext.SetColor(aOverrideColor ? *aOverrideColor : GetStyleColor()->mColor); #ifdef IBMBIDI nsresult rv = NS_ERROR_FAILURE; if (mState & NS_FRAME_IS_BIDI) { presContext->SetBidiEnabled(); nsBidiPresUtils* bidiUtils = presContext->GetBidiUtils(); if (bidiUtils) { const nsStyleVisibility* vis = GetStyleVisibility(); nsBidiDirection direction = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ? NSBIDI_RTL : NSBIDI_LTR; if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { // We let the RenderText function calculate the mnemonic's // underline position for us. nsBidiPositionResolve posResolve; posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex; rv = bidiUtils->RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction, presContext, aRenderingContext, aTextRect.x, baseline, &posResolve, 1); mAccessKeyInfo->mBeforeWidth = posResolve.visualLeftTwips; mAccessKeyInfo->mAccessWidth = posResolve.visualWidth; } else { rv = bidiUtils->RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), direction, presContext, aRenderingContext, aTextRect.x, baseline); } } } if (NS_FAILED(rv) ) #endif // IBMBIDI { aRenderingContext.SetTextRunRTL(PR_FALSE); if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { // In the simple (non-BiDi) case, we calculate the mnemonic's // underline position by getting the text metric. // XXX are attribute values always two byte? if (mAccessKeyInfo->mAccesskeyIndex > 0) aRenderingContext.GetWidth(mCroppedTitle.get(), mAccessKeyInfo->mAccesskeyIndex, mAccessKeyInfo->mBeforeWidth); else mAccessKeyInfo->mBeforeWidth = 0; } aRenderingContext.DrawString(mCroppedTitle, aTextRect.x, baseline); } if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) { aRenderingContext.FillRect(aTextRect.x + mAccessKeyInfo->mBeforeWidth, aTextRect.y + mAccessKeyInfo->mAccessOffset, mAccessKeyInfo->mAccessWidth, mAccessKeyInfo->mAccessUnderlineSize); } // Strikeout is drawn on top of the text, per // http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1. if (decorations & NS_FONT_DECORATION_LINE_THROUGH) { fontMet->GetStrikeout(offset, size); gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset); gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size); nsCSSRendering::PaintDecorationLine(ctx, strikeColor, pt, gfxSize(width, sizePixel), ascentPixel, offsetPixel, NS_STYLE_TEXT_DECORATION_LINE_THROUGH, nsCSSRendering::DECORATION_STYLE_SOLID); } }