1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
* The contents of this file are subject to the Mozilla Public License Version
6
* 1.1 (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
8
* http://www.mozilla.org/MPL/
10
* Software distributed under the License is distributed on an "AS IS" basis,
11
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
* for the specific language governing rights and limitations under the
15
* The Original Code is Mozilla MathML Project.
17
* The Initial Developer of the Original Code is
18
* The University Of Queensland.
19
* Portions created by the Initial Developer are Copyright (C) 1999
20
* the Initial Developer. All Rights Reserved.
23
* Roger B. Sidje <rbs@maths.uq.edu.au>
25
* Alternatively, the contents of this file may be used under the terms of
26
* either of the GNU General Public License Version 2 or later (the "GPL"),
27
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
41
#include "nsPresContext.h"
42
#include "nsUnitConversion.h"
43
#include "nsStyleContext.h"
44
#include "nsStyleConsts.h"
45
#include "nsINameSpaceManager.h"
46
#include "nsIRenderingContext.h"
47
#include "nsIFontMetrics.h"
49
#include "nsCSSRendering.h"
50
#include "prprf.h" // For PR_snprintf()
52
#include "nsIDocShellTreeItem.h"
53
#include "nsIDocShellTreeOwner.h"
54
#include "nsIWebBrowserChrome.h"
55
#include "nsIInterfaceRequestor.h"
56
#include "nsIInterfaceRequestorUtils.h"
57
#include "nsIDOMElement.h"
59
#include "nsIDOMEventTarget.h"
60
#include "nsIDOMMouseListener.h"
62
#include "nsMathMLmactionFrame.h"
63
#include "nsAutoPtr.h"
64
#include "nsStyleSet.h"
65
#include "nsDisplayList.h"
66
#include "nsContentUtils.h"
69
// <maction> -- bind actions to a subexpression - implementation
72
#define NS_MATHML_ACTION_TYPE_NONE 0
73
#define NS_MATHML_ACTION_TYPE_TOGGLE 1
74
#define NS_MATHML_ACTION_TYPE_STATUSLINE 2
75
#define NS_MATHML_ACTION_TYPE_TOOLTIP 3 // unsupported
76
#define NS_MATHML_ACTION_TYPE_RESTYLE 4
78
NS_IMPL_ADDREF_INHERITED(nsMathMLmactionFrame, nsMathMLContainerFrame)
79
NS_IMPL_RELEASE_INHERITED(nsMathMLmactionFrame, nsMathMLContainerFrame)
80
NS_IMPL_QUERY_INTERFACE_INHERITED1(nsMathMLmactionFrame, nsMathMLContainerFrame, nsIDOMMouseListener)
83
NS_NewMathMLmactionFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
85
return new (aPresShell) nsMathMLmactionFrame(aContext);
88
nsMathMLmactionFrame::~nsMathMLmactionFrame()
90
// unregister us as a mouse event listener ...
91
// printf("maction:%p unregistering as mouse event listener ...\n", this);
92
mContent->RemoveEventListenerByIID(this, NS_GET_IID(nsIDOMMouseListener));
96
nsMathMLmactionFrame::Init(nsIContent* aContent,
98
nsIFrame* aPrevInFlow)
100
nsAutoString value, prefix;
102
// Init our local attributes
104
mChildCount = -1; // these will be updated in GetSelectedFrame()
106
mSelectedFrame = nsnull;
107
nsRefPtr<nsStyleContext> newStyleContext;
109
mActionType = NS_MATHML_ACTION_TYPE_NONE;
110
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::actiontype_, value);
111
if (!value.IsEmpty()) {
112
if (value.EqualsLiteral("toggle"))
113
mActionType = NS_MATHML_ACTION_TYPE_TOGGLE;
115
// XXX use goto to jump out of these if?
117
if (NS_MATHML_ACTION_TYPE_NONE == mActionType) {
118
// expected tooltip prefix (8ch)...
119
if (8 < value.Length() && 0 == value.Find("tooltip#"))
120
mActionType = NS_MATHML_ACTION_TYPE_TOOLTIP;
123
if (NS_MATHML_ACTION_TYPE_NONE == mActionType) {
124
// expected statusline prefix (11ch)...
125
if (11 < value.Length() && 0 == value.Find("statusline#"))
126
mActionType = NS_MATHML_ACTION_TYPE_STATUSLINE;
129
if (NS_MATHML_ACTION_TYPE_NONE == mActionType) {
130
// expected restyle prefix (8ch)...
131
if (8 < value.Length() && 0 == value.Find("restyle#")) {
132
mActionType = NS_MATHML_ACTION_TYPE_RESTYLE;
135
// Here is the situation:
136
// When the attribute [actiontype="restyle#id"] is set, the Style System has
137
// given us the associated style. But we want to start with our default style.
139
// So... first, remove the attribute actiontype="restyle#id"
140
// XXXbz this is pretty messed up, since this can change whether we
141
// should have a frame at all. This really needs a better solution.
142
PRBool notify = PR_FALSE; // don't trigger a reflow yet!
143
aContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::actiontype_, notify);
145
// then, re-resolve our style
146
nsStyleContext* parentStyleContext = GetStyleContext()->GetParent();
147
newStyleContext = PresContext()->StyleSet()->
148
ResolveStyleFor(aContent, parentStyleContext);
150
if (!newStyleContext)
153
if (newStyleContext != GetStyleContext())
154
SetStyleContextWithoutNotification(newStyleContext);
162
// Let the base class do the rest
163
return nsMathMLContainerFrame::Init(aContent, aParent, aPrevInFlow);
167
nsMathMLmactionFrame::ChildListChanged(PRInt32 aModType)
169
// update cached values
172
mSelectedFrame = nsnull;
175
return nsMathMLContainerFrame::ChildListChanged(aModType);
178
// return the frame whose number is given by the attribute selection="number"
180
nsMathMLmactionFrame::GetSelectedFrame()
185
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value);
186
if (!value.IsEmpty()) {
188
selection = value.ToInteger(&errorCode);
189
if (NS_FAILED(errorCode))
192
else selection = 1; // default is first frame
194
if (-1 != mChildCount) { // we have been in this function before...
195
// cater for invalid user-supplied selection
196
if (selection > mChildCount || selection < 1)
198
// quick return if it is identical with our cache
199
if (selection == mSelection)
200
return mSelectedFrame;
203
// get the selected child and cache new values...
205
nsIFrame* childFrame = mFrames.FirstChild();
208
mSelectedFrame = childFrame; // default is first child
209
if (++count == selection)
210
mSelectedFrame = childFrame;
212
childFrame = childFrame->GetNextSibling();
214
// cater for invalid user-supplied selection
215
if (selection > count || selection < 1)
219
mSelection = selection;
221
// if the selected child is an embellished operator,
222
// we become embellished as well
223
mPresentationData.baseFrame = mSelectedFrame;
224
GetEmbellishDataFrom(mSelectedFrame, mEmbellishData);
226
return mSelectedFrame;
230
nsMathMLmactionFrame::SetInitialChildList(nsIAtom* aListName,
231
nsIFrame* aChildList)
233
nsresult rv = nsMathMLContainerFrame::SetInitialChildList(aListName, aChildList);
235
// This very first call to GetSelectedFrame() will cause us to be marked as an
236
// embellished operator if the selected child is an embellished operator
237
if (!GetSelectedFrame()) {
238
mActionType = NS_MATHML_ACTION_TYPE_NONE;
241
// register us as a mouse event listener ...
242
// printf("maction:%p registering as mouse event listener ...\n", this);
243
mContent->AddEventListenerByIID(this, NS_GET_IID(nsIDOMMouseListener));
248
// Only paint the selected child...
250
nsMathMLmactionFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
251
const nsRect& aDirtyRect,
252
const nsDisplayListSet& aLists)
254
nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
255
NS_ENSURE_SUCCESS(rv, rv);
257
nsIFrame* childFrame = GetSelectedFrame();
259
// Put the child's background directly onto the content list
260
nsDisplayListSet set(aLists, aLists.Content());
261
// The children should be in content order
262
rv = BuildDisplayListForChild(aBuilder, childFrame, aDirtyRect, set);
263
NS_ENSURE_SUCCESS(rv, rv);
266
#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
268
rv = DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
273
// Only reflow the selected child ...
275
nsMathMLmactionFrame::Reflow(nsPresContext* aPresContext,
276
nsHTMLReflowMetrics& aDesiredSize,
277
const nsHTMLReflowState& aReflowState,
278
nsReflowStatus& aStatus)
281
aStatus = NS_FRAME_COMPLETE;
282
aDesiredSize.width = aDesiredSize.height = 0;
283
aDesiredSize.ascent = 0;
284
mBoundingMetrics.Clear();
285
nsIFrame* childFrame = GetSelectedFrame();
287
nsSize availSize(aReflowState.ComputedWidth(),
288
aReflowState.ComputedHeight());
289
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
290
childFrame, availSize);
291
rv = ReflowChild(childFrame, aPresContext, aDesiredSize,
292
childReflowState, aStatus);
293
childFrame->SetRect(nsRect(0,aDesiredSize.ascent,
294
aDesiredSize.width,aDesiredSize.height));
295
mBoundingMetrics = aDesiredSize.mBoundingMetrics;
297
FinalizeReflow(*aReflowState.rendContext, aDesiredSize);
298
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
302
// Only place the selected child ...
304
nsMathMLmactionFrame::Place(nsIRenderingContext& aRenderingContext,
306
nsHTMLReflowMetrics& aDesiredSize)
308
aDesiredSize.width = aDesiredSize.height = 0;
309
aDesiredSize.ascent = 0;
310
mBoundingMetrics.Clear();
311
nsIFrame* childFrame = GetSelectedFrame();
313
GetReflowAndBoundingMetricsFor(childFrame, aDesiredSize, mBoundingMetrics);
315
FinishReflowChild(childFrame, PresContext(), nsnull, aDesiredSize, 0, 0, 0);
318
mReference.y = aDesiredSize.ascent;
320
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
324
// ################################################################
326
// ################################################################
328
// helper to show a msg on the status bar
329
// curled from nsObjectFrame.cpp ...
331
nsMathMLmactionFrame::ShowStatus(nsPresContext* aPresContext,
332
nsString& aStatusMsg)
334
nsCOMPtr<nsISupports> cont = aPresContext->GetContainer();
336
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(cont));
338
nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
339
docShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
341
nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(treeOwner));
343
browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, aStatusMsg.get());
352
nsMathMLmactionFrame::MouseOver(nsIDOMEvent* aMouseEvent)
354
// see if we should display a status message
355
if (NS_MATHML_ACTION_TYPE_STATUSLINE == mActionType) {
357
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::actiontype_, value);
358
// expected statusline prefix (11ch)...
359
if (11 < value.Length() && 0 == value.Find("statusline#")) {
361
ShowStatus(PresContext(), value);
368
nsMathMLmactionFrame::MouseOut(nsIDOMEvent* aMouseEvent)
370
// see if we should remove the status message
371
if (NS_MATHML_ACTION_TYPE_STATUSLINE == mActionType) {
374
ShowStatus(PresContext(), value);
380
nsMathMLmactionFrame::MouseClick(nsIDOMEvent* aMouseEvent)
382
if (NS_MATHML_ACTION_TYPE_TOGGLE == mActionType) {
383
if (mChildCount > 1) {
384
PRInt32 selection = (mSelection == mChildCount)? 1 : mSelection + 1;
387
PR_snprintf(cbuf, sizeof(cbuf), "%d", selection);
388
value.AssignASCII(cbuf);
389
PRBool notify = PR_FALSE; // don't yet notify the document
390
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::selection_, value, notify);
392
// Now trigger a content-changed reflow...
393
PresContext()->PresShell()->
394
FrameNeedsReflow(mSelectedFrame, nsIPresShell::eTreeChange,
398
else if (NS_MATHML_ACTION_TYPE_RESTYLE == mActionType) {
399
if (!mRestyle.IsEmpty()) {
400
nsCOMPtr<nsIDOMElement> node( do_QueryInterface(mContent) );
402
if (nsContentUtils::HasNonEmptyAttr(mContent, kNameSpaceID_None,
403
nsGkAtoms::actiontype_))
404
node->RemoveAttribute(NS_LITERAL_STRING("actiontype"));
406
node->SetAttribute(NS_LITERAL_STRING("actiontype"), mRestyle);
408
// Trigger a style change reflow
409
PresContext()->PresShell()->
410
FrameNeedsReflow(mSelectedFrame, nsIPresShell::eStyleChange,