Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/mathml/nsMathMLTokenFrame.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsMathMLTokenFrame.h"
8
#include "nsPresContext.h"
9
#include "nsContentUtils.h"
10
#include "nsTextFrame.h"
11
#include <algorithm>
12
13
using namespace mozilla;
14
15
nsIFrame*
16
NS_NewMathMLTokenFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
17
0
{
18
0
  return new (aPresShell) nsMathMLTokenFrame(aStyle);
19
0
}
20
21
NS_IMPL_FRAMEARENA_HELPERS(nsMathMLTokenFrame)
22
23
nsMathMLTokenFrame::~nsMathMLTokenFrame()
24
0
{
25
0
}
26
27
NS_IMETHODIMP
28
nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
29
0
{
30
0
  // let the base class get the default from our parent
31
0
  nsMathMLContainerFrame::InheritAutomaticData(aParent);
32
0
33
0
  return NS_OK;
34
0
}
35
36
eMathMLFrameType
37
nsMathMLTokenFrame::GetMathMLFrameType()
38
0
{
39
0
  // treat everything other than <mi> as ordinary...
40
0
  if (!mContent->IsMathMLElement(nsGkAtoms::mi_)) {
41
0
    return eMathMLFrameType_Ordinary;
42
0
  }
43
0
44
0
  uint8_t mathVariant = StyleFont()->mMathVariant;
45
0
  if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
46
0
       (StyleFont()->mFont.style == FontSlantStyle::Italic() ||
47
0
        HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) ||
48
0
      mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
49
0
      mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
50
0
      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
51
0
      mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
52
0
    return eMathMLFrameType_ItalicIdentifier;
53
0
  }
54
0
  return eMathMLFrameType_UprightIdentifier;
55
0
}
56
57
void
58
nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
59
0
{
60
0
  nsIFrame* child = nullptr;
61
0
  uint32_t childCount = 0;
62
0
63
0
  // Set flags on child text frames
64
0
  // - to force them to trim their leading and trailing whitespaces.
65
0
  // - Indicate which frames are suitable for mathvariant
66
0
  // - flag single character <mi> frames for special italic treatment
67
0
  for (nsIFrame* childFrame = PrincipalChildList().FirstChild(); childFrame;
68
0
       childFrame = childFrame->GetNextSibling()) {
69
0
    for (nsIFrame* childFrame2 = childFrame->PrincipalChildList().FirstChild();
70
0
         childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
71
0
      if (childFrame2->IsTextFrame()) {
72
0
        childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
73
0
        child = childFrame2;
74
0
        childCount++;
75
0
      }
76
0
    }
77
0
  }
78
0
  if (mContent->IsMathMLElement(nsGkAtoms::mi_) && childCount == 1) {
79
0
    nsAutoString data;
80
0
    nsContentUtils::GetNodeTextContent(mContent, false, data);
81
0
82
0
    data.CompressWhitespace();
83
0
    int32_t length = data.Length();
84
0
85
0
    bool isSingleCharacter = length == 1 ||
86
0
      (length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
87
0
88
0
    if (isSingleCharacter) {
89
0
      child->AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
90
0
      AddStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI);
91
0
    }
92
0
  }
93
0
}
94
95
void
96
nsMathMLTokenFrame::SetInitialChildList(ChildListID     aListID,
97
                                        nsFrameList&    aChildList)
98
0
{
99
0
  // First, let the base class do its work
100
0
  nsMathMLContainerFrame::SetInitialChildList(aListID, aChildList);
101
0
  MarkTextFramesAsTokenMathML();
102
0
}
103
104
void
105
nsMathMLTokenFrame::AppendFrames(ChildListID aListID,
106
                                 nsFrameList& aChildList)
107
0
{
108
0
  nsMathMLContainerFrame::AppendFrames(aListID, aChildList);
109
0
  MarkTextFramesAsTokenMathML();
110
0
}
111
112
void
113
nsMathMLTokenFrame::InsertFrames(ChildListID aListID,
114
                                 nsIFrame* aPrevFrame,
115
                                 nsFrameList& aChildList)
