forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnsMathMLmsubFrame.cpp
193 lines (165 loc) · 7.02 KB
/
nsMathMLmsubFrame.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/* -*- 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/. */
#include "nsCOMPtr.h"
#include "nsFrame.h"
#include "nsPresContext.h"
#include "nsStyleContext.h"
#include "nsStyleConsts.h"
#include "nsMathMLmsubFrame.h"
#include <algorithm>
//
// <msub> -- attach a subscript to a base - implementation
//
nsIFrame*
NS_NewMathMLmsubFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsMathMLmsubFrame(aContext);
}
NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmsubFrame)
nsMathMLmsubFrame::~nsMathMLmsubFrame()
{
}
NS_IMETHODIMP
nsMathMLmsubFrame::TransmitAutomaticData()
{
// if our base is an embellished operator, let its state bubble to us
mPresentationData.baseFrame = mFrames.FirstChild();
GetEmbellishDataFrom(mPresentationData.baseFrame, mEmbellishData);
// 1. The REC says:
// The <msub> element increments scriptlevel by 1, and sets displaystyle to
// "false", within subscript, but leaves both attributes unchanged within base.
// 2. The TeXbook (Ch 17. p.141) says the subscript is compressed
UpdatePresentationDataFromChildAt(1, -1,
~NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED,
NS_MATHML_DISPLAYSTYLE | NS_MATHML_COMPRESSED);
return NS_OK;
}
/* virtual */ nsresult
nsMathMLmsubFrame::Place (nsRenderingContext& aRenderingContext,
bool aPlaceOrigin,
nsHTMLReflowMetrics& aDesiredSize)
{
// extra spacing after sup/subscript
nscoord scriptSpace = nsPresContext::CSSPointsToAppUnits(0.5f); // 0.5pt as in plain TeX
// subscriptshift
//
// "Specifies the minimum amount to shift the baseline of subscript down; the
// default is for the rendering agent to use its own positioning rules."
//
// values: length
// default: automatic
//
// We use 0 as the default value so unitless values can be ignored.
// As a minimum, negative values can be ignored.
//
nscoord subScriptShift = 0;
nsAutoString value;
GetAttribute(mContent, mPresentationData.mstyle,
nsGkAtoms::subscriptshift_, value);
if (!value.IsEmpty()) {
ParseNumericValue(value, &subScriptShift, 0, PresContext(), mStyleContext);
}
return nsMathMLmsubFrame::PlaceSubScript(PresContext(),
aRenderingContext,
aPlaceOrigin,
aDesiredSize,
this,
subScriptShift,
scriptSpace);
}
// exported routine that both munder and msub share.
// munder uses this when movablelimits is set.
nsresult
nsMathMLmsubFrame::PlaceSubScript (nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
bool aPlaceOrigin,
nsHTMLReflowMetrics& aDesiredSize,
nsMathMLContainerFrame* aFrame,
nscoord aUserSubScriptShift,
nscoord aScriptSpace)
{
// force the scriptSpace to be atleast 1 pixel
aScriptSpace = std::max(nsPresContext::CSSPixelsToAppUnits(1), aScriptSpace);
////////////////////////////////////
// Get the children's desired sizes
nsBoundingMetrics bmBase, bmSubScript;
nsHTMLReflowMetrics baseSize;
nsHTMLReflowMetrics subScriptSize;
nsIFrame* baseFrame = aFrame->GetFirstPrincipalChild();
nsIFrame* subScriptFrame = nullptr;
if (baseFrame)
subScriptFrame = baseFrame->GetNextSibling();
if (!baseFrame || !subScriptFrame || subScriptFrame->GetNextSibling()) {
// report an error, encourage people to get their markups in order
if (aPlaceOrigin) {
aFrame->ReportChildCountError();
}
return aFrame->ReflowError(aRenderingContext, aDesiredSize);
}
GetReflowAndBoundingMetricsFor(baseFrame, baseSize, bmBase);
GetReflowAndBoundingMetricsFor(subScriptFrame, subScriptSize, bmSubScript);
// get the subdrop from the subscript font
nscoord subDrop;
GetSubDropFromChild(subScriptFrame, subDrop);
// parameter v, Rule 18a, App. G, TeXbook
nscoord minSubScriptShift = bmBase.descent + subDrop;
//////////////////
// Place Children
// get min subscript shift limit from x-height
// = h(x) - 4/5 * sigma_5, Rule 18b, App. G, TeXbook
nscoord xHeight = 0;
nsRefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(baseFrame, getter_AddRefs(fm));
xHeight = fm->XHeight();
nscoord minShiftFromXHeight = (nscoord)
(bmSubScript.ascent - (4.0f/5.0f) * xHeight);
// subScriptShift
// = minimum amount to shift the subscript down set by user or from the font
// = sub1 in TeX
// = subscriptshift attribute * x-height
nscoord subScriptShift, dummy;
// get subScriptShift default from font
GetSubScriptShifts (fm, subScriptShift, dummy);
subScriptShift =
std::max(subScriptShift, aUserSubScriptShift);
// get actual subscriptshift to be used
// Rule 18b, App. G, TeXbook
nscoord actualSubScriptShift =
std::max(minSubScriptShift,std::max(subScriptShift,minShiftFromXHeight));
// get bounding box for base + subscript
nsBoundingMetrics boundingMetrics;
boundingMetrics.ascent =
std::max(bmBase.ascent, bmSubScript.ascent - actualSubScriptShift);
boundingMetrics.descent =
std::max(bmBase.descent, bmSubScript.descent + actualSubScriptShift);
// add aScriptSpace to the subscript's width
boundingMetrics.width = bmBase.width + bmSubScript.width + aScriptSpace;
boundingMetrics.leftBearing = bmBase.leftBearing;
boundingMetrics.rightBearing = std::max(bmBase.rightBearing, bmBase.width +
std::max(bmSubScript.width + aScriptSpace, bmSubScript.rightBearing));
aFrame->SetBoundingMetrics (boundingMetrics);
// reflow metrics
aDesiredSize.ascent =
std::max(baseSize.ascent, subScriptSize.ascent - actualSubScriptShift);
aDesiredSize.height = aDesiredSize.ascent +
std::max(baseSize.height - baseSize.ascent,
subScriptSize.height - subScriptSize.ascent + actualSubScriptShift);
aDesiredSize.width = boundingMetrics.width;
aDesiredSize.mBoundingMetrics = boundingMetrics;
aFrame->SetReference(nsPoint(0, aDesiredSize.ascent));
if (aPlaceOrigin) {
nscoord dx, dy;
// now place the base ...
dx = aFrame->MirrorIfRTL(aDesiredSize.width, baseSize.width, 0);
dy = aDesiredSize.ascent - baseSize.ascent;
FinishReflowChild (baseFrame, aPresContext, nullptr, baseSize, dx, dy, 0);
// ... and subscript
dx = aFrame->MirrorIfRTL(aDesiredSize.width, subScriptSize.width,
bmBase.width);
dy = aDesiredSize.ascent - (subScriptSize.ascent - actualSubScriptShift);
FinishReflowChild (subScriptFrame, aPresContext, nullptr, subScriptSize, dx, dy, 0);
}
return NS_OK;
}