nsTextControlFrame.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/DebugOnly.h"
  6. #include "nsCOMPtr.h"
  7. #include "nsFontMetrics.h"
  8. #include "nsTextControlFrame.h"
  9. #include "nsIPlaintextEditor.h"
  10. #include "nsCaret.h"
  11. #include "nsCSSPseudoElements.h"
  12. #include "nsGenericHTMLElement.h"
  13. #include "nsIEditor.h"
  14. #include "nsIEditorIMESupport.h"
  15. #include "nsIPhonetic.h"
  16. #include "nsTextFragment.h"
  17. #include "nsIDOMHTMLTextAreaElement.h"
  18. #include "nsNameSpaceManager.h"
  19. #include "nsFormControlFrame.h" //for registering accesskeys
  20. #include "nsIContent.h"
  21. #include "nsPresContext.h"
  22. #include "nsRenderingContext.h"
  23. #include "nsGkAtoms.h"
  24. #include "nsLayoutUtils.h"
  25. #include "nsIDOMElement.h"
  26. #include "nsIDOMHTMLElement.h"
  27. #include "nsIPresShell.h"
  28. #include <algorithm>
  29. #include "nsIDOMNodeList.h" //for selection setting helper func
  30. #include "nsIDOMRange.h" //for selection setting helper func
  31. #include "nsPIDOMWindow.h" //needed for notify selection changed to update the menus ect.
  32. #include "nsIDOMNode.h"
  33. #include "nsIDOMText.h" //for multiline getselection
  34. #include "nsFocusManager.h"
  35. #include "nsPresState.h"
  36. #include "nsContentList.h"
  37. #include "nsAttrValueInlines.h"
  38. #include "mozilla/dom/Selection.h"
  39. #include "mozilla/TextEditRules.h"
  40. #include "nsContentUtils.h"
  41. #include "nsTextNode.h"
  42. #include "mozilla/StyleSetHandle.h"
  43. #include "mozilla/StyleSetHandleInlines.h"
  44. #include "mozilla/dom/HTMLInputElement.h"
  45. #include "mozilla/dom/HTMLTextAreaElement.h"
  46. #include "mozilla/dom/ScriptSettings.h"
  47. #include "mozilla/MathAlgorithms.h"
  48. #include "nsFrameSelection.h"
  49. #define DEFAULT_COLUMN_WIDTH 20
  50. using namespace mozilla;
  51. using namespace mozilla::dom;
  52. nsIFrame*
  53. NS_NewTextControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  54. {
  55. return new (aPresShell) nsTextControlFrame(aContext);
  56. }
  57. NS_IMPL_FRAMEARENA_HELPERS(nsTextControlFrame)
  58. NS_QUERYFRAME_HEAD(nsTextControlFrame)
  59. NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
  60. NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
  61. NS_QUERYFRAME_ENTRY(nsITextControlFrame)
  62. NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
  63. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  64. #ifdef ACCESSIBILITY
  65. a11y::AccType
  66. nsTextControlFrame::AccessibleType()
  67. {
  68. return a11y::eHTMLTextFieldType;
  69. }
  70. #endif
  71. #ifdef DEBUG
  72. class EditorInitializerEntryTracker {
  73. public:
  74. explicit EditorInitializerEntryTracker(nsTextControlFrame &frame)
  75. : mFrame(frame)
  76. , mFirstEntry(false)
  77. {
  78. if (!mFrame.mInEditorInitialization) {
  79. mFrame.mInEditorInitialization = true;
  80. mFirstEntry = true;
  81. }
  82. }
  83. ~EditorInitializerEntryTracker()
  84. {
  85. if (mFirstEntry) {
  86. mFrame.mInEditorInitialization = false;
  87. }
  88. }
  89. bool EnteredMoreThanOnce() const { return !mFirstEntry; }
  90. private:
  91. nsTextControlFrame &mFrame;
  92. bool mFirstEntry;
  93. };
  94. #endif
  95. nsTextControlFrame::nsTextControlFrame(nsStyleContext* aContext)
  96. : nsContainerFrame(aContext)
  97. , mFirstBaseline(NS_INTRINSIC_WIDTH_UNKNOWN)
  98. , mEditorHasBeenInitialized(false)
  99. , mIsProcessing(false)
  100. #ifdef DEBUG
  101. , mInEditorInitialization(false)
  102. #endif
  103. {
  104. }
  105. nsTextControlFrame::~nsTextControlFrame()
  106. {
  107. }
  108. void
  109. nsTextControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
  110. {
  111. mScrollEvent.Revoke();
  112. EditorInitializer* initializer = GetProperty(TextControlInitializer());
  113. if (initializer) {
  114. initializer->Revoke();
  115. DeleteProperty(TextControlInitializer());
  116. }
  117. // Unbind the text editor state object from the frame. The editor will live
  118. // on, but things like controllers will be released.
  119. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  120. NS_ASSERTION(txtCtrl, "Content not a text control element");
  121. txtCtrl->UnbindFromFrame(this);
  122. nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
  123. nsContainerFrame::DestroyFrom(aDestructRoot);
  124. }
  125. nsIAtom*
  126. nsTextControlFrame::GetType() const
  127. {
  128. return nsGkAtoms::textInputFrame;
  129. }
  130. LogicalSize
  131. nsTextControlFrame::CalcIntrinsicSize(nsRenderingContext* aRenderingContext,
  132. WritingMode aWM,
  133. float aFontSizeInflation) const
  134. {
  135. LogicalSize intrinsicSize(aWM);
  136. // Get leading and the Average/MaxAdvance char width
  137. nscoord lineHeight = 0;
  138. nscoord charWidth = 0;
  139. nscoord charMaxAdvance = 0;
  140. RefPtr<nsFontMetrics> fontMet =
  141. nsLayoutUtils::GetFontMetricsForFrame(this, aFontSizeInflation);
  142. lineHeight =
  143. ReflowInput::CalcLineHeight(GetContent(), StyleContext(),
  144. NS_AUTOHEIGHT, aFontSizeInflation);
  145. charWidth = fontMet->AveCharWidth();
  146. charMaxAdvance = fontMet->MaxAdvance();
  147. // Set the width equal to the width in characters
  148. int32_t cols = GetCols();
  149. intrinsicSize.ISize(aWM) = cols * charWidth;
  150. // To better match IE, take the maximum character width(in twips) and remove
  151. // 4 pixels add this on as additional padding(internalPadding). But only do
  152. // this if we think we have a fixed-width font.
  153. if (mozilla::Abs(charWidth - charMaxAdvance) > (unsigned)nsPresContext::CSSPixelsToAppUnits(1)) {
  154. nscoord internalPadding =
  155. std::max(0, charMaxAdvance - nsPresContext::CSSPixelsToAppUnits(4));
  156. nscoord t = nsPresContext::CSSPixelsToAppUnits(1);
  157. // Round to a multiple of t
  158. nscoord rest = internalPadding % t;
  159. if (rest < t - rest) {
  160. internalPadding -= rest;
  161. } else {
  162. internalPadding += t - rest;
  163. }
  164. // Now add the extra padding on (so that small input sizes work well)
  165. intrinsicSize.ISize(aWM) += internalPadding;
  166. } else {
  167. // This is to account for the anonymous <br> having a 1 twip width
  168. // in Full Standards mode, see BRFrame::Reflow and bug 228752.
  169. if (PresContext()->CompatibilityMode() == eCompatibility_FullStandards) {
  170. intrinsicSize.ISize(aWM) += 1;
  171. }
  172. }
  173. // Increment width with cols * letter-spacing.
  174. {
  175. const nsStyleCoord& lsCoord = StyleText()->mLetterSpacing;
  176. if (eStyleUnit_Coord == lsCoord.GetUnit()) {
  177. nscoord letterSpacing = lsCoord.GetCoordValue();
  178. if (letterSpacing != 0) {
  179. intrinsicSize.ISize(aWM) += cols * letterSpacing;
  180. }
  181. }
  182. }
  183. // Set the height equal to total number of rows (times the height of each
  184. // line, of course)
  185. intrinsicSize.BSize(aWM) = lineHeight * GetRows();
  186. // Add in the size of the scrollbars for textarea
  187. if (IsTextArea()) {
  188. nsIFrame* first = PrincipalChildList().FirstChild();
  189. nsIScrollableFrame *scrollableFrame = do_QueryFrame(first);
  190. NS_ASSERTION(scrollableFrame, "Child must be scrollable");
  191. if (scrollableFrame) {
  192. LogicalMargin scrollbarSizes(aWM,
  193. scrollableFrame->GetDesiredScrollbarSizes(PresContext(),
  194. aRenderingContext));
  195. intrinsicSize.ISize(aWM) += scrollbarSizes.IStartEnd(aWM);
  196. intrinsicSize.BSize(aWM) += scrollbarSizes.BStartEnd(aWM);
  197. }
  198. }
  199. return intrinsicSize;
  200. }
  201. nsresult
  202. nsTextControlFrame::EnsureEditorInitialized()
  203. {
  204. // This method initializes our editor, if needed.
  205. // This code used to be called from CreateAnonymousContent(), but
  206. // when the editor set the initial string, it would trigger a
  207. // PresShell listener which called FlushPendingNotifications()
  208. // during frame construction. This was causing other form controls
  209. // to display wrong values. Additionally, calling this every time
  210. // a text frame control is instantiated means that we're effectively
  211. // instantiating the editor for all text fields, even if they
  212. // never get used. So, now this method is being called lazily only
  213. // when we actually need an editor.
  214. if (mEditorHasBeenInitialized)
  215. return NS_OK;
  216. nsIDocument* doc = mContent->GetComposedDoc();
  217. NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
  218. nsWeakFrame weakFrame(this);
  219. // Flush out content on our document. Have to do this, because script
  220. // blockers don't prevent the sink flushing out content and notifying in the
  221. // process, which can destroy frames.
  222. doc->FlushPendingNotifications(Flush_ContentAndNotify);
  223. NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE);
  224. // Make sure that editor init doesn't do things that would kill us off
  225. // (especially off the script blockers it'll create for its DOM mutations).
  226. {
  227. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  228. MOZ_ASSERT(txtCtrl, "Content not a text control element");
  229. // Hide selection changes during the initialization, as webpages should not
  230. // be aware of these initializations
  231. AutoHideSelectionChanges hideSelectionChanges(txtCtrl->GetConstFrameSelection());
  232. nsAutoScriptBlocker scriptBlocker;
  233. // Time to mess with our security context... See comments in GetValue()
  234. // for why this is needed.
  235. mozilla::dom::AutoNoJSAPI nojsapi;
  236. // Make sure that we try to focus the content even if the method fails
  237. class EnsureSetFocus {
  238. public:
  239. explicit EnsureSetFocus(nsTextControlFrame* aFrame)
  240. : mFrame(aFrame) {}
  241. ~EnsureSetFocus() {
  242. if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
  243. mFrame->SetFocus(true, false);
  244. }
  245. private:
  246. nsTextControlFrame *mFrame;
  247. };
  248. EnsureSetFocus makeSureSetFocusHappens(this);
  249. #ifdef DEBUG
  250. // Make sure we are not being called again until we're finished.
  251. // If reentrancy happens, just pretend that we don't have an editor.
  252. const EditorInitializerEntryTracker tracker(*this);
  253. NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
  254. "EnsureEditorInitialized has been called while a previous call was in progress");
  255. #endif
  256. // Create an editor for the frame, if one doesn't already exist
  257. nsresult rv = txtCtrl->CreateEditor();
  258. NS_ENSURE_SUCCESS(rv, rv);
  259. NS_ENSURE_STATE(weakFrame.IsAlive());
  260. // Set mEditorHasBeenInitialized so that subsequent calls will use the
  261. // editor.
  262. mEditorHasBeenInitialized = true;
  263. if (weakFrame.IsAlive()) {
  264. int32_t position = 0;
  265. // Set the selection to the end of the text field (bug 1287655),
  266. // but only if the contents has changed (bug 1337392).
  267. if (txtCtrl->ValueChanged()) {
  268. nsAutoString val;
  269. txtCtrl->GetTextEditorValue(val, true);
  270. position = val.Length();
  271. }
  272. SetSelectionEndPoints(position, position);
  273. }
  274. }
  275. NS_ENSURE_STATE(weakFrame.IsAlive());
  276. return NS_OK;
  277. }
  278. nsresult
  279. nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
  280. {
  281. NS_ASSERTION(mContent, "We should have a content!");
  282. mState |= NS_FRAME_INDEPENDENT_SELECTION;
  283. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  284. NS_ASSERTION(txtCtrl, "Content not a text control element");
  285. // Bind the frame to its text control
  286. nsresult rv = txtCtrl->BindToFrame(this);
  287. NS_ENSURE_SUCCESS(rv, rv);
  288. nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  289. NS_ENSURE_TRUE(rootNode, NS_ERROR_OUT_OF_MEMORY);
  290. if (!aElements.AppendElement(rootNode))
  291. return NS_ERROR_OUT_OF_MEMORY;
  292. // Do we need a placeholder node?
  293. nsAutoString placeholderTxt;
  294. mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::placeholder,
  295. placeholderTxt);
  296. nsContentUtils::RemoveNewlines(placeholderTxt);
  297. mUsePlaceholder = !placeholderTxt.IsEmpty();
  298. // Create the placeholder anonymous content if needed.
  299. if (mUsePlaceholder) {
  300. Element* placeholderNode = txtCtrl->CreatePlaceholderNode();
  301. NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY);
  302. // Associate ::placeholder pseudo-element with the placeholder node.
  303. placeholderNode->SetPseudoElementType(CSSPseudoElementType::placeholder);
  304. aElements.AppendElement(placeholderNode);
  305. if (!IsSingleLineTextControl()) {
  306. // For textareas, UpdateValueDisplay doesn't initialize the visibility
  307. // status of the placeholder because it returns early, so we have to
  308. // do that manually here.
  309. txtCtrl->UpdatePlaceholderVisibility(true);
  310. }
  311. }
  312. rv = UpdateValueDisplay(false);
  313. NS_ENSURE_SUCCESS(rv, rv);
  314. // textareas are eagerly initialized
  315. bool initEagerly = !IsSingleLineTextControl();
  316. if (!initEagerly) {
  317. // Also, input elements which have a cached selection should get eager
  318. // editor initialization.
  319. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  320. NS_ASSERTION(txtCtrl, "Content not a text control element");
  321. initEagerly = txtCtrl->HasCachedSelection();
  322. }
  323. if (!initEagerly) {
  324. nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(txtCtrl);
  325. if (element) {
  326. // so are input text controls with spellcheck=true
  327. element->GetSpellcheck(&initEagerly);
  328. }
  329. }
  330. if (initEagerly) {
  331. NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
  332. "Someone forgot a script blocker?");
  333. EditorInitializer* initializer = GetProperty(TextControlInitializer());
  334. if (initializer) {
  335. initializer->Revoke();
  336. }
  337. initializer = new EditorInitializer(this);
  338. SetProperty(TextControlInitializer(),initializer);
  339. nsContentUtils::AddScriptRunner(initializer);
  340. }
  341. return NS_OK;
  342. }
  343. void
  344. nsTextControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
  345. uint32_t aFilter)
  346. {
  347. // This can be called off-main-thread during Servo traversal, so we take care
  348. // to avoid QI-ing the DOM node.
  349. nsITextControlElement* txtCtrl = nullptr;
  350. nsIContent* content = GetContent();
  351. if (content->IsHTMLElement(nsGkAtoms::input)) {
  352. txtCtrl = static_cast<HTMLInputElement*>(content);
  353. } else if (content->IsHTMLElement(nsGkAtoms::textarea)) {
  354. txtCtrl = static_cast<HTMLTextAreaElement*>(content);
  355. } else {
  356. MOZ_CRASH("Unexpected content type for nsTextControlFrame");
  357. }
  358. nsIContent* root = txtCtrl->GetRootEditorNode();
  359. if (root) {
  360. aElements.AppendElement(root);
  361. }
  362. nsIContent* placeholder = txtCtrl->GetPlaceholderNode();
  363. if (placeholder && !(aFilter & nsIContent::eSkipPlaceholderContent))
  364. aElements.AppendElement(placeholder);
  365. }
  366. nscoord
  367. nsTextControlFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
  368. {
  369. nscoord result = 0;
  370. DISPLAY_PREF_WIDTH(this, result);
  371. float inflation = nsLayoutUtils::FontSizeInflationFor(this);
  372. WritingMode wm = GetWritingMode();
  373. result = CalcIntrinsicSize(aRenderingContext, wm, inflation).ISize(wm);
  374. return result;
  375. }
  376. nscoord
  377. nsTextControlFrame::GetMinISize(nsRenderingContext* aRenderingContext)
  378. {
  379. // Our min width is just our preferred width if we have auto width.
  380. nscoord result;
  381. DISPLAY_MIN_WIDTH(this, result);
  382. result = GetPrefISize(aRenderingContext);
  383. return result;
  384. }
  385. LogicalSize
  386. nsTextControlFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
  387. WritingMode aWM,
  388. const LogicalSize& aCBSize,
  389. nscoord aAvailableISize,
  390. const LogicalSize& aMargin,
  391. const LogicalSize& aBorder,
  392. const LogicalSize& aPadding,
  393. ComputeSizeFlags aFlags)
  394. {
  395. float inflation = nsLayoutUtils::FontSizeInflationFor(this);
  396. LogicalSize autoSize = CalcIntrinsicSize(aRenderingContext, aWM, inflation);
  397. // Note: nsContainerFrame::ComputeAutoSize only computes the inline-size (and
  398. // only for 'auto'), the block-size it returns is always NS_UNCONSTRAINEDSIZE.
  399. const nsStyleCoord& iSizeCoord = StylePosition()->ISize(aWM);
  400. if (iSizeCoord.GetUnit() == eStyleUnit_Auto) {
  401. if (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) {
  402. // CalcIntrinsicSize isn't aware of grid-item margin-box clamping, so we
  403. // fall back to nsContainerFrame's ComputeAutoSize to handle that.
  404. // XXX maybe a font-inflation issue here? (per the assertion below).
  405. autoSize.ISize(aWM) =
  406. nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM,
  407. aCBSize, aAvailableISize,
  408. aMargin, aBorder,
  409. aPadding, aFlags).ISize(aWM);
  410. }
  411. #ifdef DEBUG
  412. else {
  413. LogicalSize ancestorAutoSize =
  414. nsContainerFrame::ComputeAutoSize(aRenderingContext, aWM,
  415. aCBSize, aAvailableISize,
  416. aMargin, aBorder,
  417. aPadding, aFlags);
  418. // Disabled when there's inflation; see comment in GetXULPrefSize.
  419. MOZ_ASSERT(inflation != 1.0f ||
  420. ancestorAutoSize.ISize(aWM) == autoSize.ISize(aWM),
  421. "Incorrect size computed by ComputeAutoSize?");
  422. }
  423. #endif
  424. }
  425. return autoSize;
  426. }
  427. void
  428. nsTextControlFrame::Reflow(nsPresContext* aPresContext,
  429. ReflowOutput& aDesiredSize,
  430. const ReflowInput& aReflowInput,
  431. nsReflowStatus& aStatus)
  432. {
  433. MarkInReflow();
  434. DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
  435. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  436. // make sure that the form registers itself on the initial/first reflow
  437. if (mState & NS_FRAME_FIRST_REFLOW) {
  438. nsFormControlFrame::RegUnRegAccessKey(this, true);
  439. }
  440. // set values of reflow's out parameters
  441. WritingMode wm = aReflowInput.GetWritingMode();
  442. LogicalSize
  443. finalSize(wm,
  444. aReflowInput.ComputedISize() +
  445. aReflowInput.ComputedLogicalBorderPadding().IStartEnd(wm),
  446. aReflowInput.ComputedBSize() +
  447. aReflowInput.ComputedLogicalBorderPadding().BStartEnd(wm));
  448. aDesiredSize.SetSize(wm, finalSize);
  449. // Calculate the baseline and store it in mFirstBaseline.
  450. nscoord lineHeight = aReflowInput.ComputedBSize();
  451. float inflation = nsLayoutUtils::FontSizeInflationFor(this);
  452. if (!IsSingleLineTextControl()) {
  453. lineHeight = ReflowInput::CalcLineHeight(GetContent(), StyleContext(),
  454. NS_AUTOHEIGHT, inflation);
  455. }
  456. RefPtr<nsFontMetrics> fontMet =
  457. nsLayoutUtils::GetFontMetricsForFrame(this, inflation);
  458. mFirstBaseline =
  459. nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight,
  460. wm.IsLineInverted()) +
  461. aReflowInput.ComputedLogicalBorderPadding().BStart(wm);
  462. aDesiredSize.SetBlockStartAscent(mFirstBaseline);
  463. // overflow handling
  464. aDesiredSize.SetOverflowAreasToDesiredBounds();
  465. // perform reflow on all kids
  466. nsIFrame* kid = mFrames.FirstChild();
  467. while (kid) {
  468. ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus, aDesiredSize);
  469. kid = kid->GetNextSibling();
  470. }
  471. // take into account css properties that affect overflow handling
  472. FinishAndStoreOverflow(&aDesiredSize);
  473. aStatus = NS_FRAME_COMPLETE;
  474. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  475. }
  476. void
  477. nsTextControlFrame::ReflowTextControlChild(nsIFrame* aKid,
  478. nsPresContext* aPresContext,
  479. const ReflowInput& aReflowInput,
  480. nsReflowStatus& aStatus,
  481. ReflowOutput& aParentDesiredSize)
  482. {
  483. // compute available size and frame offsets for child
  484. WritingMode wm = aKid->GetWritingMode();
  485. LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm);
  486. availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
  487. ReflowInput kidReflowInput(aPresContext, aReflowInput,
  488. aKid, availSize, nullptr,
  489. ReflowInput::CALLER_WILL_INIT);
  490. // Override padding with our computed padding in case we got it from theming or percentage
  491. kidReflowInput.Init(aPresContext, nullptr, nullptr, &aReflowInput.ComputedPhysicalPadding());
  492. // Set computed width and computed height for the child
  493. kidReflowInput.SetComputedWidth(aReflowInput.ComputedWidth());
  494. kidReflowInput.SetComputedHeight(aReflowInput.ComputedHeight());
  495. // Offset the frame by the size of the parent's border
  496. nscoord xOffset = aReflowInput.ComputedPhysicalBorderPadding().left -
  497. aReflowInput.ComputedPhysicalPadding().left;
  498. nscoord yOffset = aReflowInput.ComputedPhysicalBorderPadding().top -
  499. aReflowInput.ComputedPhysicalPadding().top;
  500. // reflow the child
  501. ReflowOutput desiredSize(aReflowInput);
  502. ReflowChild(aKid, aPresContext, desiredSize, kidReflowInput,
  503. xOffset, yOffset, 0, aStatus);
  504. // place the child
  505. FinishReflowChild(aKid, aPresContext, desiredSize,
  506. &kidReflowInput, xOffset, yOffset, 0);
  507. // consider the overflow
  508. aParentDesiredSize.mOverflowAreas.UnionWith(desiredSize.mOverflowAreas);
  509. }
  510. nsSize
  511. nsTextControlFrame::GetXULMinSize(nsBoxLayoutState& aState)
  512. {
  513. // XXXbz why? Why not the nsBoxFrame sizes?
  514. return nsBox::GetXULMinSize(aState);
  515. }
  516. bool
  517. nsTextControlFrame::IsXULCollapsed()
  518. {
  519. // We're never collapsed in the box sense.
  520. return false;
  521. }
  522. bool
  523. nsTextControlFrame::IsLeaf() const
  524. {
  525. return true;
  526. }
  527. NS_IMETHODIMP
  528. nsTextControlFrame::ScrollOnFocusEvent::Run()
  529. {
  530. if (mFrame) {
  531. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(mFrame->GetContent());
  532. NS_ASSERTION(txtCtrl, "Content not a text control element");
  533. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  534. if (selCon) {
  535. mFrame->mScrollEvent.Forget();
  536. selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
  537. nsISelectionController::SELECTION_FOCUS_REGION,
  538. nsISelectionController::SCROLL_SYNCHRONOUS);
  539. }
  540. }
  541. return NS_OK;
  542. }
  543. //IMPLEMENTING NS_IFORMCONTROLFRAME
  544. void nsTextControlFrame::SetFocus(bool aOn, bool aRepaint)
  545. {
  546. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  547. NS_ASSERTION(txtCtrl, "Content not a text control element");
  548. // Revoke the previous scroll event if one exists
  549. mScrollEvent.Revoke();
  550. // If 'dom.placeholeder.show_on_focus' preference is 'false', focusing or
  551. // blurring the frame can have an impact on the placeholder visibility.
  552. if (mUsePlaceholder) {
  553. txtCtrl->UpdatePlaceholderVisibility(true);
  554. }
  555. if (!aOn) {
  556. return;
  557. }
  558. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  559. if (!selCon)
  560. return;
  561. nsCOMPtr<nsISelection> ourSel;
  562. selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  563. getter_AddRefs(ourSel));
  564. if (!ourSel) return;
  565. nsIPresShell* presShell = PresContext()->GetPresShell();
  566. RefPtr<nsCaret> caret = presShell->GetCaret();
  567. if (!caret) return;
  568. // Scroll the current selection into view
  569. nsISelection *caretSelection = caret->GetSelection();
  570. const bool isFocusedRightNow = ourSel == caretSelection;
  571. if (!isFocusedRightNow) {
  572. // Don't scroll the current selection if we've been focused using the mouse.
  573. uint32_t lastFocusMethod = 0;
  574. nsIDocument* doc = GetContent()->GetComposedDoc();
  575. if (doc) {
  576. nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  577. if (fm) {
  578. fm->GetLastFocusMethod(doc->GetWindow(), &lastFocusMethod);
  579. }
  580. }
  581. if (!(lastFocusMethod & nsIFocusManager::FLAG_BYMOUSE)) {
  582. RefPtr<ScrollOnFocusEvent> event = new ScrollOnFocusEvent(this);
  583. nsresult rv = NS_DispatchToCurrentThread(event);
  584. if (NS_SUCCEEDED(rv)) {
  585. mScrollEvent = event;
  586. }
  587. }
  588. }
  589. // tell the caret to use our selection
  590. caret->SetSelection(ourSel);
  591. // mutual-exclusion: the selection is either controlled by the
  592. // document or by the text input/area. Clear any selection in the
  593. // document since the focus is now on our independent selection.
  594. nsCOMPtr<nsISelectionController> selcon = do_QueryInterface(presShell);
  595. nsCOMPtr<nsISelection> docSel;
  596. selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
  597. getter_AddRefs(docSel));
  598. if (!docSel) return;
  599. bool isCollapsed = false;
  600. docSel->GetIsCollapsed(&isCollapsed);
  601. if (!isCollapsed)
  602. docSel->RemoveAllRanges();
  603. }
  604. nsresult nsTextControlFrame::SetFormProperty(nsIAtom* aName, const nsAString& aValue)
  605. {
  606. if (!mIsProcessing)//some kind of lock.
  607. {
  608. mIsProcessing = true;
  609. if (nsGkAtoms::select == aName)
  610. {
  611. // Select all the text.
  612. //
  613. // XXX: This is lame, we can't call editor's SelectAll method
  614. // because that triggers AutoCopies in unix builds.
  615. // Instead, we have to call our own homegrown version
  616. // of select all which merely builds a range that selects
  617. // all of the content and adds that to the selection.
  618. nsWeakFrame weakThis = this;
  619. SelectAllOrCollapseToEndOfText(true); // NOTE: can destroy the world
  620. if (!weakThis.IsAlive()) {
  621. return NS_OK;
  622. }
  623. }
  624. mIsProcessing = false;
  625. }
  626. return NS_OK;
  627. }
  628. NS_IMETHODIMP
  629. nsTextControlFrame::GetEditor(nsIEditor **aEditor)
  630. {
  631. NS_ENSURE_ARG_POINTER(aEditor);
  632. nsresult rv = EnsureEditorInitialized();
  633. NS_ENSURE_SUCCESS(rv, rv);
  634. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  635. NS_ASSERTION(txtCtrl, "Content not a text control element");
  636. *aEditor = txtCtrl->GetTextEditor();
  637. NS_IF_ADDREF(*aEditor);
  638. return NS_OK;
  639. }
  640. nsresult
  641. nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode,
  642. int32_t aStartOffset,
  643. nsIDOMNode *aEndNode,
  644. int32_t aEndOffset,
  645. nsITextControlFrame::SelectionDirection aDirection)
  646. {
  647. // Create a new range to represent the new selection.
  648. // Note that we use a new range to avoid having to do
  649. // isIncreasing checks to avoid possible errors.
  650. RefPtr<nsRange> range = new nsRange(mContent);
  651. // Be careful to use internal nsRange methods which do not check to make sure
  652. // we have access to the node.
  653. nsCOMPtr<nsINode> start = do_QueryInterface(aStartNode);
  654. nsCOMPtr<nsINode> end = do_QueryInterface(aEndNode);
  655. // XXXbz nsRange::SetStartAndEnd takes int32_t (and ranges generally work on
  656. // int32_t), but we're passing uint32_t. The good news is that at this point
  657. // our endpoints should really be within our length, so not really that big.
  658. // And if they _are_ that big, SetStartAndEnd() will simply error out, which
  659. // is not too bad for a case we don't expect to happen.
  660. nsresult rv = range->SetStartAndEnd(start, aStartOffset, end, aEndOffset);
  661. NS_ENSURE_SUCCESS(rv, rv);
  662. // Get the selection, clear it and add the new range to it!
  663. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  664. NS_ASSERTION(txtCtrl, "Content not a text control element");
  665. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  666. NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
  667. nsCOMPtr<nsISelection> selection;
  668. selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
  669. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  670. nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection, &rv);
  671. NS_ENSURE_SUCCESS(rv, rv);
  672. nsDirection direction;
  673. if (aDirection == eNone) {
  674. // Preserve the direction
  675. direction = selPriv->GetSelectionDirection();
  676. } else {
  677. direction = (aDirection == eBackward) ? eDirPrevious : eDirNext;
  678. }
  679. rv = selection->RemoveAllRanges();
  680. NS_ENSURE_SUCCESS(rv, rv);
  681. rv = selection->AddRange(range); // NOTE: can destroy the world
  682. NS_ENSURE_SUCCESS(rv, rv);
  683. selPriv->SetSelectionDirection(direction);
  684. return rv;
  685. }
  686. nsresult
  687. nsTextControlFrame::ScrollSelectionIntoView()
  688. {
  689. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  690. NS_ASSERTION(txtCtrl, "Content not a text control element");
  691. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  692. if (selCon) {
  693. // Scroll the selection into view (see bug 231389).
  694. return selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL,
  695. nsISelectionController::SELECTION_FOCUS_REGION,
  696. nsISelectionController::SCROLL_FIRST_ANCESTOR_ONLY);
  697. }
  698. return NS_ERROR_FAILURE;
  699. }
  700. mozilla::dom::Element*
  701. nsTextControlFrame::GetRootNodeAndInitializeEditor()
  702. {
  703. nsCOMPtr<nsIDOMElement> root;
  704. GetRootNodeAndInitializeEditor(getter_AddRefs(root));
  705. nsCOMPtr<mozilla::dom::Element> rootElem = do_QueryInterface(root);
  706. return rootElem;
  707. }
  708. nsresult
  709. nsTextControlFrame::GetRootNodeAndInitializeEditor(nsIDOMElement **aRootElement)
  710. {
  711. NS_ENSURE_ARG_POINTER(aRootElement);
  712. nsCOMPtr<nsIEditor> editor;
  713. GetEditor(getter_AddRefs(editor));
  714. if (!editor)
  715. return NS_OK;
  716. return editor->GetRootElement(aRootElement);
  717. }
  718. nsresult
  719. nsTextControlFrame::SelectAllOrCollapseToEndOfText(bool aSelect)
  720. {
  721. nsCOMPtr<nsIDOMElement> rootElement;
  722. nsresult rv = GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement));
  723. NS_ENSURE_SUCCESS(rv, rv);
  724. nsCOMPtr<nsIContent> rootContent = do_QueryInterface(rootElement);
  725. nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
  726. NS_ENSURE_TRUE(rootNode && rootContent, NS_ERROR_FAILURE);
  727. int32_t numChildren = rootContent->GetChildCount();
  728. if (numChildren > 0) {
  729. // We never want to place the selection after the last
  730. // br under the root node!
  731. nsIContent *child = rootContent->GetChildAt(numChildren - 1);
  732. if (child) {
  733. if (child->IsHTMLElement(nsGkAtoms::br))
  734. --numChildren;
  735. }
  736. if (!aSelect && numChildren) {
  737. child = rootContent->GetChildAt(numChildren - 1);
  738. if (child && child->IsNodeOfType(nsINode::eTEXT)) {
  739. rootNode = do_QueryInterface(child);
  740. const nsTextFragment* fragment = child->GetText();
  741. numChildren = fragment ? fragment->GetLength() : 0;
  742. }
  743. }
  744. }
  745. rv = SetSelectionInternal(rootNode, aSelect ? 0 : numChildren,
  746. rootNode, numChildren);
  747. NS_ENSURE_SUCCESS(rv, rv);
  748. return ScrollSelectionIntoView();
  749. }
  750. nsresult
  751. nsTextControlFrame::SetSelectionEndPoints(int32_t aSelStart, int32_t aSelEnd,
  752. nsITextControlFrame::SelectionDirection aDirection)
  753. {
  754. NS_ASSERTION(aSelStart <= aSelEnd, "Invalid selection offsets!");
  755. if (aSelStart > aSelEnd)
  756. return NS_ERROR_FAILURE;
  757. nsCOMPtr<nsIDOMNode> startNode, endNode;
  758. int32_t startOffset, endOffset;
  759. // Calculate the selection start point.
  760. nsresult rv = OffsetToDOMPoint(aSelStart, getter_AddRefs(startNode), &startOffset);
  761. NS_ENSURE_SUCCESS(rv, rv);
  762. if (aSelStart == aSelEnd) {
  763. // Collapsed selection, so start and end are the same!
  764. endNode = startNode;
  765. endOffset = startOffset;
  766. }
  767. else {
  768. // Selection isn't collapsed so we have to calculate
  769. // the end point too.
  770. rv = OffsetToDOMPoint(aSelEnd, getter_AddRefs(endNode), &endOffset);
  771. NS_ENSURE_SUCCESS(rv, rv);
  772. }
  773. return SetSelectionInternal(startNode, startOffset, endNode, endOffset, aDirection);
  774. }
  775. NS_IMETHODIMP
  776. nsTextControlFrame::SetSelectionRange(int32_t aSelStart, int32_t aSelEnd,
  777. nsITextControlFrame::SelectionDirection aDirection)
  778. {
  779. nsresult rv = EnsureEditorInitialized();
  780. NS_ENSURE_SUCCESS(rv, rv);
  781. if (aSelStart > aSelEnd) {
  782. // Simulate what we'd see SetSelectionStart() was called, followed
  783. // by a SetSelectionEnd().
  784. aSelStart = aSelEnd;
  785. }
  786. return SetSelectionEndPoints(aSelStart, aSelEnd, aDirection);
  787. }
  788. NS_IMETHODIMP
  789. nsTextControlFrame::SetSelectionStart(int32_t aSelectionStart)
  790. {
  791. nsresult rv = EnsureEditorInitialized();
  792. NS_ENSURE_SUCCESS(rv, rv);
  793. int32_t selStart = 0, selEnd = 0;
  794. rv = GetSelectionRange(&selStart, &selEnd);
  795. NS_ENSURE_SUCCESS(rv, rv);
  796. if (aSelectionStart > selEnd) {
  797. // Collapse to the new start point.
  798. selEnd = aSelectionStart;
  799. }
  800. selStart = aSelectionStart;
  801. return SetSelectionEndPoints(selStart, selEnd);
  802. }
  803. NS_IMETHODIMP
  804. nsTextControlFrame::SetSelectionEnd(int32_t aSelectionEnd)
  805. {
  806. nsresult rv = EnsureEditorInitialized();
  807. NS_ENSURE_SUCCESS(rv, rv);
  808. int32_t selStart = 0, selEnd = 0;
  809. rv = GetSelectionRange(&selStart, &selEnd);
  810. NS_ENSURE_SUCCESS(rv, rv);
  811. if (aSelectionEnd < selStart) {
  812. // Collapse to the new end point.
  813. selStart = aSelectionEnd;
  814. }
  815. selEnd = aSelectionEnd;
  816. return SetSelectionEndPoints(selStart, selEnd);
  817. }
  818. nsresult
  819. nsTextControlFrame::OffsetToDOMPoint(int32_t aOffset,
  820. nsIDOMNode** aResult,
  821. int32_t* aPosition)
  822. {
  823. NS_ENSURE_ARG_POINTER(aResult && aPosition);
  824. *aResult = nullptr;
  825. *aPosition = 0;
  826. nsCOMPtr<nsIDOMElement> rootElement;
  827. nsresult rv = GetRootNodeAndInitializeEditor(getter_AddRefs(rootElement));
  828. NS_ENSURE_SUCCESS(rv, rv);
  829. nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
  830. NS_ENSURE_TRUE(rootNode, NS_ERROR_FAILURE);
  831. nsCOMPtr<nsIDOMNodeList> nodeList;
  832. rv = rootNode->GetChildNodes(getter_AddRefs(nodeList));
  833. NS_ENSURE_SUCCESS(rv, rv);
  834. NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
  835. uint32_t length = 0;
  836. rv = nodeList->GetLength(&length);
  837. NS_ENSURE_SUCCESS(rv, rv);
  838. NS_ASSERTION(length <= 2, "We should have one text node and one mozBR at most");
  839. nsCOMPtr<nsIDOMNode> firstNode;
  840. rv = nodeList->Item(0, getter_AddRefs(firstNode));
  841. NS_ENSURE_SUCCESS(rv, rv);
  842. nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(firstNode);
  843. if (length == 0 || aOffset < 0) {
  844. NS_IF_ADDREF(*aResult = rootNode);
  845. *aPosition = 0;
  846. } else if (textNode) {
  847. uint32_t textLength = 0;
  848. textNode->GetLength(&textLength);
  849. if (length == 2 && uint32_t(aOffset) == textLength) {
  850. // If we're at the end of the text node and we have a trailing BR node,
  851. // set the selection on the BR node.
  852. NS_IF_ADDREF(*aResult = rootNode);
  853. *aPosition = 1;
  854. } else {
  855. // Otherwise, set the selection on the textnode itself.
  856. NS_IF_ADDREF(*aResult = firstNode);
  857. *aPosition = std::min(aOffset, int32_t(textLength));
  858. }
  859. } else {
  860. NS_IF_ADDREF(*aResult = rootNode);
  861. *aPosition = 0;
  862. }
  863. return NS_OK;
  864. }
  865. NS_IMETHODIMP
  866. nsTextControlFrame::GetSelectionRange(int32_t* aSelectionStart,
  867. int32_t* aSelectionEnd,
  868. SelectionDirection* aDirection)
  869. {
  870. // make sure we have an editor
  871. nsresult rv = EnsureEditorInitialized();
  872. NS_ENSURE_SUCCESS(rv, rv);
  873. if (aSelectionStart) {
  874. *aSelectionStart = 0;
  875. }
  876. if (aSelectionEnd) {
  877. *aSelectionEnd = 0;
  878. }
  879. if (aDirection) {
  880. *aDirection = eNone;
  881. }
  882. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  883. NS_ASSERTION(txtCtrl, "Content not a text control element");
  884. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  885. NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
  886. nsCOMPtr<nsISelection> selection;
  887. rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
  888. NS_ENSURE_SUCCESS(rv, rv);
  889. NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
  890. dom::Selection* sel = selection->AsSelection();
  891. if (aDirection) {
  892. nsDirection direction = sel->GetSelectionDirection();
  893. if (direction == eDirNext) {
  894. *aDirection = eForward;
  895. } else if (direction == eDirPrevious) {
  896. *aDirection = eBackward;
  897. } else {
  898. NS_NOTREACHED("Invalid nsDirection enum value");
  899. }
  900. }
  901. if (!aSelectionStart || !aSelectionEnd) {
  902. return NS_OK;
  903. }
  904. mozilla::dom::Element* root = GetRootNodeAndInitializeEditor();
  905. NS_ENSURE_STATE(root);
  906. nsContentUtils::GetSelectionInTextControl(sel, root,
  907. *aSelectionStart, *aSelectionEnd);
  908. return NS_OK;
  909. }
  910. /////END INTERFACE IMPLEMENTATIONS
  911. ////NSIFRAME
  912. nsresult
  913. nsTextControlFrame::AttributeChanged(int32_t aNameSpaceID,
  914. nsIAtom* aAttribute,
  915. int32_t aModType)
  916. {
  917. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  918. NS_ASSERTION(txtCtrl, "Content not a text control element");
  919. nsISelectionController* selCon = txtCtrl->GetSelectionController();
  920. const bool needEditor = nsGkAtoms::maxlength == aAttribute ||
  921. nsGkAtoms::readonly == aAttribute ||
  922. nsGkAtoms::disabled == aAttribute ||
  923. nsGkAtoms::spellcheck == aAttribute;
  924. nsCOMPtr<nsIEditor> editor;
  925. if (needEditor) {
  926. GetEditor(getter_AddRefs(editor));
  927. }
  928. if ((needEditor && !editor) || !selCon) {
  929. return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
  930. }
  931. if (nsGkAtoms::maxlength == aAttribute) {
  932. int32_t maxLength;
  933. bool maxDefined = GetMaxLength(&maxLength);
  934. nsCOMPtr<nsIPlaintextEditor> textEditor = do_QueryInterface(editor);
  935. if (textEditor) {
  936. if (maxDefined) { // set the maxLength attribute
  937. textEditor->SetMaxTextLength(maxLength);
  938. // if maxLength>docLength, we need to truncate the doc content
  939. } else { // unset the maxLength attribute
  940. textEditor->SetMaxTextLength(-1);
  941. }
  942. }
  943. return NS_OK;
  944. }
  945. if (nsGkAtoms::readonly == aAttribute) {
  946. uint32_t flags;
  947. editor->GetFlags(&flags);
  948. if (AttributeExists(nsGkAtoms::readonly)) { // set readonly
  949. flags |= nsIPlaintextEditor::eEditorReadonlyMask;
  950. if (nsContentUtils::IsFocusedContent(mContent)) {
  951. selCon->SetCaretEnabled(false);
  952. }
  953. } else { // unset readonly
  954. flags &= ~(nsIPlaintextEditor::eEditorReadonlyMask);
  955. if (!(flags & nsIPlaintextEditor::eEditorDisabledMask) &&
  956. nsContentUtils::IsFocusedContent(mContent)) {
  957. selCon->SetCaretEnabled(true);
  958. }
  959. }
  960. editor->SetFlags(flags);
  961. return NS_OK;
  962. }
  963. if (nsGkAtoms::disabled == aAttribute) {
  964. uint32_t flags;
  965. editor->GetFlags(&flags);
  966. int16_t displaySelection = nsISelectionController::SELECTION_OFF;
  967. const bool focused = nsContentUtils::IsFocusedContent(mContent);
  968. const bool hasAttr = AttributeExists(nsGkAtoms::disabled);
  969. if (hasAttr) { // set disabled
  970. flags |= nsIPlaintextEditor::eEditorDisabledMask;
  971. } else { // unset disabled
  972. flags &= ~(nsIPlaintextEditor::eEditorDisabledMask);
  973. displaySelection = focused ? nsISelectionController::SELECTION_ON
  974. : nsISelectionController::SELECTION_HIDDEN;
  975. }
  976. selCon->SetDisplaySelection(displaySelection);
  977. if (focused) {
  978. selCon->SetCaretEnabled(!hasAttr);
  979. }
  980. editor->SetFlags(flags);
  981. return NS_OK;
  982. }
  983. if (!mEditorHasBeenInitialized && nsGkAtoms::value == aAttribute) {
  984. UpdateValueDisplay(true);
  985. return NS_OK;
  986. }
  987. // Allow the base class to handle common attributes supported by all form
  988. // elements...
  989. return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
  990. }
  991. nsresult
  992. nsTextControlFrame::GetText(nsString& aText)
  993. {
  994. nsresult rv = NS_OK;
  995. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  996. NS_ASSERTION(txtCtrl, "Content not a text control element");
  997. if (IsSingleLineTextControl()) {
  998. // There will be no line breaks so we can ignore the wrap property.
  999. txtCtrl->GetTextEditorValue(aText, true);
  1000. } else {
  1001. nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(mContent);
  1002. if (textArea) {
  1003. rv = textArea->GetValue(aText);
  1004. }
  1005. }
  1006. return rv;
  1007. }
  1008. nsresult
  1009. nsTextControlFrame::GetPhonetic(nsAString& aPhonetic)
  1010. {
  1011. aPhonetic.Truncate(0);
  1012. nsCOMPtr<nsIEditor> editor;
  1013. nsresult rv = GetEditor(getter_AddRefs(editor));
  1014. NS_ENSURE_SUCCESS(rv, rv);
  1015. nsCOMPtr<nsIEditorIMESupport> imeSupport = do_QueryInterface(editor);
  1016. if (imeSupport) {
  1017. nsCOMPtr<nsIPhonetic> phonetic = do_QueryInterface(imeSupport);
  1018. if (phonetic)
  1019. phonetic->GetPhonetic(aPhonetic);
  1020. }
  1021. return NS_OK;
  1022. }
  1023. ///END NSIFRAME OVERLOADS
  1024. /////BEGIN PROTECTED METHODS
  1025. bool
  1026. nsTextControlFrame::GetMaxLength(int32_t* aSize)
  1027. {
  1028. *aSize = -1;
  1029. nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
  1030. if (content) {
  1031. const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::maxlength);
  1032. if (attr && attr->Type() == nsAttrValue::eInteger) {
  1033. *aSize = attr->GetIntegerValue();
  1034. return true;
  1035. }
  1036. }
  1037. return false;
  1038. }
  1039. // END IMPLEMENTING NS_IFORMCONTROLFRAME
  1040. void
  1041. nsTextControlFrame::SetInitialChildList(ChildListID aListID,
  1042. nsFrameList& aChildList)
  1043. {
  1044. nsContainerFrame::SetInitialChildList(aListID, aChildList);
  1045. if (aListID != kPrincipalList) {
  1046. return;
  1047. }
  1048. // Mark the scroll frame as being a reflow root. This will allow
  1049. // incremental reflows to be initiated at the scroll frame, rather
  1050. // than descending from the root frame of the frame hierarchy.
  1051. if (nsIFrame* first = PrincipalChildList().FirstChild()) {
  1052. first->AddStateBits(NS_FRAME_REFLOW_ROOT);
  1053. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1054. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1055. txtCtrl->InitializeKeyboardEventListeners();
  1056. nsPoint* contentScrollPos = GetProperty(ContentScrollPos());
  1057. if (contentScrollPos) {
  1058. // If we have a scroll pos stored to be passed to our anonymous
  1059. // div, do it here!
  1060. nsIStatefulFrame* statefulFrame = do_QueryFrame(first);
  1061. NS_ASSERTION(statefulFrame, "unexpected type of frame for the anonymous div");
  1062. nsPresState fakePresState;
  1063. fakePresState.SetScrollState(*contentScrollPos);
  1064. statefulFrame->RestoreState(&fakePresState);
  1065. RemoveProperty(ContentScrollPos());
  1066. delete contentScrollPos;
  1067. }
  1068. }
  1069. }
  1070. void
  1071. nsTextControlFrame::SetValueChanged(bool aValueChanged)
  1072. {
  1073. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1074. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1075. if (mUsePlaceholder) {
  1076. nsWeakFrame weakFrame(this);
  1077. txtCtrl->UpdatePlaceholderVisibility(true);
  1078. if (!weakFrame.IsAlive()) {
  1079. return;
  1080. }
  1081. }
  1082. txtCtrl->SetValueChanged(aValueChanged);
  1083. }
  1084. nsresult
  1085. nsTextControlFrame::UpdateValueDisplay(bool aNotify,
  1086. bool aBeforeEditorInit,
  1087. const nsAString *aValue)
  1088. {
  1089. if (!IsSingleLineTextControl()) // textareas don't use this
  1090. return NS_OK;
  1091. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1092. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1093. nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1094. NS_PRECONDITION(rootNode, "Must have a div content\n");
  1095. NS_PRECONDITION(!mEditorHasBeenInitialized,
  1096. "Do not call this after editor has been initialized");
  1097. NS_ASSERTION(!mUsePlaceholder || txtCtrl->GetPlaceholderNode(),
  1098. "A placeholder div must exist");
  1099. nsIContent *textContent = rootNode->GetChildAt(0);
  1100. if (!textContent) {
  1101. // Set up a textnode with our value
  1102. RefPtr<nsTextNode> textNode =
  1103. new nsTextNode(mContent->NodeInfo()->NodeInfoManager());
  1104. NS_ASSERTION(textNode, "Must have textcontent!\n");
  1105. rootNode->AppendChildTo(textNode, aNotify);
  1106. textContent = textNode;
  1107. }
  1108. NS_ENSURE_TRUE(textContent, NS_ERROR_UNEXPECTED);
  1109. // Get the current value of the textfield from the content.
  1110. nsAutoString value;
  1111. if (aValue) {
  1112. value = *aValue;
  1113. } else {
  1114. txtCtrl->GetTextEditorValue(value, true);
  1115. }
  1116. // Update the display of the placeholder value if needed.
  1117. // We don't need to do this if we're about to initialize the
  1118. // editor, since EnsureEditorInitialized takes care of this.
  1119. if (mUsePlaceholder && !aBeforeEditorInit)
  1120. {
  1121. nsWeakFrame weakFrame(this);
  1122. txtCtrl->UpdatePlaceholderVisibility(aNotify);
  1123. NS_ENSURE_STATE(weakFrame.IsAlive());
  1124. }
  1125. if (aBeforeEditorInit && value.IsEmpty()) {
  1126. rootNode->RemoveChildAt(0, true);
  1127. return NS_OK;
  1128. }
  1129. if (!value.IsEmpty() && IsPasswordTextControl()) {
  1130. TextEditRules::FillBufWithPWChars(&value, value.Length());
  1131. }
  1132. return textContent->SetText(value, aNotify);
  1133. }
  1134. NS_IMETHODIMP
  1135. nsTextControlFrame::GetOwnedSelectionController(nsISelectionController** aSelCon)
  1136. {
  1137. NS_ENSURE_ARG_POINTER(aSelCon);
  1138. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1139. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1140. *aSelCon = txtCtrl->GetSelectionController();
  1141. NS_IF_ADDREF(*aSelCon);
  1142. return NS_OK;
  1143. }
  1144. nsFrameSelection*
  1145. nsTextControlFrame::GetOwnedFrameSelection()
  1146. {
  1147. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1148. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1149. return txtCtrl->GetConstFrameSelection();
  1150. }
  1151. NS_IMETHODIMP
  1152. nsTextControlFrame::SaveState(nsPresState** aState)
  1153. {
  1154. NS_ENSURE_ARG_POINTER(aState);
  1155. *aState = nullptr;
  1156. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1157. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1158. nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1159. if (rootNode) {
  1160. // Query the nsIStatefulFrame from the HTMLScrollFrame
  1161. nsIStatefulFrame* scrollStateFrame = do_QueryFrame(rootNode->GetPrimaryFrame());
  1162. if (scrollStateFrame) {
  1163. return scrollStateFrame->SaveState(aState);
  1164. }
  1165. }
  1166. return NS_OK;
  1167. }
  1168. NS_IMETHODIMP
  1169. nsTextControlFrame::RestoreState(nsPresState* aState)
  1170. {
  1171. NS_ENSURE_ARG_POINTER(aState);
  1172. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1173. NS_ASSERTION(txtCtrl, "Content not a text control element");
  1174. nsIContent* rootNode = txtCtrl->GetRootEditorNode();
  1175. if (rootNode) {
  1176. // Query the nsIStatefulFrame from the HTMLScrollFrame
  1177. nsIStatefulFrame* scrollStateFrame = do_QueryFrame(rootNode->GetPrimaryFrame());
  1178. if (scrollStateFrame) {
  1179. return scrollStateFrame->RestoreState(aState);
  1180. }
  1181. }
  1182. // Most likely, we don't have our anonymous content constructed yet, which
  1183. // would cause us to end up here. In this case, we'll just store the scroll
  1184. // pos ourselves, and forward it to the scroll frame later when it's created.
  1185. SetProperty(ContentScrollPos(), new nsPoint(aState->GetScrollPosition()));
  1186. return NS_OK;
  1187. }
  1188. nsresult
  1189. nsTextControlFrame::PeekOffset(nsPeekOffsetStruct *aPos)
  1190. {
  1191. return NS_ERROR_FAILURE;
  1192. }
  1193. void
  1194. nsTextControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  1195. const nsDisplayListSet& aLists)
  1196. {
  1197. /*
  1198. * The implementation of this method is equivalent as:
  1199. * nsContainerFrame::BuildDisplayList()
  1200. * with the difference that we filter-out the placeholder frame when it
  1201. * should not be visible.
  1202. */
  1203. DO_GLOBAL_REFLOW_COUNT_DSP("nsTextControlFrame");
  1204. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1205. NS_ASSERTION(txtCtrl, "Content not a text control element!");
  1206. DisplayBorderBackgroundOutline(aBuilder, aLists);
  1207. nsIFrame* kid = mFrames.FirstChild();
  1208. // Redirect all lists to the Content list so that nothing can escape, ie
  1209. // opacity creating stacking contexts that then get sorted with stacking
  1210. // contexts external to us.
  1211. nsDisplayList* content = aLists.Content();
  1212. nsDisplayListSet set(content, content, content, content, content, content);
  1213. while (kid) {
  1214. // If the frame is the placeholder frame, we should only show it if the
  1215. // placeholder has to be visible.
  1216. if (kid->GetContent() != txtCtrl->GetPlaceholderNode() ||
  1217. txtCtrl->GetPlaceholderVisibility()) {
  1218. BuildDisplayListForChild(aBuilder, kid, set, 0);
  1219. }
  1220. kid = kid->GetNextSibling();
  1221. }
  1222. }
  1223. mozilla::dom::Element*
  1224. nsTextControlFrame::GetPseudoElement(CSSPseudoElementType aType)
  1225. {
  1226. if (aType == CSSPseudoElementType::placeholder) {
  1227. nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  1228. return txtCtrl->GetPlaceholderNode();
  1229. }
  1230. return nsContainerFrame::GetPseudoElement(aType);
  1231. }
  1232. NS_IMETHODIMP
  1233. nsTextControlFrame::EditorInitializer::Run()
  1234. {
  1235. if (!mFrame) {
  1236. return NS_OK;
  1237. }
  1238. // Need to block script to avoid bug 669767.
  1239. nsAutoScriptBlocker scriptBlocker;
  1240. nsCOMPtr<nsIPresShell> shell =
  1241. mFrame->PresContext()->GetPresShell();
  1242. bool observes = shell->ObservesNativeAnonMutationsForPrint();
  1243. shell->ObserveNativeAnonMutationsForPrint(true);
  1244. // This can cause the frame to be destroyed (and call Revoke()).
  1245. mFrame->EnsureEditorInitialized();
  1246. shell->ObserveNativeAnonMutationsForPrint(observes);
  1247. // The frame can *still* be destroyed even though we have a scriptblocker,
  1248. // bug 682684.
  1249. if (!mFrame) {
  1250. return NS_ERROR_FAILURE;
  1251. }
  1252. mFrame->FinishedInitializer();
  1253. return NS_OK;
  1254. }