116
0
{
117
0
  nsMathMLContainerFrame::InsertFrames(aListID, aPrevFrame, aChildList);
118
0
  MarkTextFramesAsTokenMathML();
119
0
}
120
121
void
122
nsMathMLTokenFrame::Reflow(nsPresContext*          aPresContext,
123
                           ReflowOutput&     aDesiredSize,
124
                           const ReflowInput& aReflowInput,
125
                           nsReflowStatus&          aStatus)
126
0
{
127
0
  MarkInReflow();
128
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
129
0
130
0
  mPresentationData.flags &= ~NS_MATHML_ERROR;
131
0
132
0
  // initializations needed for empty markup like <mtag></mtag>
133
0
  aDesiredSize.ClearSize();
134
0
  aDesiredSize.SetBlockStartAscent(0);
135
0
  aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
136
0
137
0
  for (nsIFrame* childFrame : PrincipalChildList()) {
138
0
    // ask our children to compute their bounding metrics
139
0
    ReflowOutput childDesiredSize(aReflowInput.GetWritingMode());
140
0
    WritingMode wm = childFrame->GetWritingMode();
141
0
    LogicalSize availSize = aReflowInput.ComputedSize(wm);
142
0
    availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
143
0
    ReflowInput childReflowInput(aPresContext, aReflowInput,
144
0
                                       childFrame, availSize);
145
0
    ReflowChild(childFrame, aPresContext, childDesiredSize,
146
0
                childReflowInput, aStatus);
147
0
    //NS_ASSERTION(aStatus.IsComplete(), "bad status");
148
0
    SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
149
0
                                    childDesiredSize.mBoundingMetrics);
150
0
  }
151
0
152
0
  // place and size children
153
0
  FinalizeReflow(aReflowInput.mRenderingContext->GetDrawTarget(), aDesiredSize);
154
0
155
0
  aStatus.Reset(); // This type of frame can't be split.
156
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
157
0
}
158
159
// For token elements, mBoundingMetrics is computed at the ReflowToken
160
// pass, it is not computed here because our children may be text frames
161
// that do not implement the GetBoundingMetrics() interface.
162
/* virtual */ nsresult
163
nsMathMLTokenFrame::Place(DrawTarget*          aDrawTarget,
164
                          bool                 aPlaceOrigin,
165
                          ReflowOutput& aDesiredSize)
166
0
{
167
0
  mBoundingMetrics = nsBoundingMetrics();
168
0
  for (nsIFrame* childFrame :PrincipalChildList()) {
169
0
    ReflowOutput childSize(aDesiredSize.GetWritingMode());
170
0
    GetReflowAndBoundingMetricsFor(childFrame, childSize,
171
0
                                   childSize.mBoundingMetrics, nullptr);
172
0
    // compute and cache the bounding metrics
173
0
    mBoundingMetrics += childSize.mBoundingMetrics;
174
0
  }
175
0
176
0
  RefPtr<nsFontMetrics> fm =
177
0
    nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
178
0
  nscoord ascent = fm->MaxAscent();
179
0
  nscoord descent = fm->MaxDescent();
180
0
181
0
  aDesiredSize.mBoundingMetrics = mBoundingMetrics;
182
0
  aDesiredSize.Width() = mBoundingMetrics.width;
183
0
  aDesiredSize.SetBlockStartAscent(std::max(mBoundingMetrics.ascent, ascent));
184
0
  aDesiredSize.Height() = aDesiredSize.BlockStartAscent() +
185
0
                        std::max(mBoundingMetrics.descent, descent);
186
0
187
0
  if (aPlaceOrigin) {
188
0
    nscoord dy, dx = 0;
189
0
    for (nsIFrame* childFrame : PrincipalChildList()) {
190
0
      ReflowOutput childSize(aDesiredSize.GetWritingMode());
191
0
      GetReflowAndBoundingMetricsFor(childFrame, childSize,
192
0
                                     childSize.mBoundingMetrics);
193
0
194
0
      // place and size the child; (dx,0) makes the caret happy - bug 188146
195
0
      dy = childSize.Height() == 0 ? 0 : aDesiredSize.BlockStartAscent() - childSize.BlockStartAscent();
196
0
      FinishReflowChild(childFrame, PresContext(), childSize, nullptr, dx, dy, 0);
197
0
      dx += childSize.Width();
198
0
    }
199
0
  }
200
0
201
0
  SetReference(nsPoint(0, aDesiredSize.BlockStartAscent()));
202
0
203
0
  return NS_OK;
204
0
}
205