LCOV - code coverage report
Current view: top level - layout/xul - nsTextBoxFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 337 602 56.0 %
Date: 2017-07-14 16:53:18 Functions: 40 49 81.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=4 sw=4 sts=4 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsTextBoxFrame.h"
       8             : 
       9             : #include "gfx2DGlue.h"
      10             : #include "gfxUtils.h"
      11             : #include "mozilla/gfx/2D.h"
      12             : #include "nsFontMetrics.h"
      13             : #include "nsReadableUtils.h"
      14             : #include "nsCOMPtr.h"
      15             : #include "nsGkAtoms.h"
      16             : #include "nsPresContext.h"
      17             : #include "gfxContext.h"
      18             : #include "nsStyleContext.h"
      19             : #include "nsIContent.h"
      20             : #include "nsNameSpaceManager.h"
      21             : #include "nsBoxLayoutState.h"
      22             : #include "nsMenuBarListener.h"
      23             : #include "nsXPIDLString.h"
      24             : #include "nsIServiceManager.h"
      25             : #include "nsIDOMElement.h"
      26             : #include "nsIDOMXULLabelElement.h"
      27             : #include "mozilla/EventStateManager.h"
      28             : #include "nsITheme.h"
      29             : #include "nsUnicharUtils.h"
      30             : #include "nsContentUtils.h"
      31             : #include "nsDisplayList.h"
      32             : #include "nsCSSRendering.h"
      33             : #include "nsIReflowCallback.h"
      34             : #include "nsBoxFrame.h"
      35             : #include "mozilla/Preferences.h"
      36             : #include "nsLayoutUtils.h"
      37             : #include "mozilla/Attributes.h"
      38             : #include "nsUnicodeProperties.h"
      39             : 
      40             : #ifdef ACCESSIBILITY
      41             : #include "nsAccessibilityService.h"
      42             : #endif
      43             : 
      44             : #include "nsBidiUtils.h"
      45             : #include "nsBidiPresUtils.h"
      46             : 
      47             : using namespace mozilla;
      48             : using namespace mozilla::gfx;
      49             : 
      50             : class nsAccessKeyInfo
      51             : {
      52             : public:
      53             :     int32_t mAccesskeyIndex;
      54             :     nscoord mBeforeWidth, mAccessWidth, mAccessUnderlineSize, mAccessOffset;
      55             : };
      56             : 
      57             : 
      58             : bool nsTextBoxFrame::gAlwaysAppendAccessKey          = false;
      59             : bool nsTextBoxFrame::gAccessKeyPrefInitialized       = false;
      60             : bool nsTextBoxFrame::gInsertSeparatorBeforeAccessKey = false;
      61             : bool nsTextBoxFrame::gInsertSeparatorPrefInitialized = false;
      62             : 
      63             : nsIFrame*
      64          11 : NS_NewTextBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
      65             : {
      66          11 :     return new (aPresShell) nsTextBoxFrame(aContext);
      67             : }
      68             : 
      69          11 : NS_IMPL_FRAMEARENA_HELPERS(nsTextBoxFrame)
      70             : 
      71          38 : NS_QUERYFRAME_HEAD(nsTextBoxFrame)
      72           0 :   NS_QUERYFRAME_ENTRY(nsTextBoxFrame)
      73          38 : NS_QUERYFRAME_TAIL_INHERITING(nsLeafBoxFrame)
      74             : 
      75             : nsresult
      76           2 : nsTextBoxFrame::AttributeChanged(int32_t         aNameSpaceID,
      77             :                                  nsIAtom*        aAttribute,
      78             :                                  int32_t         aModType)
      79             : {
      80             :     bool aResize;
      81             :     bool aRedraw;
      82             : 
      83           2 :     UpdateAttributes(aAttribute, aResize, aRedraw);
      84             : 
      85           2 :     if (aResize) {
      86           2 :         PresContext()->PresShell()->
      87           2 :             FrameNeedsReflow(this, nsIPresShell::eStyleChange,
      88           4 :                              NS_FRAME_IS_DIRTY);
      89           0 :     } else if (aRedraw) {
      90           0 :         nsBoxLayoutState state(PresContext());
      91           0 :         XULRedraw(state);
      92             :     }
      93             : 
      94             :     // If the accesskey changed, register for the new value
      95             :     // The old value has been unregistered in nsXULElement::SetAttr
      96           2 :     if (aAttribute == nsGkAtoms::accesskey || aAttribute == nsGkAtoms::control)
      97           0 :         RegUnregAccessKey(true);
      98             : 
      99           2 :     return NS_OK;
     100             : }
     101             : 
     102          11 : nsTextBoxFrame::nsTextBoxFrame(nsStyleContext* aContext)
     103             :   : nsLeafBoxFrame(aContext, kClassID)
     104             :   , mAccessKeyInfo(nullptr)
     105             :   , mCropType(CropRight)
     106             :   , mAscent(0)
     107          11 :   , mNeedsReflowCallback(false)
     108             : {
     109          11 :   MarkIntrinsicISizesDirty();
     110          11 : }
     111             : 
     112           0 : nsTextBoxFrame::~nsTextBoxFrame()
     113             : {
     114           0 :     delete mAccessKeyInfo;
     115           0 : }
     116             : 
     117             : 
     118             : void
     119          11 : nsTextBoxFrame::Init(nsIContent*       aContent,
     120             :                      nsContainerFrame* aParent,
     121             :                      nsIFrame*         aPrevInFlow)
     122             : {
     123          11 :     nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
     124             : 
     125             :     bool aResize;
     126             :     bool aRedraw;
     127          11 :     UpdateAttributes(nullptr, aResize, aRedraw); /* update all */
     128             : 
     129             :     // register access key
     130          11 :     RegUnregAccessKey(true);
     131          11 : }
     132             : 
     133             : void
     134           0 : nsTextBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
     135             : {
     136             :     // unregister access key
     137           0 :     RegUnregAccessKey(false);
     138           0 :     nsLeafBoxFrame::DestroyFrom(aDestructRoot);
     139           0 : }
     140             : 
     141             : bool
     142          14 : nsTextBoxFrame::AlwaysAppendAccessKey()
     143             : {
     144          14 :   if (!gAccessKeyPrefInitialized)
     145             :   {
     146           1 :     gAccessKeyPrefInitialized = true;
     147             : 
     148           1 :     const char* prefName = "intl.menuitems.alwaysappendaccesskeys";
     149           2 :     nsAdoptingString val = Preferences::GetLocalizedString(prefName);
     150           1 :     gAlwaysAppendAccessKey = val.EqualsLiteral("true");
     151             :   }
     152          14 :   return gAlwaysAppendAccessKey;
     153             : }
     154             : 
     155             : bool
     156           0 : nsTextBoxFrame::InsertSeparatorBeforeAccessKey()
     157             : {
     158           0 :   if (!gInsertSeparatorPrefInitialized)
     159             :   {
     160           0 :     gInsertSeparatorPrefInitialized = true;
     161             : 
     162           0 :     const char* prefName = "intl.menuitems.insertseparatorbeforeaccesskeys";
     163           0 :     nsAdoptingString val = Preferences::GetLocalizedString(prefName);
     164           0 :     gInsertSeparatorBeforeAccessKey = val.EqualsLiteral("true");
     165             :   }
     166           0 :   return gInsertSeparatorBeforeAccessKey;
     167             : }
     168             : 
     169          11 : class nsAsyncAccesskeyUpdate final : public nsIReflowCallback
     170             : {
     171             : public:
     172          11 :     explicit nsAsyncAccesskeyUpdate(nsIFrame* aFrame) : mWeakFrame(aFrame)
     173             :     {
     174          11 :     }
     175             : 
     176          11 :     virtual bool ReflowFinished() override
     177             :     {
     178          11 :         bool shouldFlush = false;
     179             :         nsTextBoxFrame* frame =
     180          11 :             static_cast<nsTextBoxFrame*>(mWeakFrame.GetFrame());
     181          11 :         if (frame) {
     182          11 :             shouldFlush = frame->UpdateAccesskey(mWeakFrame);
     183             :         }
     184          11 :         delete this;
     185          11 :         return shouldFlush;
     186             :     }
     187             : 
     188           0 :     virtual void ReflowCallbackCanceled() override
     189             :     {
     190           0 :         delete this;
     191           0 :     }
     192             : 
     193             :     WeakFrame mWeakFrame;
     194             : };
     195             : 
     196             : bool
     197          11 : nsTextBoxFrame::UpdateAccesskey(WeakFrame& aWeakThis)
     198             : {
     199          22 :     nsAutoString accesskey;
     200          22 :     nsCOMPtr<nsIDOMXULLabelElement> labelElement = do_QueryInterface(mContent);
     201          11 :     NS_ENSURE_TRUE(aWeakThis.IsAlive(), false);
     202          11 :     if (labelElement) {
     203             :         // Accesskey may be stored on control.
     204          10 :         labelElement->GetAccessKey(accesskey);
     205          10 :         NS_ENSURE_TRUE(aWeakThis.IsAlive(), false);
     206             :     }
     207             :     else {
     208           1 :         mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accesskey);
     209             :     }
     210             : 
     211          11 :     if (!accesskey.Equals(mAccessKey)) {
     212             :         // Need to get clean mTitle.
     213           7 :         RecomputeTitle();
     214           7 :         mAccessKey = accesskey;
     215           7 :         UpdateAccessTitle();
     216           7 :         PresContext()->PresShell()->
     217           7 :             FrameNeedsReflow(this, nsIPresShell::eStyleChange,
     218          14 :                              NS_FRAME_IS_DIRTY);
     219           7 :         return true;
     220             :     }
     221           4 :     return false;
     222             : }
     223             : 
     224             : void
     225          13 : nsTextBoxFrame::UpdateAttributes(nsIAtom*         aAttribute,
     226             :                                  bool&          aResize,
     227             :                                  bool&          aRedraw)
     228             : {
     229          13 :     bool doUpdateTitle = false;
     230          13 :     aResize = false;
     231          13 :     aRedraw = false;
     232             : 
     233          13 :     if (aAttribute == nullptr || aAttribute == nsGkAtoms::crop) {
     234             :         static nsIContent::AttrValuesArray strings[] =
     235             :           {&nsGkAtoms::left, &nsGkAtoms::start, &nsGkAtoms::center,
     236             :            &nsGkAtoms::right, &nsGkAtoms::end, &nsGkAtoms::none, nullptr};
     237             :         CroppingStyle cropType;
     238          22 :         switch (mContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::crop,
     239          11 :                                           strings, eCaseMatters)) {
     240             :           case 0:
     241             :           case 1:
     242           0 :             cropType = CropLeft;
     243           0 :             break;
     244             :           case 2:
     245           1 :             cropType = CropCenter;
     246           1 :             break;
     247             :           case 3:
     248             :           case 4:
     249           9 :             cropType = CropRight;
     250           9 :             break;
     251             :           case 5:
     252           0 :             cropType = CropNone;
     253           0 :             break;
     254             :           default:
     255           1 :             cropType = CropAuto;
     256           1 :             break;
     257             :         }
     258             : 
     259          11 :         if (cropType != mCropType) {
     260           2 :             aResize = true;
     261           2 :             mCropType = cropType;
     262             :         }
     263             :     }
     264             : 
     265          13 :     if (aAttribute == nullptr || aAttribute == nsGkAtoms::value) {
     266          13 :         RecomputeTitle();
     267          13 :         doUpdateTitle = true;
     268             :     }
     269             : 
     270          13 :     if (aAttribute == nullptr || aAttribute == nsGkAtoms::accesskey) {
     271          11 :         mNeedsReflowCallback = true;
     272             :         // Ensure that layout is refreshed and reflow callback called.
     273          11 :         aResize = true;
     274             :     }
     275             : 
     276          13 :     if (doUpdateTitle) {
     277          13 :         UpdateAccessTitle();
     278          13 :         aResize = true;
     279             :     }
     280             : 
     281          13 : }
     282             : 
     283             : class nsDisplayXULTextBox final : public nsDisplayItem
     284             : {
     285             : public:
     286          11 :   nsDisplayXULTextBox(nsDisplayListBuilder* aBuilder,
     287          11 :                       nsTextBoxFrame* aFrame) :
     288             :     nsDisplayItem(aBuilder, aFrame),
     289          11 :     mDisableSubpixelAA(false)
     290             :   {
     291          11 :     MOZ_COUNT_CTOR(nsDisplayXULTextBox);
     292          11 :   }
     293             : #ifdef NS_BUILD_REFCNT_LOGGING
     294          22 :   virtual ~nsDisplayXULTextBox() {
     295          11 :     MOZ_COUNT_DTOR(nsDisplayXULTextBox);
     296          11 :   }
     297             : #endif
     298             : 
     299             :   virtual void Paint(nsDisplayListBuilder* aBuilder,
     300             :                      gfxContext* aCtx) override;
     301             :   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
     302             :                            bool* aSnap) override;
     303          95 :   NS_DISPLAY_DECL_NAME("XULTextBox", TYPE_XUL_TEXT_BOX)
     304             : 
     305             :   virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) override;
     306             : 
     307           0 :   virtual void DisableComponentAlpha() override {
     308           0 :     mDisableSubpixelAA = true;
     309           0 :   }
     310             : 
     311             :   void PaintTextToContext(gfxContext* aCtx,
     312             :                           nsPoint aOffset,
     313             :                           const nscolor* aColor);
     314             : 
     315             :   bool mDisableSubpixelAA;
     316             : };
     317             : 
     318             : static void
     319           0 : PaintTextShadowCallback(gfxContext* aCtx,
     320             :                         nsPoint aShadowOffset,
     321             :                         const nscolor& aShadowColor,
     322             :                         void* aData)
     323             : {
     324             :   reinterpret_cast<nsDisplayXULTextBox*>(aData)->
     325           0 :            PaintTextToContext(aCtx, aShadowOffset, &aShadowColor);
     326           0 : }
     327             : 
     328             : void
     329           3 : nsDisplayXULTextBox::Paint(nsDisplayListBuilder* aBuilder,
     330             :                            gfxContext* aCtx)
     331             : {
     332             :   DrawTargetAutoDisableSubpixelAntialiasing disable(aCtx->GetDrawTarget(),
     333           6 :                                                     mDisableSubpixelAA);
     334             : 
     335             :   // Paint the text shadow before doing any foreground stuff
     336           3 :   nsRect drawRect = static_cast<nsTextBoxFrame*>(mFrame)->mTextDrawRect +
     337           9 :                     ToReferenceFrame();
     338           3 :   nsLayoutUtils::PaintTextShadow(mFrame, aCtx,
     339             :                                  drawRect, mVisibleRect,
     340           3 :                                  mFrame->StyleColor()->mColor,
     341             :                                  PaintTextShadowCallback,
     342           3 :                                  (void*)this);
     343             : 
     344           3 :   PaintTextToContext(aCtx, nsPoint(0, 0), nullptr);
     345           3 : }
     346             : 
     347             : void
     348           3 : nsDisplayXULTextBox::PaintTextToContext(gfxContext* aCtx,
     349             :                                         nsPoint aOffset,
     350             :                                         const nscolor* aColor)
     351             : {
     352           3 :   static_cast<nsTextBoxFrame*>(mFrame)->
     353           6 :     PaintTitle(*aCtx, mVisibleRect, ToReferenceFrame() + aOffset, aColor);
     354           3 : }
     355             : 
     356             : nsRect
     357          47 : nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
     358          47 :   *aSnap = false;
     359          47 :   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
     360             : }
     361             : 
     362             : nsRect
     363          11 : nsDisplayXULTextBox::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
     364             : {
     365          22 :   return static_cast<nsTextBoxFrame*>(mFrame)->GetComponentAlphaBounds() +
     366          33 :       ToReferenceFrame();
     367             : }
     368             : 
     369             : void
     370          14 : nsTextBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
     371             :                                  const nsRect&           aDirtyRect,
     372             :                                  const nsDisplayListSet& aLists)
     373             : {
     374          14 :     if (!IsVisibleForPainting(aBuilder))
     375           3 :         return;
     376             : 
     377          11 :     nsLeafBoxFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists);
     378             : 
     379          11 :     aLists.Content()->AppendNewToTop(new (aBuilder)
     380          22 :         nsDisplayXULTextBox(aBuilder, this));
     381             : }
     382             : 
     383             : void
     384           3 : nsTextBoxFrame::PaintTitle(gfxContext&          aRenderingContext,
     385             :                            const nsRect&        aDirtyRect,
     386             :                            nsPoint              aPt,
     387             :                            const nscolor*       aOverrideColor)
     388             : {
     389           3 :     if (mTitle.IsEmpty())
     390           0 :         return;
     391             : 
     392           3 :     DrawText(aRenderingContext, aDirtyRect, mTextDrawRect + aPt, aOverrideColor);
     393             : }
     394             : 
     395             : void
     396           3 : nsTextBoxFrame::DrawText(gfxContext&         aRenderingContext,
     397             :                          const nsRect&       aDirtyRect,
     398             :                          const nsRect&       aTextRect,
     399             :                          const nscolor*      aOverrideColor)
     400             : {
     401           3 :     nsPresContext* presContext = PresContext();
     402           3 :     int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
     403           3 :     DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
     404             : 
     405             :     // paint the title
     406           3 :     nscolor overColor = 0;
     407           3 :     nscolor underColor = 0;
     408           3 :     nscolor strikeColor = 0;
     409           3 :     uint8_t overStyle = 0;
     410           3 :     uint8_t underStyle = 0;
     411           3 :     uint8_t strikeStyle = 0;
     412             : 
     413             :     // Begin with no decorations
     414           3 :     uint8_t decorations = NS_STYLE_TEXT_DECORATION_LINE_NONE;
     415             :     // A mask of all possible decorations.
     416           3 :     uint8_t decorMask = NS_STYLE_TEXT_DECORATION_LINE_LINES_MASK;
     417             : 
     418           3 :     WritingMode wm = GetWritingMode();
     419           3 :     bool vertical = wm.IsVertical();
     420             : 
     421           3 :     nsIFrame* f = this;
     422           0 :     do {  // find decoration colors
     423           3 :       nsStyleContext* context = f->StyleContext();
     424           3 :       if (!context->HasTextDecorationLines()) {
     425           3 :         break;
     426             :       }
     427           0 :       const nsStyleTextReset* styleText = context->StyleTextReset();
     428             : 
     429           0 :       if (decorMask & styleText->mTextDecorationLine) {  // a decoration defined here
     430             :         nscolor color;
     431           0 :         if (aOverrideColor) {
     432           0 :           color = *aOverrideColor;
     433             :         } else {
     434             :           color = context->StyleColor()->
     435           0 :             CalcComplexColor(styleText->mTextDecorationColor);
     436             :         }
     437           0 :         uint8_t style = styleText->mTextDecorationStyle;
     438             : 
     439           0 :         if (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE & decorMask &
     440           0 :               styleText->mTextDecorationLine) {
     441           0 :           underColor = color;
     442           0 :           underStyle = style;
     443           0 :           decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
     444           0 :           decorations |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
     445             :         }
     446           0 :         if (NS_STYLE_TEXT_DECORATION_LINE_OVERLINE & decorMask &
     447           0 :               styleText->mTextDecorationLine) {
     448           0 :           overColor = color;
     449           0 :           overStyle = style;
     450           0 :           decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
     451           0 :           decorations |= NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
     452             :         }
     453           0 :         if (NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH & decorMask &
     454           0 :               styleText->mTextDecorationLine) {
     455           0 :           strikeColor = color;
     456           0 :           strikeStyle = style;
     457           0 :           decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
     458           0 :           decorations |= NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
     459             :         }
     460             :       }
     461           0 :     } while (0 != decorMask &&
     462             :              (f = nsLayoutUtils::GetParentOrPlaceholderFor(f)));
     463             : 
     464             :     RefPtr<nsFontMetrics> fontMet =
     465           6 :       nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
     466           3 :     fontMet->SetVertical(wm.IsVertical());
     467           3 :     fontMet->SetTextOrientation(StyleVisibility()->mTextOrientation);
     468             : 
     469             :     nscoord offset;
     470             :     nscoord size;
     471           3 :     nscoord ascent = fontMet->MaxAscent();
     472             : 
     473           3 :     nsPoint baselinePt;
     474           3 :     if (wm.IsVertical()) {
     475           0 :       baselinePt.x =
     476           0 :         presContext->RoundAppUnitsToNearestDevPixels(aTextRect.x +
     477           0 :             (wm.IsVerticalRL() ? aTextRect.width - ascent : ascent));
     478           0 :       baselinePt.y = aTextRect.y;
     479             :     } else {
     480           3 :       baselinePt.x = aTextRect.x;
     481           3 :       baselinePt.y =
     482           3 :         presContext->RoundAppUnitsToNearestDevPixels(aTextRect.y + ascent);
     483             :     }
     484             : 
     485           3 :     nsCSSRendering::PaintDecorationLineParams params;
     486           3 :     params.dirtyRect = ToRect(presContext->AppUnitsToGfxUnits(aDirtyRect));
     487           3 :     params.pt = Point(presContext->AppUnitsToGfxUnits(aTextRect.x),
     488           3 :                       presContext->AppUnitsToGfxUnits(aTextRect.y));
     489           3 :     params.icoordInFrame =
     490           3 :       Float(PresContext()->AppUnitsToGfxUnits(mTextDrawRect.x));
     491           3 :     params.lineSize = Size(presContext->AppUnitsToGfxUnits(aTextRect.width), 0);
     492           3 :     params.ascent = presContext->AppUnitsToGfxUnits(ascent);
     493           3 :     params.vertical = vertical;
     494             : 
     495             :     // XXX todo: vertical-mode support for decorations not tested yet,
     496             :     // probably won't be positioned correctly
     497             : 
     498             :     // Underlines are drawn before overlines, and both before the text
     499             :     // itself, per http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1.
     500             :     // (We don't apply this rule to the access-key underline because we only
     501             :     // find out where that is as a side effect of drawing the text, in the
     502             :     // general case -- see below.)
     503           3 :     if (decorations & (NS_STYLE_TEXT_DECORATION_LINE_OVERLINE |
     504             :                        NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE)) {
     505           0 :       fontMet->GetUnderline(offset, size);
     506           0 :       params.lineSize.height = presContext->AppUnitsToGfxUnits(size);
     507           0 :       if ((decorations & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) &&
     508             :           underStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
     509           0 :         params.color = underColor;
     510           0 :         params.offset = presContext->AppUnitsToGfxUnits(offset);
     511           0 :         params.decoration = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
     512           0 :         params.style = underStyle;
     513           0 :         nsCSSRendering::PaintDecorationLine(this, *drawTarget, params);
     514             :       }
     515           0 :       if ((decorations & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) &&
     516             :           overStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
     517           0 :         params.color = overColor;
     518           0 :         params.offset = params.ascent;
     519           0 :         params.decoration = NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
     520           0 :         params.style = overStyle;
     521           0 :         nsCSSRendering::PaintDecorationLine(this, *drawTarget, params);
     522             :       }
     523             :     }
     524             : 
     525             :     RefPtr<gfxContext> refContext =
     526           6 :         PresContext()->PresShell()->CreateReferenceRenderingContext();
     527           3 :     DrawTarget* refDrawTarget = refContext->GetDrawTarget();
     528             : 
     529           3 :     CalculateUnderline(refDrawTarget, *fontMet);
     530             : 
     531           3 :     nscolor c = aOverrideColor ? *aOverrideColor : StyleColor()->mColor;
     532           6 :     ColorPattern color(ToDeviceColor(c));
     533           3 :     aRenderingContext.SetColor(Color::FromABGR(c));
     534             : 
     535           3 :     nsresult rv = NS_ERROR_FAILURE;
     536             : 
     537           3 :     if (mState & NS_FRAME_IS_BIDI) {
     538           0 :       presContext->SetBidiEnabled();
     539           0 :       nsBidiLevel level = nsBidiPresUtils::BidiLevelFromStyle(StyleContext());
     540           0 :       if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
     541             :           // We let the RenderText function calculate the mnemonic's
     542             :           // underline position for us.
     543             :           nsBidiPositionResolve posResolve;
     544           0 :           posResolve.logicalIndex = mAccessKeyInfo->mAccesskeyIndex;
     545           0 :           rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level,
     546             :                                            presContext, aRenderingContext,
     547             :                                            refDrawTarget, *fontMet,
     548             :                                            baselinePt.x, baselinePt.y,
     549             :                                            &posResolve,
     550           0 :                                            1);
     551           0 :           mAccessKeyInfo->mBeforeWidth = posResolve.visualLeftTwips;
     552           0 :           mAccessKeyInfo->mAccessWidth = posResolve.visualWidth;
     553             :       }
     554             :       else
     555             :       {
     556           0 :           rv = nsBidiPresUtils::RenderText(mCroppedTitle.get(), mCroppedTitle.Length(), level,
     557             :                                            presContext, aRenderingContext,
     558             :                                            refDrawTarget, *fontMet,
     559           0 :                                            baselinePt.x, baselinePt.y);
     560             :       }
     561             :     }
     562           3 :     if (NS_FAILED(rv)) {
     563           3 :        fontMet->SetTextRunRTL(false);
     564             : 
     565           3 :        if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
     566             :            // In the simple (non-BiDi) case, we calculate the mnemonic's
     567             :            // underline position by getting the text metric.
     568             :            // XXX are attribute values always two byte?
     569           0 :            if (mAccessKeyInfo->mAccesskeyIndex > 0)
     570           0 :                mAccessKeyInfo->mBeforeWidth = nsLayoutUtils::
     571           0 :                    AppUnitWidthOfString(mCroppedTitle.get(),
     572           0 :                                         mAccessKeyInfo->mAccesskeyIndex,
     573             :                                         *fontMet, refDrawTarget);
     574             :            else
     575           0 :                mAccessKeyInfo->mBeforeWidth = 0;
     576             :        }
     577             : 
     578           3 :        fontMet->DrawString(mCroppedTitle.get(), mCroppedTitle.Length(),
     579             :                            baselinePt.x, baselinePt.y, &aRenderingContext,
     580           3 :                            refDrawTarget);
     581             :     }
     582             : 
     583           3 :     if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
     584           0 :       nsRect r(aTextRect.x + mAccessKeyInfo->mBeforeWidth,
     585           0 :                aTextRect.y + mAccessKeyInfo->mAccessOffset,
     586           0 :                mAccessKeyInfo->mAccessWidth,
     587           0 :                mAccessKeyInfo->mAccessUnderlineSize);
     588             :       Rect devPxRect =
     589           0 :         NSRectToSnappedRect(r, appUnitsPerDevPixel, *drawTarget);
     590           0 :       drawTarget->FillRect(devPxRect, color);
     591             :     }
     592             : 
     593             :     // Strikeout is drawn on top of the text, per
     594             :     // http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1.
     595           3 :     if ((decorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) &&
     596             :         strikeStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
     597           0 :       fontMet->GetStrikeout(offset, size);
     598           0 :       params.color = strikeColor;
     599           0 :       params.lineSize.height = presContext->AppUnitsToGfxUnits(size);
     600           0 :       params.offset = presContext->AppUnitsToGfxUnits(offset);
     601           0 :       params.decoration = NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
     602           0 :       params.style = strikeStyle;
     603           0 :       nsCSSRendering::PaintDecorationLine(this, *drawTarget, params);
     604             :     }
     605           3 : }
     606             : 
     607             : void
     608           3 : nsTextBoxFrame::CalculateUnderline(DrawTarget* aDrawTarget,
     609             :                                    nsFontMetrics& aFontMetrics)
     610             : {
     611           3 :     if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
     612             :          // Calculate all fields of mAccessKeyInfo which
     613             :          // are the same for both BiDi and non-BiDi frames.
     614           0 :          const char16_t *titleString = mCroppedTitle.get();
     615           0 :          aFontMetrics.SetTextRunRTL(false);
     616           0 :          mAccessKeyInfo->mAccessWidth = nsLayoutUtils::
     617           0 :              AppUnitWidthOfString(titleString[mAccessKeyInfo->mAccesskeyIndex],
     618             :                                   aFontMetrics, aDrawTarget);
     619             : 
     620             :          nscoord offset, baseline;
     621           0 :          aFontMetrics.GetUnderline(offset, mAccessKeyInfo->mAccessUnderlineSize);
     622           0 :          baseline = aFontMetrics.MaxAscent();
     623           0 :          mAccessKeyInfo->mAccessOffset = baseline - offset;
     624             :     }
     625           3 : }
     626             : 
     627             : nscoord
     628          24 : nsTextBoxFrame::CalculateTitleForWidth(gfxContext&          aRenderingContext,
     629             :                                        nscoord              aWidth)
     630             : {
     631          24 :     DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
     632             : 
     633          24 :     if (mTitle.IsEmpty()) {
     634           4 :         mCroppedTitle.Truncate();
     635           4 :         return 0;
     636             :     }
     637             : 
     638             :     RefPtr<nsFontMetrics> fm =
     639          40 :       nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
     640             : 
     641             :     // see if the text will completely fit in the width given
     642             :     nscoord titleWidth =
     643          20 :       nsLayoutUtils::AppUnitWidthOfStringBidi(mTitle, this, *fm,
     644          20 :                                               aRenderingContext);
     645          20 :     if (titleWidth <= aWidth) {
     646          19 :         mCroppedTitle = mTitle;
     647          38 :         if (HasRTLChars(mTitle) ||
     648          19 :             StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
     649           0 :             mState |= NS_FRAME_IS_BIDI;
     650             :         }
     651          19 :         return titleWidth;  // fits, done.
     652             :     }
     653             : 
     654           2 :     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     655           1 :     if (mCropType != CropNone) {
     656             :       // start with an ellipsis
     657           1 :       mCroppedTitle.Assign(kEllipsis);
     658             : 
     659             :       // see if the width is even smaller than the ellipsis
     660             :       // if so, clear the text (XXX set as many '.' as we can?).
     661           1 :       fm->SetTextRunRTL(false);
     662           1 :       titleWidth = nsLayoutUtils::AppUnitWidthOfString(kEllipsis, *fm,
     663           1 :                                                        drawTarget);
     664             : 
     665           1 :       if (titleWidth > aWidth) {
     666           1 :           mCroppedTitle.SetLength(0);
     667           1 :           return 0;
     668             :       }
     669             : 
     670             :       // if the ellipsis fits perfectly, no use in trying to insert
     671           0 :       if (titleWidth == aWidth)
     672           0 :           return titleWidth;
     673             : 
     674           0 :       aWidth -= titleWidth;
     675             :     } else {
     676           0 :       mCroppedTitle.Truncate(0);
     677           0 :       titleWidth = 0;
     678             :     }
     679             : 
     680             :     using mozilla::unicode::ClusterIterator;
     681             :     using mozilla::unicode::ClusterReverseIterator;
     682             : 
     683             :     // ok crop things
     684           0 :     switch (mCropType)
     685             :     {
     686             :         case CropAuto:
     687             :         case CropNone:
     688             :         case CropRight:
     689             :         {
     690           0 :             ClusterIterator iter(mTitle.Data(), mTitle.Length());
     691           0 :             const char16_t* dataBegin = iter;
     692           0 :             const char16_t* pos = dataBegin;
     693             :             nscoord charWidth;
     694           0 :             nscoord totalWidth = 0;
     695             : 
     696           0 :             while (!iter.AtEnd()) {
     697           0 :                 iter.Next();
     698           0 :                 const char16_t* nextPos = iter;
     699           0 :                 ptrdiff_t length = nextPos - pos;
     700           0 :                 charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
     701             :                                                                 *fm,
     702           0 :                                                                 drawTarget);
     703           0 :                 if (totalWidth + charWidth > aWidth) {
     704           0 :                     break;
     705             :                 }
     706             : 
     707           0 :                 if (UCS2_CHAR_IS_BIDI(*pos)) {
     708           0 :                     mState |= NS_FRAME_IS_BIDI;
     709             :                 }
     710           0 :                 pos = nextPos;
     711           0 :                 totalWidth += charWidth;
     712             :             }
     713             : 
     714           0 :             if (pos == dataBegin) {
     715           0 :                 return titleWidth;
     716             :             }
     717             : 
     718             :             // insert what character we can in.
     719           0 :             nsAutoString title(mTitle);
     720           0 :             title.Truncate(pos - dataBegin);
     721           0 :             mCroppedTitle.Insert(title, 0);
     722             :         }
     723           0 :         break;
     724             : 
     725             :         case CropLeft:
     726             :         {
     727           0 :             ClusterReverseIterator iter(mTitle.Data(), mTitle.Length());
     728           0 :             const char16_t* dataEnd = iter;
     729           0 :             const char16_t* prevPos = dataEnd;
     730             :             nscoord charWidth;
     731           0 :             nscoord totalWidth = 0;
     732             : 
     733           0 :             while (!iter.AtEnd()) {
     734           0 :                 iter.Next();
     735           0 :                 const char16_t* pos = iter;
     736           0 :                 ptrdiff_t length = prevPos - pos;
     737           0 :                 charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
     738             :                                                                 *fm,
     739           0 :                                                                 drawTarget);
     740           0 :                 if (totalWidth + charWidth > aWidth) {
     741           0 :                     break;
     742             :                 }
     743             : 
     744           0 :                 if (UCS2_CHAR_IS_BIDI(*pos)) {
     745           0 :                     mState |= NS_FRAME_IS_BIDI;
     746             :                 }
     747           0 :                 prevPos = pos;
     748           0 :                 totalWidth += charWidth;
     749             :             }
     750             : 
     751           0 :             if (prevPos == dataEnd) {
     752           0 :                 return titleWidth;
     753             :             }
     754             : 
     755           0 :             nsAutoString copy;
     756           0 :             mTitle.Right(copy, dataEnd - prevPos);
     757           0 :             mCroppedTitle += copy;
     758             :         }
     759           0 :         break;
     760             : 
     761             :         case CropCenter:
     762             :         {
     763             :             nscoord stringWidth =
     764           0 :                 nsLayoutUtils::AppUnitWidthOfStringBidi(mTitle, this, *fm,
     765           0 :                                                         aRenderingContext);
     766           0 :             if (stringWidth <= aWidth) {
     767             :                 // the entire string will fit in the maximum width
     768           0 :                 mCroppedTitle.Insert(mTitle, 0);
     769           0 :                 break;
     770             :             }
     771             : 
     772             :             // determine how much of the string will fit in the max width
     773           0 :             nscoord charWidth = 0;
     774           0 :             nscoord totalWidth = 0;
     775           0 :             ClusterIterator leftIter(mTitle.Data(), mTitle.Length());
     776           0 :             ClusterReverseIterator rightIter(mTitle.Data(), mTitle.Length());
     777           0 :             const char16_t* dataBegin = leftIter;
     778           0 :             const char16_t* dataEnd = rightIter;
     779           0 :             const char16_t* leftPos = dataBegin;
     780           0 :             const char16_t* rightPos = dataEnd;
     781             :             const char16_t* pos;
     782             :             ptrdiff_t length;
     783           0 :             nsAutoString leftString, rightString;
     784             : 
     785           0 :             while (leftPos < rightPos) {
     786           0 :                 leftIter.Next();
     787           0 :                 pos = leftIter;
     788           0 :                 length = pos - leftPos;
     789           0 :                 charWidth = nsLayoutUtils::AppUnitWidthOfString(leftPos, length,
     790             :                                                                 *fm,
     791           0 :                                                                 drawTarget);
     792           0 :                 if (totalWidth + charWidth > aWidth) {
     793           0 :                     break;
     794             :                 }
     795             : 
     796           0 :                 if (UCS2_CHAR_IS_BIDI(*leftPos)) {
     797           0 :                     mState |= NS_FRAME_IS_BIDI;
     798             :                 }
     799             : 
     800           0 :                 leftString.Append(leftPos, length);
     801           0 :                 leftPos = pos;
     802           0 :                 totalWidth += charWidth;
     803             : 
     804           0 :                 if (leftPos >= rightPos) {
     805           0 :                     break;
     806             :                 }
     807             : 
     808           0 :                 rightIter.Next();
     809           0 :                 pos = rightIter;
     810           0 :                 length = rightPos - pos;
     811           0 :                 charWidth = nsLayoutUtils::AppUnitWidthOfString(pos, length,
     812             :                                                                 *fm,
     813           0 :                                                                 drawTarget);
     814           0 :                 if (totalWidth + charWidth > aWidth) {
     815           0 :                     break;
     816             :                 }
     817             : 
     818           0 :                 if (UCS2_CHAR_IS_BIDI(*pos)) {
     819           0 :                     mState |= NS_FRAME_IS_BIDI;
     820             :                 }
     821             : 
     822           0 :                 rightString.Insert(pos, 0, length);
     823           0 :                 rightPos = pos;
     824           0 :                 totalWidth += charWidth;
     825             :             }
     826             : 
     827           0 :             mCroppedTitle = leftString + kEllipsis + rightString;
     828             :         }
     829           0 :         break;
     830             :     }
     831             : 
     832           0 :     return nsLayoutUtils::AppUnitWidthOfStringBidi(mCroppedTitle, this, *fm,
     833           0 :                                                    aRenderingContext);
     834             : }
     835             : 
     836             : #define OLD_ELLIPSIS NS_LITERAL_STRING("...")
     837             : 
     838             : // the following block is to append the accesskey to mTitle if there is an accesskey
     839             : // but the mTitle doesn't have the character
     840             : void
     841          22 : nsTextBoxFrame::UpdateAccessTitle()
     842             : {
     843             :     /*
     844             :      * Note that if you change appending access key label spec,
     845             :      * you need to maintain same logic in following methods. See bug 324159.
     846             :      * toolkit/content/commonDialog.js (setLabelForNode)
     847             :      * toolkit/content/widgets/text.xml (formatAccessKey)
     848             :      */
     849             :     int32_t menuAccessKey;
     850          22 :     nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
     851          22 :     if (!menuAccessKey || mAccessKey.IsEmpty())
     852          37 :         return;
     853             : 
     854          28 :     if (!AlwaysAppendAccessKey() &&
     855          28 :         FindInReadable(mAccessKey, mTitle, nsCaseInsensitiveStringComparator()))
     856           7 :         return;
     857             : 
     858           0 :     nsAutoString accessKeyLabel;
     859           0 :     accessKeyLabel += '(';
     860           0 :     accessKeyLabel += mAccessKey;
     861           0 :     ToUpperCase(accessKeyLabel);
     862           0 :     accessKeyLabel += ')';
     863             : 
     864           0 :     if (mTitle.IsEmpty()) {
     865           0 :         mTitle = accessKeyLabel;
     866           0 :         return;
     867             :     }
     868             : 
     869           0 :     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     870           0 :     uint32_t offset = mTitle.Length();
     871           0 :     if (StringEndsWith(mTitle, kEllipsis)) {
     872           0 :         offset -= kEllipsis.Length();
     873           0 :     } else if (StringEndsWith(mTitle, OLD_ELLIPSIS)) {
     874             :         // Try to check with our old ellipsis (for old addons)
     875           0 :         offset -= OLD_ELLIPSIS.Length();
     876             :     } else {
     877             :         // Try to check with
     878             :         // our default ellipsis (for non-localized addons) or ':'
     879           0 :         const char16_t kLastChar = mTitle.Last();
     880           0 :         if (kLastChar == char16_t(0x2026) || kLastChar == char16_t(':'))
     881           0 :             offset--;
     882             :     }
     883             : 
     884           0 :     if (InsertSeparatorBeforeAccessKey() &&
     885           0 :         offset > 0 && !NS_IS_SPACE(mTitle[offset - 1])) {
     886           0 :         mTitle.Insert(' ', offset);
     887           0 :         offset++;
     888             :     }
     889             : 
     890           0 :     mTitle.Insert(accessKeyLabel, offset);
     891             : }
     892             : 
     893             : void
     894          24 : nsTextBoxFrame::UpdateAccessIndex()
     895             : {
     896             :     int32_t menuAccessKey;
     897          24 :     nsMenuBarListener::GetMenuAccessKey(&menuAccessKey);
     898          24 :     if (menuAccessKey) {
     899          24 :         if (mAccessKey.IsEmpty()) {
     900          17 :             if (mAccessKeyInfo) {
     901           0 :                 delete mAccessKeyInfo;
     902           0 :                 mAccessKeyInfo = nullptr;
     903             :             }
     904             :         } else {
     905           7 :             if (!mAccessKeyInfo) {
     906           7 :                 mAccessKeyInfo = new nsAccessKeyInfo();
     907           7 :                 if (!mAccessKeyInfo)
     908           0 :                     return;
     909             :             }
     910             : 
     911           7 :             nsAString::const_iterator start, end;
     912             : 
     913           7 :             mCroppedTitle.BeginReading(start);
     914           7 :             mCroppedTitle.EndReading(end);
     915             : 
     916             :             // remember the beginning of the string
     917           7 :             nsAString::const_iterator originalStart = start;
     918             : 
     919             :             bool found;
     920           7 :             if (!AlwaysAppendAccessKey()) {
     921             :                 // not appending access key - do case-sensitive search
     922             :                 // first
     923           7 :                 found = FindInReadable(mAccessKey, start, end);
     924           7 :                 if (!found) {
     925             :                     // didn't find it - perform a case-insensitive search
     926           0 :                     start = originalStart;
     927           0 :                     found = FindInReadable(mAccessKey, start, end,
     928           0 :                                            nsCaseInsensitiveStringComparator());
     929             :                 }
     930             :             } else {
     931           0 :                 found = RFindInReadable(mAccessKey, start, end,
     932           0 :                                         nsCaseInsensitiveStringComparator());
     933             :             }
     934             : 
     935           7 :             if (found)
     936           7 :                 mAccessKeyInfo->mAccesskeyIndex = Distance(originalStart, start);
     937             :             else
     938           0 :                 mAccessKeyInfo->mAccesskeyIndex = kNotFound;
     939             :         }
     940             :     }
     941             : }
     942             : 
     943             : void
     944          22 : nsTextBoxFrame::RecomputeTitle()
     945             : {
     946          22 :   mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::value, mTitle);
     947             : 
     948             :   // This doesn't handle language-specific uppercasing/lowercasing
     949             :   // rules, unlike textruns.
     950          22 :   uint8_t textTransform = StyleText()->mTextTransform;
     951          22 :   if (textTransform == NS_STYLE_TEXT_TRANSFORM_UPPERCASE) {
     952           0 :     ToUpperCase(mTitle);
     953          22 :   } else if (textTransform == NS_STYLE_TEXT_TRANSFORM_LOWERCASE) {
     954           0 :     ToLowerCase(mTitle);
     955             :   }
     956             :   // We can't handle NS_STYLE_TEXT_TRANSFORM_CAPITALIZE because we
     957             :   // have no clue about word boundaries here.  We also don't handle
     958             :   // NS_STYLE_TEXT_TRANSFORM_FULL_WIDTH.
     959          22 : }
     960             : 
     961             : void
     962          32 : nsTextBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
     963             : {
     964          32 :   if (!aOldStyleContext) {
     965             :     // We're just being initialized
     966          11 :     return;
     967             :   }
     968             : 
     969          21 :   const nsStyleText* oldTextStyle = aOldStyleContext->PeekStyleText();
     970             :   // We should really have oldTextStyle here, since we asked for our
     971             :   // nsStyleText during Init(), but if it's not there for some reason
     972             :   // just assume the worst and recompute mTitle.
     973          40 :   if (!oldTextStyle ||
     974          19 :       oldTextStyle->mTextTransform != StyleText()->mTextTransform) {
     975           2 :     RecomputeTitle();
     976           2 :     UpdateAccessTitle();
     977             :   }
     978             : }
     979             : 
     980             : NS_IMETHODIMP
     981          24 : nsTextBoxFrame::DoXULLayout(nsBoxLayoutState& aBoxLayoutState)
     982             : {
     983          24 :     if (mNeedsReflowCallback) {
     984          11 :         nsIReflowCallback* cb = new nsAsyncAccesskeyUpdate(this);
     985          11 :         if (cb) {
     986          11 :             PresContext()->PresShell()->PostReflowCallback(cb);
     987             :         }
     988          11 :         mNeedsReflowCallback = false;
     989             :     }
     990             : 
     991          24 :     nsresult rv = nsLeafBoxFrame::DoXULLayout(aBoxLayoutState);
     992             : 
     993          24 :     CalcDrawRect(*aBoxLayoutState.GetRenderingContext());
     994             : 
     995          24 :     const nsStyleText* textStyle = StyleText();
     996             : 
     997          48 :     nsRect scrollBounds(nsPoint(0, 0), GetSize());
     998          48 :     nsRect textRect = mTextDrawRect;
     999             : 
    1000             :     RefPtr<nsFontMetrics> fontMet =
    1001          48 :       nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
    1002             :     nsBoundingMetrics metrics =
    1003             :       fontMet->GetInkBoundsForVisualOverflow(mCroppedTitle.get(),
    1004             :                                              mCroppedTitle.Length(),
    1005          24 :                                              aBoxLayoutState.GetRenderingContext()->GetDrawTarget());
    1006             : 
    1007          24 :     WritingMode wm = GetWritingMode();
    1008          48 :     LogicalRect tr(wm, textRect, GetSize());
    1009             : 
    1010          24 :     tr.IStart(wm) -= metrics.leftBearing;
    1011          24 :     tr.ISize(wm) = metrics.width;
    1012             :     // In DrawText() we always draw with the baseline at MaxAscent() (relative to mTextDrawRect),
    1013          24 :     tr.BStart(wm) += fontMet->MaxAscent() - metrics.ascent;
    1014          24 :     tr.BSize(wm) = metrics.ascent + metrics.descent;
    1015             : 
    1016          24 :     textRect = tr.GetPhysicalRect(wm, GetSize());
    1017             : 
    1018             :     // Our scrollable overflow is our bounds; our visual overflow may
    1019             :     // extend beyond that.
    1020          48 :     nsRect visualBounds;
    1021          24 :     visualBounds.UnionRect(scrollBounds, textRect);
    1022          48 :     nsOverflowAreas overflow(visualBounds, scrollBounds);
    1023             : 
    1024          24 :     if (textStyle->mTextShadow) {
    1025             :       // text-shadow extends our visual but not scrollable bounds
    1026           0 :       nsRect &vis = overflow.VisualOverflow();
    1027           0 :       vis.UnionRect(vis, nsLayoutUtils::GetTextShadowRectsUnion(mTextDrawRect, this));
    1028             :     }
    1029          24 :     FinishAndStoreOverflow(overflow, GetSize());
    1030             : 
    1031          48 :     return rv;
    1032             : }
    1033             : 
    1034             : nsRect
    1035          11 : nsTextBoxFrame::GetComponentAlphaBounds()
    1036             : {
    1037          11 :   if (StyleText()->mTextShadow) {
    1038           0 :     return GetVisualOverflowRectRelativeToSelf();
    1039             :   }
    1040          11 :   return mTextDrawRect;
    1041             : }
    1042             : 
    1043             : bool
    1044          24 : nsTextBoxFrame::ComputesOwnOverflowArea()
    1045             : {
    1046          24 :     return true;
    1047             : }
    1048             : 
    1049             : /* virtual */ void
    1050          28 : nsTextBoxFrame::MarkIntrinsicISizesDirty()
    1051             : {
    1052          28 :     mNeedsRecalc = true;
    1053          28 :     nsLeafBoxFrame::MarkIntrinsicISizesDirty();
    1054          28 : }
    1055             : 
    1056             : void
    1057          19 : nsTextBoxFrame::GetTextSize(gfxContext& aRenderingContext,
    1058             :                             const nsString& aString,
    1059             :                             nsSize& aSize, nscoord& aAscent)
    1060             : {
    1061             :     RefPtr<nsFontMetrics> fontMet =
    1062          38 :       nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
    1063          19 :     aSize.height = fontMet->MaxHeight();
    1064          19 :     aSize.width =
    1065          19 :       nsLayoutUtils::AppUnitWidthOfStringBidi(aString, this, *fontMet,
    1066             :                                               aRenderingContext);
    1067          19 :     aAscent = fontMet->MaxAscent();
    1068          19 : }
    1069             : 
    1070             : void
    1071         195 : nsTextBoxFrame::CalcTextSize(nsBoxLayoutState& aBoxLayoutState)
    1072             : {
    1073         195 :     if (mNeedsRecalc) {
    1074          19 :         nsSize size;
    1075          19 :         gfxContext* rendContext = aBoxLayoutState.GetRenderingContext();
    1076          19 :         if (rendContext) {
    1077          19 :             GetTextSize(*rendContext, mTitle, size, mAscent);
    1078          19 :             if (GetWritingMode().IsVertical()) {
    1079           0 :                 Swap(size.width, size.height);
    1080             :             }
    1081          19 :             mTextSize = size;
    1082          19 :             mNeedsRecalc = false;
    1083             :         }
    1084             :     }
    1085         195 : }
    1086             : 
    1087             : void
    1088          24 : nsTextBoxFrame::CalcDrawRect(gfxContext &aRenderingContext)
    1089             : {
    1090          24 :     WritingMode wm = GetWritingMode();
    1091             : 
    1092          48 :     LogicalRect textRect(wm, LogicalPoint(wm, 0, 0), GetLogicalSize(wm));
    1093          24 :     nsMargin borderPadding;
    1094          24 :     GetXULBorderAndPadding(borderPadding);
    1095          24 :     textRect.Deflate(wm, LogicalMargin(wm, borderPadding));
    1096             : 
    1097             :     // determine (cropped) title and underline position
    1098             :     // determine (cropped) title which fits in aRect, and its width
    1099             :     // (where "width" is the text measure along its baseline, i.e. actually
    1100             :     // a physical height in vertical writing modes)
    1101             :     nscoord titleWidth =
    1102          24 :         CalculateTitleForWidth(aRenderingContext, textRect.ISize(wm));
    1103             : 
    1104             : #ifdef ACCESSIBILITY
    1105             :     // Make sure to update the accessible tree in case when cropped title is
    1106             :     // changed.
    1107          24 :     nsAccessibilityService* accService = GetAccService();
    1108          24 :     if (accService) {
    1109           0 :         accService->UpdateLabelValue(PresContext()->PresShell(), mContent,
    1110           0 :                                      mCroppedTitle);
    1111             :     }
    1112             : #endif
    1113             : 
    1114             :     // determine if and at which position to put the underline
    1115          24 :     UpdateAccessIndex();
    1116             : 
    1117             :     // make the rect as small as our (cropped) text.
    1118          24 :     nscoord outerISize = textRect.ISize(wm);
    1119          24 :     textRect.ISize(wm) = titleWidth;
    1120             : 
    1121             :     // Align our text within the overall rect by checking our text-align property.
    1122          24 :     const nsStyleText* textStyle = StyleText();
    1123          24 :     if (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_CENTER) {
    1124           2 :       textRect.IStart(wm) += (outerISize - textRect.ISize(wm)) / 2;
    1125          66 :     } else if (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_END ||
    1126          22 :              (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_LEFT &&
    1127          44 :               !wm.IsBidiLTR()) ||
    1128          22 :              (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_RIGHT &&
    1129           0 :               wm.IsBidiLTR())) {
    1130           0 :       textRect.IStart(wm) += (outerISize - textRect.ISize(wm));
    1131             :     }
    1132             : 
    1133          24 :     mTextDrawRect = textRect.GetPhysicalRect(wm, GetSize());
    1134          24 : }
    1135             : 
    1136             : /**
    1137             :  * Ok return our dimensions
    1138             :  */
    1139             : nsSize
    1140          73 : nsTextBoxFrame::GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState)
    1141             : {
    1142          73 :     CalcTextSize(aBoxLayoutState);
    1143             : 
    1144          73 :     nsSize size = mTextSize;
    1145         146 :     DISPLAY_PREF_SIZE(this, size);
    1146             : 
    1147          73 :     AddBorderAndPadding(size);
    1148             :     bool widthSet, heightSet;
    1149          73 :     nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
    1150             : 
    1151         146 :     return size;
    1152             : }
    1153             : 
    1154             : /**
    1155             :  * Ok return our dimensions
    1156             :  */
    1157             : nsSize
    1158          75 : nsTextBoxFrame::GetXULMinSize(nsBoxLayoutState& aBoxLayoutState)
    1159             : {
    1160          75 :     CalcTextSize(aBoxLayoutState);
    1161             : 
    1162          75 :     nsSize size = mTextSize;
    1163         150 :     DISPLAY_MIN_SIZE(this, size);
    1164             : 
    1165             :     // if there is cropping our min width becomes our border and padding
    1166          75 :     if (mCropType != CropNone && mCropType != CropAuto) {
    1167          75 :         if (GetWritingMode().IsVertical()) {
    1168           0 :             size.height = 0;
    1169             :         } else {
    1170          75 :             size.width = 0;
    1171             :         }
    1172             :     }
    1173             : 
    1174          75 :     AddBorderAndPadding(size);
    1175             :     bool widthSet, heightSet;
    1176          75 :     nsIFrame::AddXULMinSize(aBoxLayoutState, this, size, widthSet, heightSet);
    1177             : 
    1178         150 :     return size;
    1179             : }
    1180             : 
    1181             : nscoord
    1182          47 : nsTextBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState)
    1183             : {
    1184          47 :     CalcTextSize(aBoxLayoutState);
    1185             : 
    1186          47 :     nscoord ascent = mAscent;
    1187             : 
    1188          47 :     nsMargin m(0,0,0,0);
    1189          47 :     GetXULBorderAndPadding(m);
    1190             : 
    1191          47 :     WritingMode wm = GetWritingMode();
    1192          47 :     ascent += LogicalMargin(wm, m).BStart(wm);
    1193             : 
    1194          47 :     return ascent;
    1195             : }
    1196             : 
    1197             : #ifdef DEBUG_FRAME_DUMP
    1198             : nsresult
    1199           0 : nsTextBoxFrame::GetFrameName(nsAString& aResult) const
    1200             : {
    1201           0 :     MakeFrameName(NS_LITERAL_STRING("TextBox"), aResult);
    1202           0 :     aResult += NS_LITERAL_STRING("[value=") + mTitle + NS_LITERAL_STRING("]");
    1203           0 :     return NS_OK;
    1204             : }
    1205             : #endif
    1206             : 
    1207             : // If you make changes to this function, check its counterparts
    1208             : // in nsBoxFrame and nsXULLabelFrame
    1209             : nsresult
    1210          11 : nsTextBoxFrame::RegUnregAccessKey(bool aDoReg)
    1211             : {
    1212             :     // if we have no content, we can't do anything
    1213          11 :     if (!mContent)
    1214           0 :         return NS_ERROR_FAILURE;
    1215             : 
    1216             :     // check if we have a |control| attribute
    1217             :     // do this check first because few elements have control attributes, and we
    1218             :     // can weed out most of the elements quickly.
    1219             : 
    1220             :     // XXXjag a side-effect is that we filter out anonymous <label>s
    1221             :     // in e.g. <menu>, <menuitem>, <button>. These <label>s inherit
    1222             :     // |accesskey| and would otherwise register themselves, overwriting
    1223             :     // the content we really meant to be registered.
    1224          11 :     if (!mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::control))
    1225          11 :         return NS_OK;
    1226             : 
    1227             :     // see if we even have an access key
    1228           0 :     nsAutoString accessKey;
    1229           0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
    1230             : 
    1231           0 :     if (accessKey.IsEmpty())
    1232           0 :         return NS_OK;
    1233             : 
    1234             :     // With a valid PresContext we can get the ESM
    1235             :     // and (un)register the access key
    1236           0 :     EventStateManager* esm = PresContext()->EventStateManager();
    1237             : 
    1238           0 :     uint32_t key = accessKey.First();
    1239           0 :     if (aDoReg)
    1240           0 :         esm->RegisterAccessKey(mContent, key);
    1241             :     else
    1242           0 :         esm->UnregisterAccessKey(mContent, key);
    1243             : 
    1244           0 :     return NS_OK;
    1245             : }

Generated by: LCOV version 1.13