<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[207272] branches/safari-602-branch/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/207272">207272</a></dd>
<dt>Author</dt> <dd>matthew_hanson@apple.com</dd>
<dt>Date</dt> <dd>2016-10-12 19:28:49 -0700 (Wed, 12 Oct 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Merge <a href="http://trac.webkit.org/projects/webkit/changeset/205163">r205163</a>. rdar://problem/28216249

    2016-08-29  Brent Fulgham  &lt;bfulgham@apple.com&gt;

    Avoid holding GlyphData in MathOperator
    https://bugs.webkit.org/show_bug.cgi?id=161256
    &lt;rdar://problem/28033400&gt;

    Reviewed by Myles C. Maxfield.

    Do not cache GlyphData in MathOperator elements, because the fonts referenced in the
    GlyphData may be purged during low-memory conditions. Instead, we should store either
    the relevant CodePoint, or the fallback Glyph (for the current system font).

    Added an initialization function for GlyphAssemblyData, since unions containing structs
    do not properly call constructors, resulting in garbage font/glyph content.

    No new tests. Changes are covered by existing MathML test suite.

    * rendering/mathml/MathOperator.cpp:
    (WebCore::MathOperator::GlyphAssemblyData::initialize): Added.
    (WebCore::MathOperator::MathOperator): Initialize m_assembly/m_variant.
    (WebCore::MathOperator::setSizeVariant): Only store the glyph, not the font.
    (WebCore::glyphDataForCodePointOrFallbackGlyph): Added helper function.
    (WebCore::MathOperator::setGlyphAssembly): Do not rely on stored GlyphData.
    (WebCore::MathOperator::calculateGlyphAssemblyFallback): Remove unneeded argument. Check
    if a fallback glyph is being used and remember for later.
    (WebCore::MathOperator::calculateStretchyData): Do not rely on stored GlyphData.
    (WebCore::MathOperator::fillWithVerticalExtensionGlyph): Ditto.
    (WebCore::MathOperator::fillWithHorizontalExtensionGlyph): Ditto.
    (WebCore::MathOperator::paintVerticalGlyphAssembly): Ditto.
    (WebCore::MathOperator::paintHorizontalGlyphAssembly): Ditto.
    (WebCore::MathOperator::paint): Ditto.
    * rendering/mathml/MathOperator.h:
    (WebCore::MathOperator::GlyphAssemblyData::hasExtension): Added.
    (WebCore::MathOperator::GlyphAssemblyData::hasMiddle): Added.
    (WebCore::MathOperator::MathOperator): Deleted.

Patch by Brent Fulgham &lt;bfulgham@apple.com&gt; on 2016-08-25</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari602branchSourceWebCoreChangeLog">branches/safari-602-branch/Source/WebCore/ChangeLog</a></li>
<li><a href="#branchessafari602branchSourceWebCorerenderingmathmlMathOperatorcpp">branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.cpp</a></li>
<li><a href="#branchessafari602branchSourceWebCorerenderingmathmlMathOperatorh">branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari602branchSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-602-branch/Source/WebCore/ChangeLog (207271 => 207272)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-602-branch/Source/WebCore/ChangeLog        2016-10-13 02:28:46 UTC (rev 207271)
+++ branches/safari-602-branch/Source/WebCore/ChangeLog        2016-10-13 02:28:49 UTC (rev 207272)
</span><span class="lines">@@ -1,5 +1,45 @@
</span><span class="cx"> 2016-08-25  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Merge r205163. rdar://problem/28216249
+
+    2016-08-29  Brent Fulgham  &lt;bfulgham@apple.com&gt;
+
+            Avoid holding GlyphData in MathOperator
+            https://bugs.webkit.org/show_bug.cgi?id=161256
+            &lt;rdar://problem/28033400&gt;
+
+            Reviewed by Myles C. Maxfield.
+
+            Do not cache GlyphData in MathOperator elements, because the fonts referenced in the
+            GlyphData may be purged during low-memory conditions. Instead, we should store either
+            the relevant CodePoint, or the fallback Glyph (for the current system font).
+
+            Added an initialization function for GlyphAssemblyData, since unions containing structs
+            do not properly call constructors, resulting in garbage font/glyph content.
+
+            No new tests. Changes are covered by existing MathML test suite.
+
+            * rendering/mathml/MathOperator.cpp:
+            (WebCore::MathOperator::GlyphAssemblyData::initialize): Added.
+            (WebCore::MathOperator::MathOperator): Initialize m_assembly/m_variant.
+            (WebCore::MathOperator::setSizeVariant): Only store the glyph, not the font.
+            (WebCore::glyphDataForCodePointOrFallbackGlyph): Added helper function.
+            (WebCore::MathOperator::setGlyphAssembly): Do not rely on stored GlyphData.
+            (WebCore::MathOperator::calculateGlyphAssemblyFallback): Remove unneeded argument. Check
+            if a fallback glyph is being used and remember for later.
+            (WebCore::MathOperator::calculateStretchyData): Do not rely on stored GlyphData.
+            (WebCore::MathOperator::fillWithVerticalExtensionGlyph): Ditto.
+            (WebCore::MathOperator::fillWithHorizontalExtensionGlyph): Ditto.
+            (WebCore::MathOperator::paintVerticalGlyphAssembly): Ditto.
+            (WebCore::MathOperator::paintHorizontalGlyphAssembly): Ditto.
+            (WebCore::MathOperator::paint): Ditto.
+            * rendering/mathml/MathOperator.h:
+            (WebCore::MathOperator::GlyphAssemblyData::hasExtension): Added.
+            (WebCore::MathOperator::GlyphAssemblyData::hasMiddle): Added.
+            (WebCore::MathOperator::MathOperator): Deleted.
+
+2016-08-25  Brent Fulgham  &lt;bfulgham@apple.com&gt;
+
</ins><span class="cx">         Merge r205031. rdar://problem/28216249
</span><span class="cx"> 
</span><span class="cx">     2016-08-25  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span></span></pre></div>
<a id="branchessafari602branchSourceWebCorerenderingmathmlMathOperatorcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.cpp (207271 => 207272)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.cpp        2016-10-13 02:28:46 UTC (rev 207271)
+++ branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.cpp        2016-10-13 02:28:49 UTC (rev 207272)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2016 Igalia S.L. All rights reserved.
</span><ins>+ * Copyright (C) 2016 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -85,6 +86,24 @@
</span><span class="cx">     { 0x222b, 0x2320, 0x23ae, 0x2321, 0x0    } // integral sign
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+void MathOperator::GlyphAssemblyData::initialize()
+{
+    topOrRightCodePoint = 0;
+    topOrRightFallbackGlyph = 0;
+    extensionCodePoint = 0;
+    extensionFallbackGlyph = 0;
+    bottomOrLeftCodePoint = 0;
+    bottomOrLeftFallbackGlyph = 0;
+    middleCodePoint = 0;
+    middleFallbackGlyph = 0;
+}
+    
+MathOperator::MathOperator()
+{
+    m_assembly.initialize();
+    m_variantGlyph = 0;
+}
+
</ins><span class="cx"> void MathOperator::setOperator(const RenderStyle&amp; style, UChar baseCharacter, Type operatorType)
</span><span class="cx"> {
</span><span class="cx">     m_baseCharacter = baseCharacter;
</span><span class="lines">@@ -132,36 +151,57 @@
</span><span class="cx">     ASSERT(sizeVariant.font);
</span><span class="cx">     ASSERT(sizeVariant.font-&gt;mathData());
</span><span class="cx">     m_stretchType = StretchType::SizeVariant;
</span><del>-    m_variant = sizeVariant;
</del><ins>+    m_variantGlyph = sizeVariant.glyph;
</ins><span class="cx">     m_width = advanceWidthForGlyph(sizeVariant);
</span><span class="cx">     getAscentAndDescentForGlyph(sizeVariant, m_ascent, m_descent);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MathOperator::setGlyphAssembly(const GlyphAssemblyData&amp; assemblyData)
</del><ins>+static GlyphData glyphDataForCodePointOrFallbackGlyph(const RenderStyle&amp; style, UChar32 codePoint, Glyph fallbackGlyph)
</ins><span class="cx"> {
</span><ins>+    if (codePoint)
+        return style.fontCascade().glyphDataForCharacter(codePoint, false);
+    
+    GlyphData fallback;
+    
+    if (fallbackGlyph) {
+        fallback.glyph = fallbackGlyph;
+        fallback.font = &amp;style.fontCascade().primaryFont();
+    }
+    
+    return fallback;
+}
+
+void MathOperator::setGlyphAssembly(const RenderStyle&amp; style, const GlyphAssemblyData&amp; assemblyData)
+{
</ins><span class="cx">     ASSERT(m_operatorType == Type::VerticalOperator || m_operatorType == Type::HorizontalOperator);
</span><span class="cx">     m_stretchType = StretchType::GlyphAssembly;
</span><span class="cx">     m_assembly = assemblyData;
</span><ins>+
+    auto topOrRight = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.topOrRightCodePoint, m_assembly.topOrRightFallbackGlyph);
+    auto extension = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.extensionCodePoint, m_assembly.extensionFallbackGlyph);
+    auto middle = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.middleCodePoint, m_assembly.middleFallbackGlyph);
+    auto bottomOrLeft = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.bottomOrLeftCodePoint, m_assembly.bottomOrLeftFallbackGlyph);
+
</ins><span class="cx">     if (m_operatorType == Type::VerticalOperator) {
</span><span class="cx">         m_width = 0;
</span><del>-        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(m_assembly.topOrRight));
-        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(m_assembly.extension));
-        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(m_assembly.bottomOrLeft));
-        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(m_assembly.middle));
</del><ins>+        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(topOrRight));
+        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(extension));
+        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(bottomOrLeft));
+        m_width = std::max&lt;LayoutUnit&gt;(m_width, advanceWidthForGlyph(middle));
</ins><span class="cx">     } else {
</span><span class="cx">         m_ascent = 0;
</span><span class="cx">         m_descent = 0;
</span><span class="cx">         LayoutUnit ascent, descent;
</span><del>-        getAscentAndDescentForGlyph(m_assembly.bottomOrLeft, ascent, descent);
</del><ins>+        getAscentAndDescentForGlyph(bottomOrLeft, ascent, descent);
</ins><span class="cx">         m_ascent = std::max(m_ascent, ascent);
</span><span class="cx">         m_descent = std::max(m_descent, descent);
</span><del>-        getAscentAndDescentForGlyph(m_assembly.extension, ascent, descent);
</del><ins>+        getAscentAndDescentForGlyph(extension, ascent, descent);
</ins><span class="cx">         m_ascent = std::max(m_ascent, ascent);
</span><span class="cx">         m_descent = std::max(m_descent, descent);
</span><del>-        getAscentAndDescentForGlyph(m_assembly.topOrRight, ascent, descent);
</del><ins>+        getAscentAndDescentForGlyph(topOrRight, ascent, descent);
</ins><span class="cx">         m_ascent = std::max(m_ascent, ascent);
</span><span class="cx">         m_descent = std::max(m_descent, descent);
</span><del>-        getAscentAndDescentForGlyph(m_assembly.middle, ascent, descent);
</del><ins>+        getAscentAndDescentForGlyph(middle, ascent, descent);
</ins><span class="cx">         m_ascent = std::max(m_ascent, ascent);
</span><span class="cx">         m_descent = std::max(m_descent, descent);
</span><span class="cx">     }
</span><span class="lines">@@ -193,7 +233,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MathOperator::calculateGlyphAssemblyFallback(const RenderStyle&amp; style, const Vector&lt;OpenTypeMathData::AssemblyPart&gt;&amp; assemblyParts, GlyphAssemblyData&amp; assemblyData) const
</del><ins>+bool MathOperator::calculateGlyphAssemblyFallback(const Vector&lt;OpenTypeMathData::AssemblyPart&gt;&amp; assemblyParts, GlyphAssemblyData&amp; assemblyData) const
</ins><span class="cx"> {
</span><span class="cx">     // The structure of the Open Type Math table is a bit more general than the one currently used by the MathOperator code, so we try to fallback in a reasonable way.
</span><span class="cx">     // FIXME: MathOperator should support the most general format (https://bugs.webkit.org/show_bug.cgi?id=130327).
</span><span class="lines">@@ -218,8 +258,10 @@
</span><span class="cx">         None
</span><span class="cx">     };
</span><span class="cx">     PartType expectedPartType = Start;
</span><del>-    assemblyData.extension.glyph = 0;
-    assemblyData.middle.glyph = 0;
</del><ins>+    assemblyData.extensionCodePoint = 0;
+    assemblyData.extensionFallbackGlyph = 0;
+    assemblyData.middleCodePoint = 0;
+    assemblyData.middleFallbackGlyph = 0;
</ins><span class="cx">     for (auto&amp; part : assemblyParts) {
</span><span class="cx">         if (nonExtenderCount &lt; 3) {
</span><span class="cx">             // If we only have at most two non-extenders then we skip the middle glyph.
</span><span class="lines">@@ -229,9 +271,9 @@
</span><span class="cx">                 expectedPartType = End;
</span><span class="cx">         }
</span><span class="cx">         if (part.isExtender) {
</span><del>-            if (!assemblyData.extension.glyph)
-                assemblyData.extension.glyph = part.glyph; // We copy the extender part.
-            else if (assemblyData.extension.glyph != part.glyph)
</del><ins>+            if (!assemblyData.extensionFallbackGlyph)
+                assemblyData.extensionFallbackGlyph = part.glyph; // We copy the extender part.
+            else if (assemblyData.extensionFallbackGlyph != part.glyph)
</ins><span class="cx">                 return false; // This is not supported: the assembly has different extenders.
</span><span class="cx"> 
</span><span class="cx">             switch (expectedPartType) {
</span><span class="lines">@@ -257,19 +299,21 @@
</span><span class="cx">         switch (expectedPartType) {
</span><span class="cx">         case Start:
</span><span class="cx">             // We copy the left/bottom part.
</span><del>-            assemblyData.bottomOrLeft.glyph = part.glyph;
</del><ins>+            assemblyData.bottomOrLeftFallbackGlyph = part.glyph;
+            assemblyData.bottomOrLeftCodePoint = 0;
</ins><span class="cx">             expectedPartType = ExtenderBetweenStartAndMiddle;
</span><span class="cx">             continue;
</span><span class="cx">         case ExtenderBetweenStartAndMiddle:
</span><span class="cx">         case Middle:
</span><span class="cx">             // We copy the middle part.
</span><del>-            assemblyData.middle.glyph = part.glyph;
</del><ins>+            assemblyData.middleFallbackGlyph = part.glyph;
</ins><span class="cx">             expectedPartType = ExtenderBetweenMiddleAndEnd;
</span><span class="cx">             continue;
</span><span class="cx">         case ExtenderBetweenMiddleAndEnd:
</span><span class="cx">         case End:
</span><span class="cx">             // We copy the right/top part.
</span><del>-            assemblyData.topOrRight.glyph = part.glyph;
</del><ins>+            assemblyData.topOrRightFallbackGlyph = part.glyph;
+            assemblyData.topOrRightCodePoint = 0;
</ins><span class="cx">             expectedPartType = None;
</span><span class="cx">             continue;
</span><span class="cx">         case None:
</span><span class="lines">@@ -278,20 +322,15 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!assemblyData.extension.glyph)
</del><ins>+    if (!assemblyData.hasExtension())
</ins><span class="cx">         return false; // This is not supported: we always assume that we have an extension glyph.
</span><span class="cx"> 
</span><span class="cx">     // If we don't have top/bottom glyphs, we use the extension glyph.
</span><del>-    if (!assemblyData.topOrRight.glyph)
-        assemblyData.topOrRight.glyph = assemblyData.extension.glyph;
-    if (!assemblyData.bottomOrLeft.glyph)
-        assemblyData.bottomOrLeft.glyph = assemblyData.extension.glyph;
</del><ins>+    if (!assemblyData.topOrRightCodePoint &amp;&amp; !assemblyData.topOrRightFallbackGlyph)
+        assemblyData.topOrRightFallbackGlyph = assemblyData.extensionFallbackGlyph;
+    if (!assemblyData.bottomOrLeftCodePoint &amp;&amp; !assemblyData.bottomOrLeftFallbackGlyph)
+        assemblyData.bottomOrLeftFallbackGlyph = assemblyData.extensionFallbackGlyph;
</ins><span class="cx"> 
</span><del>-    assemblyData.topOrRight.font = &amp;style.fontCascade().primaryFont();
-    assemblyData.extension.font = assemblyData.topOrRight.font;
-    assemblyData.bottomOrLeft.font = assemblyData.topOrRight.font;
-    assemblyData.middle.font = assemblyData.middle.glyph ? assemblyData.topOrRight.font : nullptr;
-
</del><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -331,7 +370,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // We verify if there is a construction.
</span><del>-        if (!calculateGlyphAssemblyFallback(style, assemblyParts, assemblyData))
</del><ins>+        if (!calculateGlyphAssemblyFallback(assemblyParts, assemblyData))
</ins><span class="cx">             return;
</span><span class="cx">     } else {
</span><span class="cx">         if (!isVertical)
</span><span class="lines">@@ -369,29 +408,34 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         // We convert the list of Unicode characters into a list of glyph data.
</span><del>-        assemblyData.topOrRight = style.fontCascade().glyphDataForCharacter(stretchyCharacter-&gt;topChar, false);
-        assemblyData.extension = style.fontCascade().glyphDataForCharacter(stretchyCharacter-&gt;extensionChar, false);
-        assemblyData.bottomOrLeft = style.fontCascade().glyphDataForCharacter(stretchyCharacter-&gt;bottomChar, false);
-        assemblyData.middle = stretchyCharacter-&gt;middleChar ? style.fontCascade().glyphDataForCharacter(stretchyCharacter-&gt;middleChar, false) : GlyphData();
</del><ins>+        assemblyData.topOrRightCodePoint = stretchyCharacter-&gt;topChar;
+        assemblyData.extensionCodePoint = stretchyCharacter-&gt;extensionChar;
+        assemblyData.bottomOrLeftCodePoint = stretchyCharacter-&gt;bottomChar;
+        assemblyData.middleCodePoint = stretchyCharacter-&gt;middleChar;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    auto topOrRight = glyphDataForCodePointOrFallbackGlyph(style, assemblyData.topOrRightCodePoint, assemblyData.topOrRightFallbackGlyph);
+    auto extension = glyphDataForCodePointOrFallbackGlyph(style, assemblyData.extensionCodePoint, assemblyData.extensionFallbackGlyph);
+    auto middle = glyphDataForCodePointOrFallbackGlyph(style, assemblyData.middleCodePoint, assemblyData.middleFallbackGlyph);
+    auto bottomOrLeft = glyphDataForCodePointOrFallbackGlyph(style, assemblyData.bottomOrLeftCodePoint, assemblyData.bottomOrLeftFallbackGlyph);
+
</ins><span class="cx">     // If we are measuring the maximum width, verify each component.
</span><span class="cx">     if (calculateMaxPreferredWidth) {
</span><del>-        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(assemblyData.topOrRight));
-        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(assemblyData.extension));
-        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(assemblyData.middle));
-        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(assemblyData.bottomOrLeft));
</del><ins>+        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(topOrRight));
+        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(extension));
+        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(middle));
+        m_maxPreferredWidth = std::max&lt;LayoutUnit&gt;(m_maxPreferredWidth, advanceWidthForGlyph(bottomOrLeft));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // We ensure that the size is large enough to avoid glyph overlaps.
</span><span class="cx">     float minSize = isVertical ?
</span><del>-        heightForGlyph(assemblyData.topOrRight) + heightForGlyph(assemblyData.middle) + heightForGlyph(assemblyData.bottomOrLeft)
-        : advanceWidthForGlyph(assemblyData.bottomOrLeft) + advanceWidthForGlyph(assemblyData.middle) + advanceWidthForGlyph(assemblyData.topOrRight);
</del><ins>+        heightForGlyph(topOrRight) + heightForGlyph(middle) + heightForGlyph(bottomOrLeft)
+        : advanceWidthForGlyph(bottomOrLeft) + advanceWidthForGlyph(middle) + advanceWidthForGlyph(topOrRight);
</ins><span class="cx">     if (minSize &gt; targetSize)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    setGlyphAssembly(assemblyData);
</del><ins>+    setGlyphAssembly(style, assemblyData);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MathOperator::stretchTo(const RenderStyle&amp; style, LayoutUnit targetSize)
</span><span class="lines">@@ -463,7 +507,10 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_operatorType == Type::VerticalOperator);
</span><span class="cx">     ASSERT(m_stretchType == StretchType::GlyphAssembly);
</span><del>-    ASSERT(m_assembly.extension.font);
</del><ins>+
+    auto extension = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.extensionCodePoint, m_assembly.extensionFallbackGlyph);
+
+    ASSERT(extension.font);
</ins><span class="cx">     ASSERT(from.y() &lt;= to.y());
</span><span class="cx"> 
</span><span class="cx">     // If there is no space for the extension glyph, we don't need to do anything.
</span><span class="lines">@@ -472,7 +519,7 @@
</span><span class="cx"> 
</span><span class="cx">     GraphicsContextStateSaver stateSaver(info.context());
</span><span class="cx"> 
</span><del>-    FloatRect glyphBounds = boundsForGlyph(m_assembly.extension);
</del><ins>+    FloatRect glyphBounds = boundsForGlyph(extension);
</ins><span class="cx"> 
</span><span class="cx">     // Clipping the extender region here allows us to draw the bottom extender glyph into the
</span><span class="cx">     // regions of the bottom glyph without worrying about overdraw (hairy pixels) and simplifies later clipping.
</span><span class="lines">@@ -488,7 +535,7 @@
</span><span class="cx"> 
</span><span class="cx">     // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
</span><span class="cx">     for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxY() &lt; to.y() &amp;&amp; extensionCount &lt; kMaximumExtensionCount; extensionCount++) {
</span><del>-        lastPaintedGlyphRect = paintGlyph(style, info, m_assembly.extension, glyphOrigin, TrimTopAndBottom);
</del><ins>+        lastPaintedGlyphRect = paintGlyph(style, info, extension, glyphOrigin, TrimTopAndBottom);
</ins><span class="cx">         glyphOrigin.setY(glyphOrigin.y() + lastPaintedGlyphRect.height());
</span><span class="cx"> 
</span><span class="cx">         // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
</span><span class="lines">@@ -502,7 +549,10 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_operatorType == Type::HorizontalOperator);
</span><span class="cx">     ASSERT(m_stretchType == StretchType::GlyphAssembly);
</span><del>-    ASSERT(m_assembly.extension.font);
</del><ins>+
+    auto extension = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.extensionCodePoint, m_assembly.extensionFallbackGlyph);
+
+    ASSERT(extension.font);
</ins><span class="cx">     ASSERT(from.x() &lt;= to.x());
</span><span class="cx">     ASSERT(from.y() == to.y());
</span><span class="cx"> 
</span><span class="lines">@@ -526,7 +576,7 @@
</span><span class="cx"> 
</span><span class="cx">     // In practice, only small stretch sizes are requested but we limit the number of glyphs to avoid hangs.
</span><span class="cx">     for (unsigned extensionCount = 0; lastPaintedGlyphRect.maxX() &lt; to.x() &amp;&amp; extensionCount &lt; kMaximumExtensionCount; extensionCount++) {
</span><del>-        lastPaintedGlyphRect = paintGlyph(style, info, m_assembly.extension, glyphOrigin, TrimLeftAndRight);
</del><ins>+        lastPaintedGlyphRect = paintGlyph(style, info, extension, glyphOrigin, TrimLeftAndRight);
</ins><span class="cx">         glyphOrigin.setX(glyphOrigin.x() + lastPaintedGlyphRect.width());
</span><span class="cx"> 
</span><span class="cx">         // There's a chance that if the font size is small enough the glue glyph has been reduced to an empty rectangle
</span><span class="lines">@@ -540,27 +590,33 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_operatorType == Type::VerticalOperator);
</span><span class="cx">     ASSERT(m_stretchType == StretchType::GlyphAssembly);
</span><del>-    ASSERT(m_assembly.topOrRight.font);
-    ASSERT(m_assembly.bottomOrLeft.font);
</del><span class="cx"> 
</span><ins>+    auto topOrRight = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.topOrRightCodePoint, m_assembly.topOrRightFallbackGlyph);
+    auto bottomOrLeft = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.bottomOrLeftCodePoint, m_assembly.bottomOrLeftFallbackGlyph);
+
+    ASSERT(topOrRight.font);
+    ASSERT(bottomOrLeft.font);
+
</ins><span class="cx">     // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
</span><span class="cx">     LayoutPoint operatorTopLeft = paintOffset;
</span><del>-    FloatRect topGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
</del><ins>+    FloatRect topGlyphBounds = boundsForGlyph(topOrRight);
</ins><span class="cx">     LayoutPoint topGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() - topGlyphBounds.y());
</span><del>-    LayoutRect topGlyphPaintRect = paintGlyph(style, info, m_assembly.topOrRight, topGlyphOrigin, TrimBottom);
</del><ins>+    LayoutRect topGlyphPaintRect = paintGlyph(style, info, topOrRight, topGlyphOrigin, TrimBottom);
</ins><span class="cx"> 
</span><del>-    FloatRect bottomGlyphBounds = boundsForGlyph(m_assembly.bottomOrLeft);
</del><ins>+    FloatRect bottomGlyphBounds = boundsForGlyph(bottomOrLeft);
</ins><span class="cx">     LayoutPoint bottomGlyphOrigin(operatorTopLeft.x(), operatorTopLeft.y() + stretchSize() - (bottomGlyphBounds.height() + bottomGlyphBounds.y()));
</span><del>-    LayoutRect bottomGlyphPaintRect = paintGlyph(style, info, m_assembly.bottomOrLeft, bottomGlyphOrigin, TrimTop);
</del><ins>+    LayoutRect bottomGlyphPaintRect = paintGlyph(style, info, bottomOrLeft, bottomGlyphOrigin, TrimTop);
</ins><span class="cx"> 
</span><del>-    if (m_assembly.middle.font) {
</del><ins>+    if (m_assembly.hasMiddle()) {
+        auto middle = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.middleCodePoint, m_assembly.middleFallbackGlyph);
+
</ins><span class="cx">         // Center the glyph origin between the start and end glyph paint extents. Then shift it half the paint height toward the bottom glyph.
</span><del>-        FloatRect middleGlyphBounds = boundsForGlyph(m_assembly.middle);
</del><ins>+        FloatRect middleGlyphBounds = boundsForGlyph(middle);
</ins><span class="cx">         LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), topGlyphOrigin.y());
</span><span class="cx">         middleGlyphOrigin.moveBy(LayoutPoint(0, (bottomGlyphPaintRect.y() - topGlyphPaintRect.maxY()) / 2.0));
</span><span class="cx">         middleGlyphOrigin.moveBy(LayoutPoint(0, middleGlyphBounds.height() / 2.0));
</span><span class="cx"> 
</span><del>-        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, m_assembly.middle, middleGlyphOrigin, TrimTopAndBottom);
</del><ins>+        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, middle, middleGlyphOrigin, TrimTopAndBottom);
</ins><span class="cx">         fillWithVerticalExtensionGlyph(style, info, topGlyphPaintRect.minXMaxYCorner(), middleGlyphPaintRect.minXMinYCorner());
</span><span class="cx">         fillWithVerticalExtensionGlyph(style, info, middleGlyphPaintRect.minXMaxYCorner(), bottomGlyphPaintRect.minXMinYCorner());
</span><span class="cx">     } else
</span><span class="lines">@@ -571,24 +627,30 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_operatorType == Type::HorizontalOperator);
</span><span class="cx">     ASSERT(m_stretchType == StretchType::GlyphAssembly);
</span><del>-    ASSERT(m_assembly.bottomOrLeft.font);
-    ASSERT(m_assembly.topOrRight.font);
</del><span class="cx"> 
</span><ins>+    auto topOrRight = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.topOrRightCodePoint, m_assembly.topOrRightFallbackGlyph);
+    auto bottomOrLeft = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.bottomOrLeftCodePoint, m_assembly.bottomOrLeftFallbackGlyph);
+
+    ASSERT(bottomOrLeft.font);
+    ASSERT(topOrRight.font);
+
</ins><span class="cx">     // We are positioning the glyphs so that the edge of the tight glyph bounds line up exactly with the edges of our paint box.
</span><span class="cx">     LayoutPoint operatorTopLeft = paintOffset;
</span><span class="cx">     LayoutUnit baselineY = operatorTopLeft.y() + m_ascent;
</span><span class="cx">     LayoutPoint leftGlyphOrigin(operatorTopLeft.x(), baselineY);
</span><del>-    LayoutRect leftGlyphPaintRect = paintGlyph(style, info, m_assembly.bottomOrLeft, leftGlyphOrigin, TrimRight);
</del><ins>+    LayoutRect leftGlyphPaintRect = paintGlyph(style, info, bottomOrLeft, leftGlyphOrigin, TrimRight);
</ins><span class="cx"> 
</span><del>-    FloatRect rightGlyphBounds = boundsForGlyph(m_assembly.topOrRight);
</del><ins>+    FloatRect rightGlyphBounds = boundsForGlyph(topOrRight);
</ins><span class="cx">     LayoutPoint rightGlyphOrigin(operatorTopLeft.x() + stretchSize() - rightGlyphBounds.width(), baselineY);
</span><del>-    LayoutRect rightGlyphPaintRect = paintGlyph(style, info, m_assembly.topOrRight, rightGlyphOrigin, TrimLeft);
</del><ins>+    LayoutRect rightGlyphPaintRect = paintGlyph(style, info, topOrRight, rightGlyphOrigin, TrimLeft);
</ins><span class="cx"> 
</span><del>-    if (m_assembly.middle.font) {
</del><ins>+    if (m_assembly.hasMiddle()) {
+        auto middle = glyphDataForCodePointOrFallbackGlyph(style, m_assembly.middleCodePoint, m_assembly.middleFallbackGlyph);
+
</ins><span class="cx">         // Center the glyph origin between the start and end glyph paint extents.
</span><span class="cx">         LayoutPoint middleGlyphOrigin(operatorTopLeft.x(), baselineY);
</span><span class="cx">         middleGlyphOrigin.moveBy(LayoutPoint((rightGlyphPaintRect.x() - leftGlyphPaintRect.maxX()) / 2.0, 0));
</span><del>-        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, m_assembly.middle, middleGlyphOrigin, TrimLeftAndRight);
</del><ins>+        LayoutRect middleGlyphPaintRect = paintGlyph(style, info, middle, middleGlyphOrigin, TrimLeftAndRight);
</ins><span class="cx">         fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(leftGlyphPaintRect.maxX(), baselineY), LayoutPoint(middleGlyphPaintRect.x(), baselineY));
</span><span class="cx">         fillWithHorizontalExtensionGlyph(style, info, LayoutPoint(middleGlyphPaintRect.maxX(), baselineY), LayoutPoint(rightGlyphPaintRect.x(), baselineY));
</span><span class="cx">     } else
</span><span class="lines">@@ -623,13 +685,11 @@
</span><span class="cx"> 
</span><span class="cx">     GlyphData glyphData;
</span><span class="cx">     ASSERT(m_stretchType == StretchType::Unstretched || m_stretchType == StretchType::SizeVariant);
</span><del>-    if (m_stretchType == StretchType::Unstretched) {
-        if (!getBaseGlyph(style, glyphData))
-            return;
-    } else if (m_stretchType == StretchType::SizeVariant) {
-        ASSERT(m_variant.font);
-        glyphData = m_variant;
-    }
</del><ins>+    if (!getBaseGlyph(style, glyphData))
+        return;
+    if (m_stretchType == StretchType::SizeVariant)
+        glyphData.glyph = m_variantGlyph;
+
</ins><span class="cx">     GlyphBuffer buffer;
</span><span class="cx">     buffer.add(glyphData.glyph, glyphData.font, advanceWidthForGlyph(glyphData));
</span><span class="cx">     LayoutPoint operatorTopLeft = paintOffset;
</span></span></pre></div>
<a id="branchessafari602branchSourceWebCorerenderingmathmlMathOperatorh"></a>
<div class="modfile"><h4>Modified: branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.h (207271 => 207272)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.h        2016-10-13 02:28:46 UTC (rev 207271)
+++ branches/safari-602-branch/Source/WebCore/rendering/mathml/MathOperator.h        2016-10-13 02:28:49 UTC (rev 207272)
</span><span class="lines">@@ -1,5 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx">  * Copyright (C) 2016 Igalia S.L. All rights reserved.
</span><ins>+ * Copyright (C) 2016 Apple Inc.  All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -38,7 +39,7 @@
</span><span class="cx"> 
</span><span class="cx"> class MathOperator {
</span><span class="cx"> public:
</span><del>-    MathOperator() { }
</del><ins>+    MathOperator();
</ins><span class="cx">     enum class Type { NormalOperator, DisplayOperator, VerticalOperator, HorizontalOperator };
</span><span class="cx">     void setOperator(const RenderStyle&amp;, UChar baseCharacter, Type);
</span><span class="cx">     void reset(const RenderStyle&amp;);
</span><span class="lines">@@ -56,10 +57,18 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     struct GlyphAssemblyData {
</span><del>-        GlyphData topOrRight;
-        GlyphData extension;
-        GlyphData bottomOrLeft;
-        GlyphData middle;
</del><ins>+        UChar32 topOrRightCodePoint { 0 };
+        Glyph topOrRightFallbackGlyph { 0 };
+        UChar32 extensionCodePoint { 0 };
+        Glyph extensionFallbackGlyph { 0 };
+        UChar32 bottomOrLeftCodePoint { 0 };
+        Glyph bottomOrLeftFallbackGlyph { 0 };
+        UChar32 middleCodePoint { 0 };
+        Glyph middleFallbackGlyph { 0 };
+
+        bool hasExtension() const { return extensionCodePoint || extensionFallbackGlyph; }
+        bool hasMiddle() const { return middleCodePoint || middleFallbackGlyph; }
+        void initialize();
</ins><span class="cx">     };
</span><span class="cx">     enum class StretchType { Unstretched, SizeVariant, GlyphAssembly };
</span><span class="cx">     enum GlyphPaintTrimming {
</span><span class="lines">@@ -74,11 +83,12 @@
</span><span class="cx">     LayoutUnit stretchSize() const;
</span><span class="cx">     bool getBaseGlyph(const RenderStyle&amp;, GlyphData&amp;) const;
</span><span class="cx">     void setSizeVariant(const GlyphData&amp;);
</span><del>-    void setGlyphAssembly(const GlyphAssemblyData&amp;);
</del><ins>+    void setGlyphAssembly(const RenderStyle&amp;, const GlyphAssemblyData&amp;);
</ins><span class="cx">     void calculateDisplayStyleLargeOperator(const RenderStyle&amp;);
</span><span class="cx">     void calculateStretchyData(const RenderStyle&amp;, bool calculateMaxPreferredWidth, LayoutUnit targetSize = 0);
</span><del>-    bool calculateGlyphAssemblyFallback(const RenderStyle&amp;, const Vector&lt;OpenTypeMathData::AssemblyPart&gt;&amp;, GlyphAssemblyData&amp;) const;
</del><ins>+    bool calculateGlyphAssemblyFallback(const Vector&lt;OpenTypeMathData::AssemblyPart&gt;&amp;, GlyphAssemblyData&amp;) const;
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     LayoutRect paintGlyph(const RenderStyle&amp;, PaintInfo&amp;, const GlyphData&amp;, const LayoutPoint&amp; origin, GlyphPaintTrimming);
</span><span class="cx">     void fillWithVerticalExtensionGlyph(const RenderStyle&amp;, PaintInfo&amp;, const LayoutPoint&amp; from, const LayoutPoint&amp; to);
</span><span class="cx">     void fillWithHorizontalExtensionGlyph(const RenderStyle&amp;, PaintInfo&amp;, const LayoutPoint&amp; from, const LayoutPoint&amp; to);
</span><span class="lines">@@ -89,7 +99,7 @@
</span><span class="cx">     Type m_operatorType { Type::NormalOperator };
</span><span class="cx">     StretchType m_stretchType { StretchType::Unstretched };
</span><span class="cx">     union {
</span><del>-        GlyphData m_variant;
</del><ins>+        Glyph m_variantGlyph;
</ins><span class="cx">         GlyphAssemblyData m_assembly;
</span><span class="cx">     };
</span><span class="cx">     LayoutUnit m_maxPreferredWidth { 0 };
</span></span></pre>
</div>
</div>

</body>
</html>