Home | History | Annotate | Download | only in speech_rules
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @fileoverview Speech rules for mathml and mathjax nodes.
      7  */
      8 
      9 goog.provide('cvox.MathmlStoreRules');
     10 
     11 goog.require('cvox.MathStore');
     12 goog.require('cvox.MathmlStore');
     13 goog.require('cvox.MathmlStoreUtil');
     14 goog.require('cvox.StoreUtil');
     15 
     16 
     17 /**
     18  * Rule initialization.
     19  * @constructor
     20  */
     21 cvox.MathmlStoreRules = function() {
     22   // Custom functions used in the rules.
     23   cvox.MathmlStoreRules.initCustomFunctions_();
     24   cvox.MathmlStoreRules.initDefaultRules_(); // MathML rules.
     25   cvox.MathmlStoreRules.initMathjaxRules_(); // MathJax Rules
     26   cvox.MathmlStoreRules.initAliases_(); // MathJax Aliases for MathML rules.
     27   cvox.MathmlStoreRules.initSpecializationRules_(); // Square, cube, etc.
     28   cvox.MathmlStoreRules.initSemanticRules_();
     29 };
     30 goog.addSingletonGetter(cvox.MathmlStoreRules);
     31 
     32 
     33 /**
     34  * @type {cvox.MathStore}
     35  */
     36 cvox.MathmlStoreRules.mathStore = cvox.MathmlStore.getInstance();
     37 /**
     38  * @override
     39  */
     40 cvox.MathmlStoreRules.mathStore.initialize = cvox.MathmlStoreRules.getInstance;
     41 
     42 // These are used to work around Closure's rules for aliasing.
     43 /** @private */
     44 cvox.MathmlStoreRules.defineDefaultMathmlRule_ = goog.bind(
     45     cvox.MathmlStoreRules.mathStore.defineDefaultMathmlRule,
     46     cvox.MathmlStoreRules.mathStore);
     47 /** @private */
     48 cvox.MathmlStoreRules.defineRule_ = goog.bind(
     49     cvox.MathmlStoreRules.mathStore.defineRule,
     50     cvox.MathmlStoreRules.mathStore);
     51 /** @private */
     52 cvox.MathmlStoreRules.defineRuleAlias_ = goog.bind(
     53     cvox.MathmlStoreRules.mathStore.defineRuleAlias,
     54     cvox.MathmlStoreRules.mathStore);
     55 /** @private */
     56 cvox.MathmlStoreRules.addContextFunction_ = goog.bind(
     57     cvox.MathmlStoreRules.mathStore.contextFunctions.add,
     58     cvox.MathmlStoreRules.mathStore.contextFunctions);
     59 /** @private */
     60 cvox.MathmlStoreRules.addCustomQuery_ = goog.bind(
     61     cvox.MathmlStoreRules.mathStore.customQueries.add,
     62     cvox.MathmlStoreRules.mathStore.customQueries);
     63 
     64 goog.scope(function() {
     65 var defineDefaultMathmlRule = cvox.MathmlStoreRules.defineDefaultMathmlRule_;
     66 var defineRule = cvox.MathmlStoreRules.defineRule_;
     67 var defineRuleAlias = cvox.MathmlStoreRules.defineRuleAlias_;
     68 
     69 var addCTXF = cvox.MathmlStoreRules.addContextFunction_;
     70 var addCQF = cvox.MathmlStoreRules.addCustomQuery_;
     71 
     72 /**
     73  * Initialize the custom functions.
     74  * @private
     75  */
     76 cvox.MathmlStoreRules.initCustomFunctions_ = function() {
     77   addCTXF('CTXFnodeCounter', cvox.StoreUtil.nodeCounter);
     78   addCTXF('CTXFmfSeparators', cvox.MathmlStoreUtil.mfencedSeparators);
     79   addCTXF('CTXFcontentIterator', cvox.MathmlStoreUtil.contentIterator);
     80 
     81   addCQF('CQFextender', cvox.MathmlStoreUtil.retrieveMathjaxExtender);
     82   addCQF('CQFmathmlmunder', cvox.MathmlStoreUtil.checkMathjaxMunder);
     83   addCQF('CQFmathmlmover', cvox.MathmlStoreUtil.checkMathjaxMover);
     84   addCQF('CQFmathmlmsub', cvox.MathmlStoreUtil.checkMathjaxMsub);
     85   addCQF('CQFmathmlmsup', cvox.MathmlStoreUtil.checkMathjaxMsup);
     86   addCQF('CQFlookupleaf', cvox.MathmlStoreUtil.retrieveMathjaxLeaf);
     87 
     88 };
     89 
     90 
     91 /**
     92  * Initialize the default mathrules.
     93  * @private
     94  */
     95 cvox.MathmlStoreRules.initDefaultRules_ = function() {
     96   // Initial rule
     97   defineDefaultMathmlRule('math', '[m] ./*');
     98 
     99   // Space elements
    100   defineDefaultMathmlRule('mspace', '[p] (pause:250)');
    101   defineDefaultMathmlRule('mstyle', '[m] ./*');
    102   defineDefaultMathmlRule('mpadded', '[m] ./*');
    103   defineDefaultMathmlRule('merror', '[m] ./*');
    104   defineDefaultMathmlRule('mphantom', '[m] ./*');
    105 
    106   // Token elements.
    107   defineDefaultMathmlRule('mtext', '[t] text(); [p] (pause:200)');
    108   defineDefaultMathmlRule('mi', '[n] text()');
    109   defineDefaultMathmlRule('mo', '[n] text() (rate:-0.1)');
    110   defineDefaultMathmlRule('mn', '[n] text()');
    111 
    112   // Dealing with fonts.
    113   defineRule('mtext-variant', 'default.default',
    114       '[t] "begin"; [t] @mathvariant (pause:150);' +
    115           '[t] text() (pause:150); [t] "end"; ' +
    116           '[t] @mathvariant (pause:200)',
    117       'self::mathml:mtext', '@mathvariant', '@mathvariant!="normal"');
    118 
    119   defineRule('mi-variant', 'default.default',
    120       '[t] @mathvariant; [n] text()',
    121       'self::mathml:mi', '@mathvariant', '@mathvariant!="normal"');
    122 
    123   defineRuleAlias('mi-variant', 'self::mathml:mn',  // mn
    124       '@mathvariant', '@mathvariant!="normal"');
    125 
    126   defineRule('mo-variant', 'default.default',
    127       '[t] @mathvariant; [n] text() (rate:-0.1)',
    128       'self::mathml:mo', '@mathvariant', '@mathvariant!="normal"');
    129 
    130   defineDefaultMathmlRule(
    131       'ms',
    132       '[t] "string" (pitch:0.5, rate:0.5); [t] text()');
    133 
    134   // Script elements.
    135   defineDefaultMathmlRule(
    136       'msup', '[n] ./*[1]; [t] "super";' +
    137           '[n] ./*[2] (pitch:0.35); [p] (pause:300)');
    138   defineDefaultMathmlRule(
    139       'msubsup',
    140       '[n] ./*[1]; [t] "sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:200);' +
    141           '[t] "super"; [n] ./*[3] (pitch:0.35); [p] (pause:300)'
    142       );
    143   defineDefaultMathmlRule(
    144       'msub',
    145       '[n] ./*[1]; [t] "sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:300)');
    146   defineDefaultMathmlRule(
    147       'mover', '[n] ./*[2] (pitch:0.35); [p] (pause:200);' +
    148           ' [t] "over"; [n] ./*[1]; [p] (pause:400)');
    149   defineDefaultMathmlRule(
    150       'munder',
    151       '[n] ./*[2] (pitch:-0.35); [t] "under"; [n] ./*[1]; [p] (pause:400)');
    152   defineDefaultMathmlRule(
    153       'munderover',
    154       '[n] ./*[2] (pitch:-0.35); [t] "under and"; [n] ./*[3] (pitch:0.35);' +
    155           ' [t] "over"; [n] ./*[1]; [p] (pause:400)');
    156 
    157   // Layout elements.
    158   defineDefaultMathmlRule('mrow', '[m] ./*');
    159   defineDefaultMathmlRule(
    160       'msqrt', '[t] "Square root of"; [m] ./* (rate:0.2); [p] (pause:400)');
    161   defineDefaultMathmlRule(
    162       'mroot', '[t] "root of order"; [n] ./*[2]; [t] "of";' +
    163           '[n] ./*[1] (rate:0.2); [p] (pause:400)');
    164   defineDefaultMathmlRule(
    165       'mfrac', ' [p] (pause:400); [n] ./*[1] (pitch:0.3);' +
    166           ' [t] "divided by"; [n] ./*[2] (pitch:-0.3); [p] (pause:400)');
    167 
    168 
    169   defineRule(
    170       'mfenced-single', 'default.default',
    171       '[t] @open (context:"opening"); [m] ./* (separator:@separators);' +
    172           '[t] @close (context:"closing")',
    173       'self::mathml:mfenced', 'string-length(string(@separators))=1');
    174 
    175   defineRule(
    176       'mfenced-empty', 'default.default',
    177       '[t] @open (context:"opening"); [m] ./*;' +
    178           '[t] @close (context:"closing")',
    179       'self::mathml:mfenced', 'string-length(string(@separators))=1',
    180       'string(@separators)=" "');
    181 
    182   defineRule(
    183       'mfenced-comma', 'default.default',
    184       '[t] @open (context:"opening"); [m] ./* (separator:"comma");' +
    185           '[t] @close (context:"closing")',
    186       'self::mathml:mfenced');
    187 
    188   defineRule(
    189       'mfenced-multi', 'default.default',
    190       '[t] @open (context:"opening"); [m] ./* (sepFunc:CTXFmfSeparators,' +
    191           'separator:@separators); [t] @close (context:"closing")',
    192       'self::mathml:mfenced', 'string-length(string(@separators))>1');
    193 
    194   // Mtable rules.
    195   defineRule(
    196       'mtable', 'default.default',
    197       '[t] "matrix"; [m] ./* (ctxtFunc:CTXFnodeCounter,' +
    198           'context:"row",pause:100)',
    199       'self::mathml:mtable');
    200 
    201   defineRule(
    202       'mtr', 'default.default',
    203       '[m] ./* (ctxtFunc:CTXFnodeCounter,context:"column",pause:100)',
    204       'self::mathml:mtr');
    205 
    206   defineRule(
    207       'mtd', 'default.default',
    208       '[m] ./*', 'self::mathml:mtd');
    209 
    210   // Mtable superbrief rules.
    211   defineRule(
    212       'mtable', 'default.superbrief',
    213       '[t] count(child::mathml:mtr);  [t] "by";' +
    214           '[t] count(child::mathml:mtr[1]/mathml:mtd); [t] "matrix";',
    215       'self::mathml:mtable');
    216 
    217   // Mtable short rules.
    218   defineRule(
    219       'mtable', 'default.short',
    220       '[t] "matrix"; [m] ./*',
    221       'self::mathml:mtable');
    222 
    223   defineRule(
    224       'mtr', 'default.short',
    225       '[m] ./*', 'self::mathml:mtr');
    226 
    227   defineRule(
    228       'mtd', 'default.short',
    229       '[t] "Element"; [t] count(./preceding-sibling::mathml:mtd)+1;' +
    230           '[t] count(./parent::mathml:mtr/preceding-sibling::mathml:mtr)+1;' +
    231               '[p] (pause:500); [m] ./*',
    232       'self::mathml:mtd');
    233 
    234   // Mmultiscripts rules.
    235   defineRule(
    236       'mmultiscripts-4', 'default.default',
    237       '[n] ./*[1]; [p] (pause:200);' +
    238       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);' +
    239       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:200);' +
    240       '[t] "right sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:200);' +
    241       '[t] "right super"; [n] ./*[3] (pitch:0.35); [p] (pause:300);',
    242       'self::mathml:mmultiscripts');
    243   defineRule(
    244       'mmultiscripts-3-1', 'default.default',
    245       '[n] ./*[1]; [p] (pause:200);' +
    246       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);' +
    247       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:200);' +
    248       '[t] "right super"; [n] ./*[3] (pitch:0.35); [p] (pause:300);',
    249       'self::mathml:mmultiscripts', './mathml:none=./*[2]',
    250       './mathml:mprescripts=./*[4]');
    251   defineRule(
    252       'mmultiscripts-3-2', 'default.default',
    253       '[n] ./*[1]; [p] (pause:200);' +
    254       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);' +
    255       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:200);' +
    256       '[t] "right sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:200);',
    257       'self::mathml:mmultiscripts', './mathml:none=./*[3]',
    258       './mathml:mprescripts=./*[4]');
    259   defineRule(
    260       'mmultiscripts-3-3', 'default.default',
    261       '[n] ./*[1]; [p] (pause:200);' +
    262       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:200);' +
    263       '[t] "right sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:200);' +
    264       '[t] "right super"; [n] ./*[3] (pitch:0.35); [p] (pause:300);',
    265       'self::mathml:mmultiscripts', './mathml:none=./*[5]',
    266       './mathml:mprescripts=./*[4]');
    267   defineRule(
    268       'mmultiscripts-3-4', 'default.default',
    269       '[n] ./*[1]; [p] (pause:200);' +
    270       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);' +
    271       '[t] "right sub"; [n] ./*[2] (pitch:-0.35); [p] (pause:200);' +
    272       '[t] "right super"; [n] ./*[3] (pitch:0.35); [p] (pause:300);',
    273       'self::mathml:mmultiscripts', './mathml:none=./*[6]',
    274       './mathml:mprescripts=./*[4]');
    275   defineRule(
    276       'mmultiscripts-2-1', 'default.default',
    277       '[n] ./*[1]; [p] (pause:200);' +
    278       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);' +
    279       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:300);',
    280       'self::mathml:mmultiscripts', './mathml:none=./*[2]',
    281       './mathml:none=./*[3]', './mathml:mprescripts=./*[4]');
    282   defineRule(
    283       'mmultiscripts-1-1', 'default.default',
    284       '[n] ./*[1]; [p] (pause:200);' +
    285       '[t] "left super"; [n] ./*[6] (pitch:0.35); [p] (pause:300);',
    286       'self::mathml:mmultiscripts', './mathml:none=./*[2]',
    287       './mathml:none=./*[3]', './mathml:mprescripts=./*[4]',
    288       './mathml:none=./*[5]');
    289   defineRule(
    290       'mmultiscripts-1-2', 'default.default',
    291       '[n] ./*[1]; [p] (pause:200);' +
    292       '[t] "left sub"; [n] ./*[5] (pitch:-0.35); [p] (pause:200);',
    293       'self::mathml:mmultiscripts', './mathml:none=./*[2]',
    294       './mathml:none=./*[3]', './mathml:mprescripts=./*[4]',
    295       './mathml:none=./*[6]');
    296 };
    297 
    298 
    299 /**
    300  * Initialize mathJax Rules
    301  * @private
    302  */
    303 cvox.MathmlStoreRules.initMathjaxRules_ = function() {
    304   // Initial rule
    305   defineRule('mj-math', 'default.default',
    306              '[n] ./*[1]/*[1]/*[1]', 'self::span[@class="math"]');
    307 
    308   // Token Elements
    309   defineRule(
    310       'mj-leaf', 'default.default',
    311       '[n] CQFlookupleaf', 'self::span[@class="mi"]');
    312   defineRuleAlias('mj-leaf', 'self::span[@class="mo"]');
    313   defineRuleAlias('mj-leaf', 'self::span[@class="mn"]');
    314   defineRuleAlias('mj-leaf', 'self::span[@class="mtext"]');
    315   defineRule(
    316       'mj-mo-ext', 'default.default',
    317       '[n] CQFextender', 'self::span[@class="mo"]',
    318       './*[1]/*[1]/text()', './*[1]/*[2]/text()');
    319   defineRule(
    320       'mj-texatom', 'default.default',
    321       '[n] ./*[1]', 'self::span[@class="texatom"]');
    322 
    323   // Script elements.
    324   defineRule(
    325       'mj-msubsup', 'default.default',
    326       '[n] ./*[1]/*[1]/*[1]; [t] "sub"; [n] ./*[1]/*[3]/*[1] (pitch:-0.35);' +
    327       '[p] (pause:200); [t] "super"; [n] ./*[1]/*[2]/*[1] (pitch:0.35);' +
    328       '[p] (pause:300)',
    329       'self::span[@class="msubsup"]');
    330   defineRule(
    331       'mj-msub', 'default.default',
    332       '[n] ./*[1]/*[1]/*[1]; [t] "sub";' +
    333           '[n] ./*[1]/*[2]/*[1] (pitch:-0.35); [p] (pause:300)',
    334       'self::span[@class="msub"]');
    335   defineRule(
    336       'mj-msup', 'default.default',
    337       '[n] ./*[1]/*[1]/*[1]; [t] "super";' +
    338           '[n] ./*[1]/*[2]/*[1] (pitch:0.35); [p] (pause:300)',
    339       'self::span[@class="msup"]');
    340   defineRule(
    341       'mj-munderover', 'default.default',
    342       '[n] ./*[1]/*[2]/*[1] (pitch:0.35); [t] "under and";' +
    343           '[n] ./*[1]/*[3]/*[1] (pitch:-0.35); [t] "over";' +
    344               '[n] ./*[1]/*[1]/*[1]; [p] (pause:400)',
    345       'self::span[@class="munderover"]');
    346   defineRule(
    347       'mj-munder', 'default.default',
    348       '[n] ./*[1]/*[2]/*[1] (pitch:0.35); [t] "under";' +
    349           '[n] ./*[1]/*[1]/*[1]; [p] (pause:400)',
    350       'self::span[@class="munder"]');
    351   defineRule(
    352       'mj-mover', 'default.default',
    353       '[n] ./*[1]/*[2]/*[1] (pitch:0.35); [t] "over";' +
    354           '[n] ./*[1]/*[1]/*[1]; [p] (pause:400)',
    355       'self::span[@class="mover"]');
    356 
    357 
    358   // Layout elements.
    359   defineRule(
    360       'mj-mfrac', 'default.default',
    361       '[p] (pause:250); [n] ./*[1]/*[1]/*[1] (pitch:0.3); [p] (pause:250);' +
    362           ' [t] "divided by"; [n] ./*[1]/*[2]/*[1] (pitch:-0.3);' +
    363               '[p] (pause:400)',
    364       'self::span[@class="mfrac"]');
    365   defineRule(
    366       'mj-msqrt', 'default.default',
    367       '[t] "Square root of";' +
    368           '[n] ./*[1]/*[1]/*[1] (rate:0.2); [p] (pause:400)',
    369       'self::span[@class="msqrt"]');
    370   defineRule(
    371       'mj-mroot', 'default.default',
    372       '[t] "root of order"; [n] ./*[1]/*[4]/*[1]; [t] "of";' +
    373           '[n] ./*[1]/*[1]/*[1] (rate:0.2); [p] (pause:400)',
    374       'self::span[@class="mroot"]');
    375 
    376   defineRule(
    377       'mj-mfenced', 'default.default',
    378       '[t] "opening"; [n] ./*[1]; ' +
    379           '[m] ./*[position()>1 and position()<last()];' +
    380               ' [t] "closing"; [n] ./*[last()]',
    381       'self::span[@class="mfenced"]');
    382 
    383   // Mtable short rules.
    384   defineRuleAlias('mj-leaf', 'self::span[@class="mtable"]');
    385   // Mmultiscripts rules.
    386   defineRuleAlias('mj-leaf', 'self::span[@class="mmultiscripts"]');
    387 };
    388 
    389 
    390 /**
    391  * Initialize mathJax Aliases
    392  * @private
    393  */
    394 cvox.MathmlStoreRules.initAliases_ = function() {
    395   // Space elements
    396   defineRuleAlias('mspace', 'self::span[@class="mspace"]');
    397   defineRuleAlias('mstyle', 'self::span[@class="mstyle"]');
    398   defineRuleAlias('mpadded', 'self::span[@class="mpadded"]');
    399   defineRuleAlias('merror', 'self::span[@class="merror"]');
    400   defineRuleAlias('mphantom', 'self::span[@class="mphantom"]');
    401 
    402   // Token elements.
    403   defineRuleAlias('ms', 'self::span[@class="ms"]');
    404 
    405   // Layout elements.
    406   defineRuleAlias('mrow', 'self::span[@class="mrow"]');
    407 
    408   // The following rules fix bugs in MathJax's LaTeX translation.
    409   defineRuleAlias(
    410       'mj-msub', 'self::span[@class="msubsup"]', 'CQFmathmlmsub');
    411 
    412   defineRuleAlias(
    413       'mj-msup', 'self::span[@class="msubsup"]', 'CQFmathmlmsup');
    414 
    415   defineRuleAlias(
    416       'mj-munder', 'self::span[@class="munderover"]', 'CQFmathmlmunder');
    417 
    418   defineRuleAlias(
    419       'mj-mover', 'self::span[@class="munderover"]', 'CQFmathmlmover');
    420 };
    421 
    422 
    423 /**
    424  * Initialize specializations wrt. content of nodes.
    425  * @private
    426  */
    427 cvox.MathmlStoreRules.initSpecializationRules_ = function() {
    428   // Some special nodes for square and cube.
    429   // MathML
    430   defineRule(
    431       'square', 'default.default',
    432       '[n] ./*[1]; [t] "square" (pitch:0.35); [p] (pause:300)',
    433       'self::mathml:msup', './*[2][text()=2]');
    434   defineRuleAlias(
    435       'square', 'self::mathml:msup',
    436       './mathml:mrow=./*[2]', 'count(./*[2]/*)=1', './*[2]/*[1][text()=2]');
    437 
    438   defineRule(
    439       'cube', 'default.default',
    440       '[n] ./*[1]; [t] "cube" (pitch:0.35); [p] (pause:300)',
    441       'self::mathml:msup', './*[2][text()=3]');
    442   defineRuleAlias(
    443       'cube', 'self::mathml:msup',
    444       './mathml:mrow=./*[2]', 'count(./*[2]/*)=1', './*[2]/*[1][text()=3]');
    445 
    446   defineRule(
    447       'square-sub', 'default.default',
    448       '[n] ./*[1]; [t] "sub"; [n] ./*[2] (pitch:-0.35);' +
    449           '[p] (pause:300); [t] "square" (pitch:0.35); [p] (pause:400)',
    450       'self::mathml:msubsup', './*[3][text()=2]');
    451   defineRuleAlias(
    452       'square-sub', 'self::mathml:msubsup',
    453       './mathml:mrow=./*[3]', 'count(./*[3]/*)=1', './*[3]/*[1][text()=2]');
    454 
    455   defineRule(
    456       'cube-sub', 'default.default',
    457       '[n] ./*[1]; [t] "sub"; [n] ./*[2] (pitch:-0.35);' +
    458           '[p] (pause:300); [t] "cube" (pitch:0.35); [p] (pause:400)',
    459       'self::mathml:msubsup', './*[3][text()=3]');
    460   defineRuleAlias(
    461       'cube-sub', 'self::mathml:msubsup',
    462       './mathml:mrow=./*[3]', 'count(./*[3]/*)=1', './*[3]/*[1][text()=3]');
    463 
    464   // MathJax
    465   defineRule(
    466       'mj-square', 'default.default',
    467       '[n] ./*[1]/*[1]/*[1]; [t] "square" (pitch:0.35); [p] (pause:300)',
    468       'self::span[@class="msup"]', './*[1]/*[2]/*[1][text()=2]');
    469   defineRuleAlias(
    470       'mj-square', 'self::span[@class="msup"]',
    471       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    472       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=2]');
    473   defineRuleAlias(
    474       'mj-square', 'self::span[@class="msubsup"]', 'CQFmathmlmsup',
    475       './*[1]/*[2]/*[1][text()=2]');
    476   defineRuleAlias(
    477       'mj-square', 'self::span[@class="msubsup"]', 'CQFmathmlmsup',
    478       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    479       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=2]');
    480 
    481   defineRule(
    482       'mj-cube', 'default.default',
    483       '[n] ./*[1]/*[1]/*[1]; [t] "cube" (pitch:0.35); [p] (pause:300)',
    484       'self::span[@class="msup"]', './*[1]/*[2]/*[1][text()=3]');
    485   defineRuleAlias(
    486       'mj-cube', 'self::span[@class="msup"]',
    487       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    488       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=3]');
    489   defineRuleAlias(
    490       'mj-cube', 'self::span[@class="msubsup"]', 'CQFmathmlmsup',
    491       './*[1]/*[2]/*[1][text()=3]');
    492   defineRuleAlias(
    493       'mj-cube', 'self::span[@class="msubsup"]', 'CQFmathmlmsup',
    494       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    495       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=3]');
    496 
    497   defineRule(
    498       'mj-square-sub', 'default.default',
    499       '[n] ./*[1]/*[1]/*[1]; [t] "sub"; [n] ./*[1]/*[3]/*[1] (pitch:-0.35); ' +
    500           '[p] (pause:300); [t] "square" (pitch:0.35); [p] (pause:400)',
    501       'self::span[@class="msubsup"]', './*[1]/*[2]/*[1][text()=2]');
    502   defineRuleAlias(
    503       'mj-square-sub', 'self::span[@class="msubsup"]',
    504       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    505       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=2]');
    506 
    507   defineRule(
    508       'mj-cube-sub', 'default.default',
    509       '[n] ./*[1]/*[1]/*[1]; [t] "sub"; [n] ./*[1]/*[3]/*[1] (pitch:-0.35); ' +
    510           '[p] (pause:300); [t] "cube" (pitch:0.35); [p] (pause:400)',
    511       'self::span[@class="msubsup"]', './*[1]/*[2]/*[1][text()=3]');
    512   defineRuleAlias(
    513       'mj-cube-sub', 'self::span[@class="msubsup"]',
    514       './*[1]/*[2]/*[1]=./*[1]/*[2]/span[@class="mrow"]',
    515       'count(./*[1]/*[2]/*[1]/*)=1', './*[1]/*[2]/*[1]/*[1][text()=3]');
    516 };
    517 
    518 
    519 /**
    520  * Initialize mathJax Aliases
    521  * @private
    522  */
    523 cvox.MathmlStoreRules.initSemanticRules_ = function() {
    524   // Initial rule
    525   defineRule(
    526       'stree', 'default.default',
    527       '[n] ./*[1]', 'self::stree');
    528 
    529   defineRule(
    530       'multrel', 'default.default',
    531       '[t] "multirelation"; [m] children/* (sepFunc:CTXFcontentIterator)',
    532       'self::multirel');
    533 
    534   defineRule(
    535       'variable-equality', 'default.default',
    536       '[t] "equation sequence"; [m] ./children/* ' +
    537           '(context:"part",ctxtFunc:CTXFnodeCounter,separator:./text())',
    538       'self::relseq[@role="equality"]', 'count(./children/*)>2',
    539       './children/punct[@role="ellipsis"]');// Make that better!
    540 
    541   defineRule(
    542       'multi-equality', 'default.default',
    543       '[t] "equation sequence"; [m] ./children/* ' +
    544           '(context:"part",ctxtFunc:CTXFnodeCounter,separator:./text())',
    545       'self::relseq[@role="equality"]', 'count(./children/*)>2');
    546 
    547   defineRule(
    548       'multi-equality', 'default.short',
    549       '[t] "equation sequence"; [m] ./children/* ' +
    550           '(separator:./text())',
    551       'self::relseq[@role="equality"]', 'count(./children/*)>2');
    552 
    553   defineRule(
    554       'equality', 'default.default',
    555       '[t] "equation"; [t] "left hand side"; [n] children/*[1];' +
    556           '[p] (pause:200); [n] text() (pause:200);' +
    557           '[t] "right hand side"; [n] children/*[2]',
    558       'self::relseq[@role="equality"]', 'count(./children/*)=2');
    559 
    560   defineRule(
    561       'simple-equality', 'default.default',
    562       '[n] children/*[1]; [p] (pause:200); [n] text() (pause:200);' +
    563           '[n] children/*[2]',
    564       'self::relseq[@role="equality"]', 'count(./children/*)=2',
    565       './children/identifier or ./children/number');
    566 
    567   defineRule(
    568       'simple-equality2', 'default.default',
    569       '[n] children/*[1]; [p] (pause:200); [n] text() (pause:200);' +
    570           '[n] children/*[2]',
    571       'self::relseq[@role="equality"]', 'count(./children/*)=2',
    572       './children/function or ./children/appl');
    573 
    574   defineRule(
    575       'multrel', 'default.default',
    576       '[m] children/* (separator:./text())',
    577       'self::relseq');
    578 
    579   defineRule(
    580       'binary-operation', 'default.default',
    581       '[m] children/* (separator:text());',
    582       'self::infixop');
    583 
    584   defineRule(
    585       'variable-addition', 'default.default',
    586       '[t] "sum with variable number of summands";' +
    587           '[p] (pause:400); [m] children/* (separator:./text())',
    588       'self::infixop[@role="addition"]', 'count(children/*)>2',
    589       'children/punct[@role="ellipsis"]');// Make that better!
    590 
    591   defineRule(
    592       'multi-addition', 'default.default',
    593       '[t] "sum with,"; [t] count(./children/*); [t] ", summands";' +
    594           '[p] (pause:400); [m] ./children/* (separator:./text())',
    595       'self::infixop[@role="addition"]', 'count(./children/*)>2');
    596 
    597   // Prefix Operator
    598   defineRule(
    599       'prefix', 'default.default',
    600       '[t] "prefix"; [n] text(); [t] "of" (pause 150);' +
    601       '[n] children/*[1]',
    602       'self::prefixop');
    603 
    604   defineRule(
    605       'negative', 'default.default',
    606       '[t] "negative"; [n] children/*[1]',
    607       'self::prefixop', 'self::prefixop[@role="negative"]');
    608 
    609   // Postfix Operator
    610   defineRule(
    611       'postfix', 'default.default',
    612       '[n] children/*[1]; [t] "postfix"; [n] text() (pause 300)',
    613       'self::postfixop');
    614 
    615   defineRule(
    616       'identifier', 'default.default',
    617       '[n] text()', 'self::identifier');
    618 
    619   defineRule(
    620       'number', 'default.default',
    621       '[n] text()', 'self::number');
    622 
    623   defineRule(
    624       'fraction', 'default.default',
    625       '[p] (pause:250); [n] children/*[1] (pitch:0.3); [p] (pause:250);' +
    626           ' [t] "divided by"; [n] children/*[2] (pitch:-0.3); [p] (pause:400)',
    627       'self::fraction');
    628 
    629   defineRule(
    630       'superscript', 'default.default',
    631       '[n] children/*[1]; [t] "super"; [n] children/*[2] (pitch:0.35);' +
    632       '[p] (pause:300)',
    633       'self::superscript');
    634   defineRule(
    635       'subscript', 'default.default',
    636       '[n] children/*[1]; [t] "sub"; [n] children/*[2] (pitch:-0.35);' +
    637       '[p] (pause:300)',
    638       'self::subscript');
    639 
    640   defineRule(
    641       'ellipsis', 'default.default',
    642       '[p] (pause:200); [t] "dot dot dot"; [p] (pause:300)',
    643       'self::punct', 'self::punct[@role="ellipsis"]');
    644 
    645   defineRule(
    646       'fence-single', 'default.default',
    647       '[n] text()',
    648       'self::punct', 'self::punct[@role="openfence"]');
    649   defineRuleAlias('fence-single', 'self::punct',
    650                   'self::punct[@role="closefence"]');
    651   defineRuleAlias('fence-single', 'self::punct',
    652                   'self::punct[@role="vbar"]');
    653   defineRuleAlias('fence-single', 'self::punct',
    654                   'self::punct[@role="application"]');
    655 
    656   // TODO (sorge) Refine punctuations further.
    657   defineRule(
    658       'omit-punct', 'default.default',
    659       '[p] (pause:200);',
    660       'self::punct');
    661 
    662   defineRule(
    663       'omit-empty', 'default.default',
    664       '',
    665       'self::empty');
    666 
    667   // Fences rules.
    668   defineRule(
    669       'fences-open-close', 'default.default',
    670       '[p] (pause:100); [t] "open"; [n] children/*[1]; [p] (pause:200);' +
    671       '[t] "close"',
    672       'self::fenced[@role="leftright"]');
    673 
    674   defineRule(
    675       'fences-open-close-in-appl', 'default.default',
    676       '[p] (pause:100); [n] children/*[1]; [p] (pause:200);',
    677       'self::fenced[@role="leftright"]', './parent::children/parent::appl');
    678 
    679   defineRule(
    680       'fences-neutral', 'default.default',
    681       '[p] (pause:100); [t] "absolute value of"; [n] children/*[1];' +
    682       '[p] (pause:350);',
    683       'self::fenced', 'self::fenced[@role="neutral"]');
    684 
    685   defineRule(
    686       'omit-fences', 'default.default',
    687       '[p] (pause:500); [n] children/*[1]; [p] (pause:200);',
    688       'self::fenced');
    689 
    690   // Matrix rules.
    691   defineRule(
    692       'matrix', 'default.default',
    693       '[t] "matrix"; [m] children/* ' +
    694       '(ctxtFunc:CTXFnodeCounter,context:"row",pause:100)',
    695       'self::matrix');
    696 
    697   defineRule(
    698       'matrix-row', 'default.default',
    699       '[m] children/* (ctxtFunc:CTXFnodeCounter,context:"column",pause:100)',
    700       'self::row[@role="matrix"]');
    701 
    702   defineRule(
    703       'matrix-cell', 'default.default',
    704       '[n] children/*[1]', 'self::cell[@role="matrix"]');
    705 
    706   // Vector rules.
    707   defineRule(
    708       'vector', 'default.default',
    709       '[t] "vector"; [m] children/* ' +
    710       '(ctxtFunc:CTXFnodeCounter,context:"element",pause:100)',
    711       'self::vector');
    712 
    713   // Cases rules.
    714   defineRule(
    715       'cases', 'default.default',
    716       '[t] "case statement"; [m] children/* ' +
    717       '(ctxtFunc:CTXFnodeCounter,context:"case",pause:100)',
    718       'self::cases');
    719 
    720   defineRule(
    721       'cases-row', 'default.default',
    722       '[m] children/*', 'self::row[@role="cases"]');
    723 
    724   defineRule(
    725       'cases-cell', 'default.default',
    726       '[n] children/*[1]', 'self::cell[@role="cases"]');
    727 
    728   defineRule(
    729       'row', 'default.default',
    730       '[m] ./* (ctxtFunc:CTXFnodeCounter,context:"column",pause:100)',
    731       'self::row"');
    732 
    733   defineRule(
    734       'cases-end', 'default.default',
    735       '[t] "case statement"; ' +
    736       '[m] children/* (ctxtFunc:CTXFnodeCounter,context:"case",pause:100);' +
    737       '[t] "end cases"',
    738       'self::cases', 'following-sibling::*');
    739 
    740   // Multiline rules.
    741   defineRule(
    742       'multiline', 'default.default',
    743       '[t] "multiline equation";' +
    744       '[m] children/* (ctxtFunc:CTXFnodeCounter,context:"line",pause:100)',
    745       'self::multiline');
    746 
    747   defineRule(
    748       'line', 'default.default',
    749       '[m] children/*', 'self::line');
    750 
    751   // Table rules.
    752   defineRule(
    753       'table', 'default.default',
    754       '[t] "multiline equation";' +
    755       '[m] children/* (ctxtFunc:CTXFnodeCounter,context:"row",pause:200)',
    756       'self::table');
    757 
    758   defineRule(
    759       'table-row', 'default.default',
    760       '[m] children/* (pause:100)', 'self::row[@role="table"]');
    761 
    762   defineRuleAlias(
    763       'cases-cell', 'self::cell[@role="table"]');
    764 
    765 
    766   // Rules for punctuated expressions.
    767   defineRule(
    768       'end-punct', 'default.default',
    769       '[m] children/*; [p] (pause:300)',
    770       'self::punctuated', '@role="endpunct"');
    771 
    772   defineRule(
    773       'start-punct', 'default.default',
    774       '[n] content/*[1]; [p] (pause:200); [m] children/*',
    775       'self::punctuated', '@role="startpunct"');
    776 
    777   defineRule(
    778       'integral-punct', 'default.default',
    779       '[n] children/*[1] (rate:0.2); [n] children/*[3] (rate:0.2)',
    780       'self::punctuated', '@role="integral"');
    781 
    782   defineRule(
    783       'punctuated', 'default.default',
    784       '[m] children/* (pause:100)',
    785       'self::punctuated');
    786 
    787   // Function rules
    788   defineRule(
    789     'function', 'default.default',
    790     '[n] text()', 'self::function');
    791 
    792   defineRule(
    793     'appl', 'default.default',
    794     '[n] children/*[1]; [n] content/*[1]; [n] children/*[2]', 'self::appl');
    795 
    796   // Limit operator rules
    797   defineRule(
    798     'limboth', 'default.default',
    799     '[n] children/*[1]; [t] "from"; [n] children/*[2]; [t] "to";' +
    800     '[n] children/*[3]', 'self::limboth');
    801 
    802   defineRule(
    803     'sum-only', 'default.default',
    804     '[n] children/*[1]; [p] (pause 100); [t] "over"; [n] children/*[2];' +
    805     '[p] (pause 250);',
    806     'self::limboth', 'self::limboth[@role="sum"]');
    807 
    808   defineRule(
    809     'limlower', 'default.default',
    810     '[n] children/*[1]; [t] "over"; [n] children/*[2];', 'self::limlower');
    811 
    812   defineRule(
    813     'limupper', 'default.default',
    814     '[n] children/*[1]; [t] "under"; [n] children/*[2];', 'self::limupper');
    815 
    816   // Bigoperator rules
    817   defineRule(
    818     'largeop', 'default.default',
    819     '[n] text()', 'self::largeop');
    820 
    821   defineRule(
    822     'bigop', 'default.default',
    823     '[n] children/*[1]; [p] (pause 100); [t] "over"; [n] children/*[2];' +
    824     '[p] (pause 250);',
    825     'self::bigop');
    826 
    827 
    828   // Integral rules
    829   defineRule(
    830     'integral', 'default.default',
    831     '[n] children/*[1]; [p] (pause 100); [n] children/*[2]; [p] (pause 200);' +
    832     '[n] children/*[3] (rate:0.35);', 'self::integral');
    833 
    834 
    835   defineRule(
    836       'sqrt', 'default.default',
    837       '[t] "Square root of"; [n] children/*[1] (rate:0.2); [p] (pause:400)',
    838       'self::sqrt');
    839 
    840   defineRule(
    841       'square', 'default.default',
    842       '[n] children/*[1]; [t] "square" (pitch:0.35); [p] (pause:300)',
    843       'self::superscript', 'children/*[2][text()=2]');
    844 
    845   defineRule(
    846       'text-no-mult', 'default.default',
    847       '[n] children/*[1]; [p] (pause:200); [n] children/*[2]',
    848       'self::infixop', 'children/text');
    849 };
    850 
    851 }); // goog.scope
    852