summaryrefslogtreecommitdiffstats
path: root/layout/forms/nsDateTimeControlFrame.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /layout/forms/nsDateTimeControlFrame.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'layout/forms/nsDateTimeControlFrame.cpp')
-rw-r--r--layout/forms/nsDateTimeControlFrame.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/layout/forms/nsDateTimeControlFrame.cpp b/layout/forms/nsDateTimeControlFrame.cpp
new file mode 100644
index 000000000..df2e43986
--- /dev/null
+++ b/layout/forms/nsDateTimeControlFrame.cpp
@@ -0,0 +1,414 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * This frame type is used for input type=date, time, month, week, and
+ * datetime-local.
+ */
+
+#include "nsDateTimeControlFrame.h"
+
+#include "nsContentUtils.h"
+#include "nsFormControlFrame.h"
+#include "nsGkAtoms.h"
+#include "nsContentUtils.h"
+#include "nsContentCreatorFunctions.h"
+#include "nsContentList.h"
+#include "mozilla/dom/HTMLInputElement.h"
+#include "nsNodeInfoManager.h"
+#include "nsIDateTimeInputArea.h"
+#include "nsIObserverService.h"
+#include "nsIDOMHTMLInputElement.h"
+#include "nsIDOMMutationEvent.h"
+#include "jsapi.h"
+#include "nsJSUtils.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+nsIFrame*
+NS_NewDateTimeControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+ return new (aPresShell) nsDateTimeControlFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
+
+NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
+ NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
+ NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
+
+nsDateTimeControlFrame::nsDateTimeControlFrame(nsStyleContext* aContext)
+ : nsContainerFrame(aContext)
+{
+}
+
+void
+nsDateTimeControlFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+ nsContentUtils::DestroyAnonymousContent(&mInputAreaContent);
+ nsContainerFrame::DestroyFrom(aDestructRoot);
+}
+
+void
+nsDateTimeControlFrame::UpdateInputBoxValue()
+{
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ inputAreaContent->NotifyInputElementValueChanged();
+ }
+}
+
+void
+nsDateTimeControlFrame::SetValueFromPicker(const DateTimeValue& aValue)
+{
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ AutoJSAPI api;
+ if (!api.Init(mContent->OwnerDoc()->GetScopeObject())) {
+ return;
+ }
+
+ JSObject* wrapper = mContent->GetWrapper();
+ if (!wrapper) {
+ return;
+ }
+
+ JSObject* scope = xpc::GetXBLScope(api.cx(), wrapper);
+ AutoJSAPI jsapi;
+ if (!scope || !jsapi.Init(scope)) {
+ return;
+ }
+
+ JS::Rooted<JS::Value> jsValue(jsapi.cx());
+ if (!ToJSValue(jsapi.cx(), aValue, &jsValue)) {
+ return;
+ }
+
+ inputAreaContent->SetValueFromPicker(jsValue);
+ }
+}
+
+void
+nsDateTimeControlFrame::SetPickerState(bool aOpen)
+{
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ inputAreaContent->SetPickerState(aOpen);
+ }
+}
+
+void
+nsDateTimeControlFrame::HandleFocusEvent()
+{
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ inputAreaContent->FocusInnerTextBox();
+ }
+}
+
+void
+nsDateTimeControlFrame::HandleBlurEvent()
+{
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ inputAreaContent->BlurInnerTextBox();
+ }
+}
+
+nscoord
+nsDateTimeControlFrame::GetMinISize(nsRenderingContext* aRenderingContext)
+{
+ nscoord result;
+ DISPLAY_MIN_WIDTH(this, result);
+
+ nsIFrame* kid = mFrames.FirstChild();
+ if (kid) { // display:none?
+ result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+ kid,
+ nsLayoutUtils::MIN_ISIZE);
+ } else {
+ result = 0;
+ }
+
+ return result;
+}
+
+nscoord
+nsDateTimeControlFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
+{
+ nscoord result;
+ DISPLAY_PREF_WIDTH(this, result);
+
+ nsIFrame* kid = mFrames.FirstChild();
+ if (kid) { // display:none?
+ result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+ kid,
+ nsLayoutUtils::PREF_ISIZE);
+ } else {
+ result = 0;
+ }
+
+ return result;
+}
+
+void
+nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus)
+{
+ MarkInReflow();
+
+ DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame");
+ DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
+ NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+ ("enter nsDateTimeControlFrame::Reflow: availSize=%d,%d",
+ aReflowInput.AvailableWidth(),
+ aReflowInput.AvailableHeight()));
+
+ NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
+
+ const WritingMode myWM = aReflowInput.GetWritingMode();
+
+ // The ISize of our content box, which is the available ISize
+ // for our anonymous content:
+ const nscoord contentBoxISize = aReflowInput.ComputedISize();
+ nscoord contentBoxBSize = aReflowInput.ComputedBSize();
+
+ // Figure out our border-box sizes as well (by adding borderPadding to
+ // content-box sizes):
+ const nscoord borderBoxISize = contentBoxISize +
+ aReflowInput.ComputedLogicalBorderPadding().IStartEnd(myWM);
+
+ nscoord borderBoxBSize;
+ if (contentBoxBSize != NS_INTRINSICSIZE) {
+ borderBoxBSize = contentBoxBSize +
+ aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
+ } // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize.
+
+ nsIFrame* inputAreaFrame = mFrames.FirstChild();
+ if (!inputAreaFrame) { // display:none?
+ if (contentBoxBSize == NS_INTRINSICSIZE) {
+ contentBoxBSize = 0;
+ borderBoxBSize =
+ aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
+ }
+ } else {
+ NS_ASSERTION(inputAreaFrame->GetContent() == mInputAreaContent,
+ "What is this child doing here?");
+
+ ReflowOutput childDesiredSize(aReflowInput);
+
+ WritingMode wm = inputAreaFrame->GetWritingMode();
+ LogicalSize availSize = aReflowInput.ComputedSize(wm);
+ availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
+
+ ReflowInput childReflowOuput(aPresContext, aReflowInput,
+ inputAreaFrame, availSize);
+
+ // Convert input area margin into my own writing-mode (in case it differs):
+ LogicalMargin childMargin =
+ childReflowOuput.ComputedLogicalMargin().ConvertTo(myWM, wm);
+
+ // offsets of input area frame within this frame:
+ LogicalPoint
+ childOffset(myWM,
+ aReflowInput.ComputedLogicalBorderPadding().IStart(myWM) +
+ childMargin.IStart(myWM),
+ aReflowInput.ComputedLogicalBorderPadding().BStart(myWM) +
+ childMargin.BStart(myWM));
+
+ nsReflowStatus childStatus;
+ // We initially reflow the child with a dummy containerSize; positioning
+ // will be fixed later.
+ const nsSize dummyContainerSize;
+ ReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
+ childReflowOuput, myWM, childOffset, dummyContainerSize, 0,
+ childStatus);
+ MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(childStatus),
+ "We gave our child unconstrained available block-size, "
+ "so it should be complete");
+
+ nscoord childMarginBoxBSize =
+ childDesiredSize.BSize(myWM) + childMargin.BStartEnd(myWM);
+
+ if (contentBoxBSize == NS_INTRINSICSIZE) {
+ // We are intrinsically sized -- we should shrinkwrap the input area's
+ // block-size:
+ contentBoxBSize = childMarginBoxBSize;
+
+ // Make sure we obey min/max-bsize in the case when we're doing intrinsic
+ // sizing (we get it for free when we have a non-intrinsic
+ // aReflowInput.ComputedBSize()). Note that we do this before
+ // adjusting for borderpadding, since ComputedMaxBSize and
+ // ComputedMinBSize are content heights.
+ contentBoxBSize =
+ NS_CSS_MINMAX(contentBoxBSize,
+ aReflowInput.ComputedMinBSize(),
+ aReflowInput.ComputedMaxBSize());
+
+ borderBoxBSize = contentBoxBSize +
+ aReflowInput.ComputedLogicalBorderPadding().BStartEnd(myWM);
+ }
+
+ // Center child in block axis
+ nscoord extraSpace = contentBoxBSize - childMarginBoxBSize;
+ childOffset.B(myWM) += std::max(0, extraSpace / 2);
+
+ // Needed in FinishReflowChild, for logical-to-physical conversion:
+ nsSize borderBoxSize = LogicalSize(myWM, borderBoxISize, borderBoxBSize).
+ GetPhysicalSize(myWM);
+
+ // Place the child
+ FinishReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
+ &childReflowOuput, myWM, childOffset, borderBoxSize, 0);
+
+ nsSize contentBoxSize =
+ LogicalSize(myWM, contentBoxISize, contentBoxBSize).
+ GetPhysicalSize(myWM);
+ aDesiredSize.SetBlockStartAscent(
+ childDesiredSize.BlockStartAscent() +
+ inputAreaFrame->BStart(aReflowInput.GetWritingMode(),
+ contentBoxSize));
+ }
+
+ LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
+ aDesiredSize.SetSize(myWM, logicalDesiredSize);
+
+ aDesiredSize.SetOverflowAreasToDesiredBounds();
+
+ if (inputAreaFrame) {
+ ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inputAreaFrame);
+ }
+
+ FinishAndStoreOverflow(&aDesiredSize);
+
+ aStatus = NS_FRAME_COMPLETE;
+
+ NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+ ("exit nsDateTimeControlFrame::Reflow: size=%d,%d",
+ aDesiredSize.Width(), aDesiredSize.Height()));
+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
+}
+
+nsresult
+nsDateTimeControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
+{
+ // Set up "datetimebox" XUL element which will be XBL-bound to the
+ // actual controls.
+ nsNodeInfoManager* nodeInfoManager =
+ mContent->GetComposedDoc()->NodeInfoManager();
+ RefPtr<NodeInfo> nodeInfo =
+ nodeInfoManager->GetNodeInfo(nsGkAtoms::datetimebox, nullptr,
+ kNameSpaceID_XUL, nsIDOMNode::ELEMENT_NODE);
+ NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
+
+ NS_TrustedNewXULElement(getter_AddRefs(mInputAreaContent), nodeInfo.forget());
+ aElements.AppendElement(mInputAreaContent);
+
+ // Propogate our tabindex.
+ nsAutoString tabIndexStr;
+ if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr)) {
+ mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::tabindex,
+ tabIndexStr, false);
+ }
+
+ // Propagate our readonly state.
+ nsAutoString readonly;
+ if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly)) {
+ mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::readonly, readonly,
+ false);
+ }
+
+ SyncDisabledState();
+
+ return NS_OK;
+}
+
+void
+nsDateTimeControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
+ uint32_t aFilter)
+{
+ if (mInputAreaContent) {
+ aElements.AppendElement(mInputAreaContent);
+ }
+}
+
+void
+nsDateTimeControlFrame::SyncDisabledState()
+{
+ EventStates eventStates = mContent->AsElement()->State();
+ if (eventStates.HasState(NS_EVENT_STATE_DISABLED)) {
+ mInputAreaContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled,
+ EmptyString(), true);
+ } else {
+ mInputAreaContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true);
+ }
+}
+
+nsresult
+nsDateTimeControlFrame::AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType)
+{
+ NS_ASSERTION(mInputAreaContent, "The input area content must exist!");
+
+ // nsGkAtoms::disabled is handled by SyncDisabledState
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aAttribute == nsGkAtoms::value ||
+ aAttribute == nsGkAtoms::readonly ||
+ aAttribute == nsGkAtoms::tabindex) {
+ MOZ_ASSERT(mContent->IsHTMLElement(nsGkAtoms::input), "bad cast");
+ auto contentAsInputElem = static_cast<dom::HTMLInputElement*>(mContent);
+ // If script changed the <input>'s type before setting these attributes
+ // then we don't need to do anything since we are going to be reframed.
+ if (contentAsInputElem->GetType() == NS_FORM_INPUT_TIME) {
+ if (aAttribute == nsGkAtoms::value) {
+ nsCOMPtr<nsIDateTimeInputArea> inputAreaContent =
+ do_QueryInterface(mInputAreaContent);
+ if (inputAreaContent) {
+ nsContentUtils::AddScriptRunner(NewRunnableMethod(inputAreaContent,
+ &nsIDateTimeInputArea::NotifyInputElementValueChanged));
+ }
+ } else {
+ if (aModType == nsIDOMMutationEvent::REMOVAL) {
+ mInputAreaContent->UnsetAttr(aNameSpaceID, aAttribute, true);
+ } else {
+ MOZ_ASSERT(aModType == nsIDOMMutationEvent::ADDITION ||
+ aModType == nsIDOMMutationEvent::MODIFICATION);
+ nsAutoString value;
+ mContent->GetAttr(aNameSpaceID, aAttribute, value);
+ mInputAreaContent->SetAttr(aNameSpaceID, aAttribute, value, true);
+ }
+ }
+ }
+ }
+ }
+
+ return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
+ aModType);
+}
+
+void
+nsDateTimeControlFrame::ContentStatesChanged(EventStates aStates)
+{
+ if (aStates.HasState(NS_EVENT_STATE_DISABLED)) {
+ nsContentUtils::AddScriptRunner(new SyncDisabledStateEvent(this));
+ }
+}
+
+nsIAtom*
+nsDateTimeControlFrame::GetType() const
+{
+ return nsGkAtoms::dateTimeControlFrame;
+}