nsTextBoxFrame.cpp 40 KB

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