layout/forms/nsTextControlFrame.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial