Bug 114365 - MathML Frame changes to support mathvariant. r=fredw

This commit is contained in:
James Kitchener 2013-12-02 11:50:10 -05:00
parent 35e65cfbd9
commit 9ba7e0802f
4 changed files with 57 additions and 172 deletions

View File

@ -28,8 +28,6 @@ nsMathMLTokenFrame::InheritAutomaticData(nsIFrame* aParent)
// let the base class get the default from our parent
nsMathMLContainerFrame::InheritAutomaticData(aParent);
ProcessTextData();
return NS_OK;
}
@ -41,58 +39,54 @@ nsMathMLTokenFrame::GetMathMLFrameType()
return eMathMLFrameType_Ordinary;
}
// for <mi>, distinguish between italic and upright...
nsAutoString style;
// mathvariant overrides fontstyle
// http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.deprecatt
mContent->GetAttr(kNameSpaceID_None,
nsGkAtoms::_moz_math_fontstyle_, style) ||
GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::mathvariant_,
style) ||
GetAttribute(mContent, mPresentationData.mstyle, nsGkAtoms::fontstyle_,
style);
if (style.EqualsLiteral("italic") || style.EqualsLiteral("bold-italic") ||
style.EqualsLiteral("script") || style.EqualsLiteral("bold-script") ||
style.EqualsLiteral("sans-serif-italic") ||
style.EqualsLiteral("sans-serif-bold-italic")) {
uint8_t mathVariant = StyleFont()->mMathVariant;
if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
(StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_ITALIC ||
HasAnyStateBits(TEXT_IS_IN_SINGLE_CHAR_MI))) ||
mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
return eMathMLFrameType_ItalicIdentifier;
}
else if(style.EqualsLiteral("invariant")) {
nsAutoString data;
nsContentUtils::GetNodeTextContent(mContent, false, data);
data.CompressWhitespace();
eMATHVARIANT variant = nsMathMLOperators::LookupInvariantChar(data);
switch (variant) {
case eMATHVARIANT_italic:
case eMATHVARIANT_bold_italic:
case eMATHVARIANT_script:
case eMATHVARIANT_bold_script:
case eMATHVARIANT_sans_serif_italic:
case eMATHVARIANT_sans_serif_bold_italic:
return eMathMLFrameType_ItalicIdentifier;
default:
; // fall through to upright
}
}
return eMathMLFrameType_UprightIdentifier;
}
void
nsMathMLTokenFrame::MarkTextFramesAsTokenMathML()
{
// Set flags on child text frames to force them to trim their leading and
// trailing whitespaces.
nsIFrame* child = nullptr;
uint32_t childCount = 0;
// Set flags on child text frames
// - to force them to trim their leading and trailing whitespaces.
// - Indicate which frames are suitable for mathvariant
// - flag single character <mi> frames for special italic treatment
for (nsIFrame* childFrame = GetFirstPrincipalChild(); childFrame;
childFrame = childFrame->GetNextSibling()) {
for (nsIFrame* childFrame2 = childFrame->GetFirstPrincipalChild();
childFrame2; childFrame2 = childFrame2->GetNextSibling()) {
if (childFrame2->GetType() == nsGkAtoms::textFrame) {
childFrame2->AddStateBits(TEXT_IS_IN_TOKEN_MATHML);
child = childFrame2;
childCount++;
}
}
}
if (mContent->Tag() == nsGkAtoms::mi_ && childCount == 1) {
nsAutoString data;
nsContentUtils::GetNodeTextContent(mContent, false, data);
data.CompressWhitespace();
int32_t length = data.Length();
bool isSingleCharacter = length == 1 ||
(length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
if (isSingleCharacter) {
child->AddStateBits(TEXT_IS_IN_SINGLE_CHAR_MI);
}
}
}
NS_IMETHODIMP
@ -106,7 +100,6 @@ nsMathMLTokenFrame::SetInitialChildList(ChildListID aListID,
MarkTextFramesAsTokenMathML();
ProcessTextData();
return rv;
}
@ -232,120 +225,3 @@ nsMathMLTokenFrame::Place(nsRenderingContext& aRenderingContext,
return NS_OK;
}
/* virtual */ void
nsMathMLTokenFrame::MarkIntrinsicWidthsDirty()
{
// this could be called due to changes in the nsTextFrame beneath us
// when something changed in the text content. So re-process our text
ProcessTextData();
nsMathMLContainerFrame::MarkIntrinsicWidthsDirty();
}
void
nsMathMLTokenFrame::ProcessTextData()
{
// see if the style changes from normal to italic or vice-versa
if (!SetTextStyle())
return;
// explicitly request a re-resolve to pick up the change of style
PresContext()->RestyleManager()->
PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree, NS_STYLE_HINT_NONE);
}
///////////////////////////////////////////////////////////////////////////
// For <mi>, if the content is not a single character, turn the font to
// normal (this function will also query attributes from the mstyle hierarchy)
// Returns true if there is a style change.
//
// http://www.w3.org/TR/2003/REC-MathML2-20031021/chapter3.html#presm.commatt
//
// "It is important to note that only certain combinations of
// character data and mathvariant attribute values make sense.
// ...
// By design, the only cases that have an unambiguous
// interpretation are exactly the ones that correspond to SMP Math
// Alphanumeric Symbol characters, which are enumerated in Section
// 6.2.3 Mathematical Alphanumeric Symbols Characters. In all other
// cases, it is suggested that renderers ignore the value of the
// mathvariant attribute if it is present."
//
// There are no corresponding characters for mathvariant=normal, suggesting
// that this value should be ignored, but this (from the same section of
// Chapter 3) implies that font-style should not be inherited, but set to
// normal for mathvariant=normal:
//
// "In particular, inheritance of the mathvariant attribute does not follow
// the CSS model. The default value for this attribute is "normal"
// (non-slanted) for all tokens except mi. ... (The deprecated fontslant
// attribute also behaves this way.)"
bool
nsMathMLTokenFrame::SetTextStyle()
{
if (mContent->Tag() != nsGkAtoms::mi_)
return false;
if (!mFrames.FirstChild())
return false;
// Get the text content that we enclose and its length
nsAutoString data;
nsContentUtils::GetNodeTextContent(mContent, false, data);
data.CompressWhitespace();
int32_t length = data.Length();
if (!length)
return false;
nsAutoString fontstyle;
bool isSingleCharacter =
length == 1 ||
(length == 2 && NS_IS_HIGH_SURROGATE(data[0]));
if (isSingleCharacter &&
nsMathMLOperators::LookupInvariantChar(data) != eMATHVARIANT_NONE) {
// bug 65951 - a non-stylable character has its own intrinsic appearance
fontstyle.AssignLiteral("invariant");
}
else {
// Attributes override the default behavior.
nsAutoString value;
if (!(GetAttribute(mContent, mPresentationData.mstyle,
nsGkAtoms::mathvariant_, value) ||
GetAttribute(mContent, mPresentationData.mstyle,
nsGkAtoms::fontstyle_, value))) {
if (!isSingleCharacter) {
fontstyle.AssignLiteral("normal");
}
else if (length == 1 && // BMP
!nsMathMLOperators::
TransformVariantChar(data[0], eMATHVARIANT_italic).
Equals(data)) {
// Transformation exists. Try to make the BMP character look like the
// styled character using the style system until bug 114365 is resolved.
fontstyle.AssignLiteral("italic");
}
// else single character but there is no corresponding Math Alphanumeric
// Symbol character: "ignore the value of the [default] mathvariant
// attribute".
}
}
// set the _moz-math-font-style attribute without notifying that we want a reflow
if (fontstyle.IsEmpty()) {
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_)) {
mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
false);
return true;
}
}
else if (!mContent->AttrValueIs(kNameSpaceID_None,
nsGkAtoms::_moz_math_fontstyle_,
fontstyle, eCaseMatters)) {
mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_fontstyle_,
fontstyle, false);
return true;
}
return false;
}

View File

@ -58,26 +58,10 @@ public:
bool aPlaceOrigin,
nsHTMLReflowMetrics& aDesiredSize) MOZ_OVERRIDE;
virtual void MarkIntrinsicWidthsDirty() MOZ_OVERRIDE;
virtual nsresult
ChildListChanged(int32_t aModType) MOZ_OVERRIDE
{
ProcessTextData();
return nsMathMLContainerFrame::ChildListChanged(aModType);
}
protected:
nsMathMLTokenFrame(nsStyleContext* aContext) : nsMathMLContainerFrame(aContext) {}
virtual ~nsMathMLTokenFrame();
// hook to perform MathML-specific actions depending on the tag
virtual void ProcessTextData();
// helper to set the style of <mi> which has to be italic or normal
// depending on its textual content
bool SetTextStyle();
void MarkTextFramesAsTokenMathML();
};

View File

@ -916,6 +916,7 @@ nsMathMLmoFrame::InheritAutomaticData(nsIFrame* aParent)
// retain our native direction, it only changes if our text content changes
nsStretchDirection direction = mEmbellishData.direction;
nsMathMLTokenFrame::InheritAutomaticData(aParent);
ProcessTextData();
mEmbellishData.direction = direction;
return NS_OK;
}
@ -931,6 +932,19 @@ nsMathMLmoFrame::TransmitAutomaticData()
return NS_OK;
}
NS_IMETHODIMP
nsMathMLmoFrame::SetInitialChildList(ChildListID aListID,
nsFrameList& aChildList)
{
// First, let the parent class do its work
nsresult rv = nsMathMLTokenFrame::SetInitialChildList(aListID, aChildList);
if (NS_FAILED(rv))
return rv;
ProcessTextData();
return rv;
}
NS_IMETHODIMP
nsMathMLmoFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,

View File

@ -38,6 +38,10 @@ public:
NS_IMETHOD
TransmitAutomaticData() MOZ_OVERRIDE;
NS_IMETHOD
SetInitialChildList(ChildListID aListID,
nsFrameList& aChildList) MOZ_OVERRIDE;
NS_IMETHOD
Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -63,6 +67,13 @@ public:
nsBoundingMetrics& aContainerSize,
nsHTMLReflowMetrics& aDesiredStretchSize) MOZ_OVERRIDE;
virtual nsresult
ChildListChanged(int32_t aModType) MOZ_OVERRIDE
{
ProcessTextData();
return nsMathMLContainerFrame::ChildListChanged(aModType);
}
protected:
nsMathMLmoFrame(nsStyleContext* aContext) : nsMathMLTokenFrame(aContext) {}
virtual ~nsMathMLmoFrame();
@ -75,7 +86,7 @@ protected:
bool UseMathMLChar();
// overload the base method so that we can setup our nsMathMLChar
virtual void ProcessTextData() MOZ_OVERRIDE;
void ProcessTextData();
// helper to get our 'form' and lookup in the Operator Dictionary to fetch
// our default data that may come from there, and to complete the setup