[Sie-announce] SIEコード [2041] tspan要素の実装とtext要素のバグを修正

Back to archive index

svnno****@sourc***** svnno****@sourc*****
2010年 10月 7日 (木) 19:15:02 JST


Revision: 2041
          http://sourceforge.jp/projects/sie/svn/view?view=rev&revision=2041
Author:   dhrname
Date:     2010-10-07 19:15:02 +0900 (Thu, 07 Oct 2010)

Log Message:
-----------
tspan要素の実装とtext要素のバグを修正

Modified Paths:
--------------
    branches/06x/061/org/w3c/dom/svg.js

Modified: branches/06x/061/org/w3c/dom/svg.js
===================================================================
--- branches/06x/061/org/w3c/dom/svg.js	2010-10-05 13:54:09 UTC (rev 2040)
+++ branches/06x/061/org/w3c/dom/svg.js	2010-10-07 10:15:02 UTC (rev 2041)
@@ -3250,8 +3250,10 @@
 
 function SVGTextContentElement() { 
   SVGElement.apply(this);
-  this._list = [];  //文字の位置を格納しておくリスト
-  this._length = 0; //全文字数
+  this._list = null;         //文字の位置を格納しておくリストのキャッシュ
+  this._length = 0;          //全文字数
+  this._stx = this._sty = 0; //初めの文字の位置
+  this._chars = 0;           //tspan要素が全体の何文字目から始まっているか
   /*readonly SVGAnimatedLength*/      this.textLength = new SVGAnimatedLength();
   /*readonly SVGAnimatedEnumeration*/ this.lengthAdjust = new SVGAnimatedEnumeration(SVGTextContentElement.LENGTHADJUST_UNKNOWN);
   this._isYokogaki = true;
@@ -3327,6 +3329,136 @@
   if (charnum > this.getNumberOfChars() || charnum < 0) {
     throw (new DOMException(DOMException.INDEX_SIZE_ERR));
   } else {
+    var tar = this, ti = tar.firstChild, tp = tar.parentNode;
+    if (!!!tar._list) {
+      tar._list = [];
+      var chars = tar._chars; //現在、何文字目にあるのか
+      var x = tar._stx, y = tar._sty, n = 0; //現在のテキスト位置と順番
+      var style = tar.ownerDocument.defaultView.getComputedStyle(tar, null);
+      var isYokogaki = ((style.getPropertyValue("writing-mode")) === "lr-tb") ? true : false;
+      var fontSize = parseFloat(style.getPropertyValue("font-size"));
+      var tx = tar.x.baseVal, ty = tar.y.baseVal, tdx = tar.dx.baseVal, tdy = tar.dy.baseVal;
+      /*親要素の属性も参照しておく*/
+      var isText = tp.localName === "text";
+      if (tp && (isText ||(tp.localName === "tspan"))) {
+        var ptx = tp.x.baseVal, pty = tp.y.baseVal, ptdx = tp.dx.baseVal, ptdy = tp.dy.baseVal;
+      } else {
+        var ptx = pty = ptdx = ptdy = {numberOfItems : 0};
+      }
+      var kern = "f ijltIr.,:;'-\"()", akern = "1234567890abcdeghknopquvxyz";
+      if (isYokogaki && isText) {
+        y += fontSize * 0.2;
+      } else if (isText){
+        x -= fontSize * 0.5;
+      }
+      while (ti) {
+        if (ti.nodeType === Node.TEXT_NODE) {
+          var tt = ti._tars;
+          /*tspan要素のx属性で指定された座標の個数よりも、文字数が多い場合は、祖先(親)のx属性を
+           *使う。また、属性が指定されていないときも同様に祖先や親を使う。
+           *もし、仮に祖先や親がx属性を指定されていなければ、現在のテキスト位置(変数xに格納している)を使う。
+           *この処理はdx属性やdy、y属性でも同様とする
+           *参照資料SVG1.1 Text
+           *http://www.hcn.zaq.ne.jp/___/REC-SVG11-20030114/text.html
+           *
+           *注意:ここでは、tspan要素だけではなく、text要素にも適用しているが、本来はtspan要素のみに処理させること
+           */
+          for (var i=0, tli=tt.length;i<tli;++i) {
+            if (n < ptx.numberOfItems - chars) {
+              x = ptx.getItem(n).value;
+              if (!isYokogaki) {
+                x -= fontSize * 0.5;
+              }
+            } else if (n < tx.numberOfItems) {
+              x = tx.getItem(n).value;
+              if (!isYokogaki) {
+                x -= fontSize * 0.5;
+              }
+            }
+            if (n < pty.numberOfItems - chars) {
+              y = pty.getItem(n).value;
+              if (isYokogaki) {
+                y += fontSize * 0.2;
+              }
+            } else if (n < ty.numberOfItems) {
+              y = ty.getItem(n).value;
+              if (isYokogaki) {
+                y += fontSize * 0.2;
+              }
+            }
+            if (n < ptdx.numberOfItems - chars) {
+              x += ptdx.getItem(n).value;
+            } else if (n < tdx.numberOfItems) {
+              x += tdx.getItem(n).value;
+            }
+            if (n < ptdy.numberOfItems - chars) {
+              y += ptdy.getItem(n).value;
+            } else if (n < tdy.numberOfItems) {
+              y += tdy.getItem(n).value;
+            }
+            var alm = 0;
+            if (isYokogaki) {
+              //カーニングを求めて、字の幅を文字ごとに調整する
+              var tdc = ti.data.charAt(i);
+              if (kern.indexOf(tdc) > -1) {
+                alm = fontSize * 0.68;
+              } else if (tdc === "s"){
+                alm = fontSize * 0.52;
+              } else if ((tdc === "C") || (tdc === "D") || (tdc === "M") || (tdc === "W") || (tdc === "G") || (tdc === "m")){
+                alm = fontSize * 0.2;
+              } else if (akern.indexOf(tdc) > -1){
+                alm = fontSize * 0.45;
+              } else {
+                alm = fontSize * 0.3;
+              }
+              var tcca = tdc.charCodeAt(0);
+              if ((12288 <= tcca) && (tcca <= 65533)) {
+                alm = -fontSize * 0.01;
+                if ((tdc === "う") || (tdc === "く") || (tdc === "し") || (tdc === "ち")) {
+                  alm += fontSize * 0.2;
+                }
+              }
+              tcca = null;
+            }
+            tar._list[tar._list.length] = x;
+            tar._list[tar._list.length] = y;
+            tar._list[tar._list.length] = fontSize - alm;
+            if (isYokogaki) {
+              x += fontSize;
+              x -= alm;
+            } else {
+              y += fontSize;
+            }
+            ++n;
+          }
+          chars += tli;
+        } else if ((ti.localName === "tspan") && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
+          /*現在のテキスト位置(x,y)の分だけ、tspan要素をずらしておく。
+           *さらに、現在のテキスト位置を更新する
+           */
+          ti._stx = x;
+          ti._sty = y;
+          ti._chars = chars;
+          var p = ti.getStartPositionOfChar(ti.getNumberOfChars());
+          var almx = 0, almy = 0;
+          if (isYokogaki) {
+            almx = ti._list[ti._list.length-1];
+          } else {
+            almy = ti._list[ti._list.length-1];
+          }
+          x = ti._list[ti._list.length-3] + almx;
+          y = ti._list[ti._list.length-2] + almy;
+          tar._list = tar._list.concat(ti._list);
+          var tg = ti.getNumberOfChars();
+          n += tg;
+          chars += tg;
+          p = tg = null;
+        }
+        ti = ti.nextSibling;
+      }
+      tar._isYokogaki = isYokogaki //getEndPositionOfCharメソッドなどで使う
+      tar = ti = tp = ptx = pty = tx = ty = chars = style = x = y = isYokogaki = null;
+    }
     var s = this.ownerDocument.documentElement.createSVGPoint();
     s.x = this._list[charnum*3];
     s.y = this._list[charnum*3 + 1];
@@ -3414,140 +3546,17 @@
         tea.newValueSpecifiedUnits(type, s);
         teas.appendItem(tea);
       }
+      tar._list = null;
     }
     evt = tar = null;
   }, false);
   this.addEventListener("DOMNodeInserted", function(evt){
     if (evt.eventPhase === Event.BUBBLING_PHASE) {
-      var tar = evt.target, ttn = 2;
-      if ((tar.nodeType === Node.TEXT_NODE)) {
-        /*もし、仮にテキストノードであれば、以下のループ処理については、
-         *currentTargetの一回だけで済ますようにする
-         */
-        tar = evt.currentTarget;
-        ttn = 1;
+      var tar = evt.target;
+      if (tar.nodeType !== Node.TEXT_NODE) {
+        tar._list = null;
+        evt.currentTarget._list = null;
       }
-      for (var k=0;k<ttn;++k) {
-        var  ti = tar.firstChild, tp = tar.parentNode;
-        tar._list = [];          //リストの初期化
-        var x = 0, y = 0, n = 0; //現在のテキスト位置と順番
-        var style = tar.ownerDocument.defaultView.getComputedStyle(tar, null);
-        var isYokogaki = ((style.getPropertyValue("writing-mode")) === "lr-tb") ? true : false;
-        var fontSize = parseFloat(style.getPropertyValue("font-size"));
-        var tx = tar.x.baseVal, ty = tar.y.baseVal, tdx = tar.dx.baseVal, tdy = tar.dy.baseVal;
-        /*親要素の属性も参照しておく*/
-        if (tp && ((tp.localName === "text")||(tp.localName === "tspan"))) {
-          var ptx = tp.x.baseVal, pty = tp.y.baseVal, ptdx = tp.dx.baseVal, ptdy = tp.dy.baseVal;
-        } else {
-          var ptx = pty = ptdx = ptdy = {numberOfItems : 0};
-        }
-        var kern = "f ijltIr.,:;'-\"()", akern = "1234567890abcdeghknopquvxyz";
-        if (isYokogaki) {
-          y += fontSize * 0.2;
-        } else {
-          x -= fontSize * 0.5;
-        }
-        while (ti) {
-          if (ti.nodeType === Node.TEXT_NODE) {
-            var tt = ti._tars;
-            /*tspan要素のx属性で指定された座標の個数よりも、文字数が多い場合は、祖先(親)のx属性を
-             *使う。また、属性が指定されていないときも同様に祖先や親を使う。
-             *もし、仮に祖先や親がx属性を指定されていなければ、現在のテキスト位置(変数xに格納している)を使う。
-             *この処理はdx属性やdy、y属性でも同様とする
-             *参照資料SVG1.1 Text
-             *http://www.hcn.zaq.ne.jp/___/REC-SVG11-20030114/text.html
-             *
-             *注意:ここでは、tspan要素だけではなく、text要素にも適用しているが、本来はtspan要素のみに処理させること
-             */
-            for (var i=0, tli=tt.length;i<tli;++i) {
-              if (n < ptx.numberOfItems) {
-                x = ptx.getItem(n).value;
-                if (!isYokogaki) {
-                  x -= fontSize * 0.5;
-                }
-              } else if (n < tx.numberOfItems) {
-                x = tx.getItem(n).value;
-                if (!isYokogaki) {
-                  x -= fontSize * 0.5;
-                }
-              }
-              if (n < pty.numberOfItems) {
-                y = pty.getItem(n).value;
-                if (isYokogaki) {
-                  y += fontSize * 0.2;
-                }
-              } else if (n < ty.numberOfItems) {
-                y = ty.getItem(n).value;
-                if (isYokogaki) {
-                  y += fontSize * 0.2;
-                }
-              }
-              if (n < ptdx.numberOfItems) {
-                x += ptdx.getItem(n).value;
-              } else if (n < tdx.numberOfItems) {
-                x += tdx.getItem(n).value;
-              }
-              if (n < ptdy.numberOfItems) {
-                y += ptdy.getItem(n).value;
-              } else if (n < tdy.numberOfItems) {
-                y += tdy.getItem(n).value;
-              }
-              var alm = 0;
-              if (isYokogaki) {
-                //カーニングを求めて、字の幅を文字ごとに調整する
-                var tdc = ti.data.charAt(i);
-                if (kern.indexOf(tdc) > -1) {
-                  alm = fontSize * 0.68;
-                } else if (tdc === "s"){
-                  alm = fontSize * 0.52;
-                } else if ((tdc === "C") || (tdc === "D") || (tdc === "M") || (tdc === "W") || (tdc === "G") || (tdc === "m")){
-                  alm = fontSize * 0.2;
-                } else if (akern.indexOf(tdc) > -1){
-                  alm = fontSize * 0.45;
-                } else {
-                  alm = fontSize * 0.3;
-                }
-                var tcca = tdc.charCodeAt(0);
-                if ((12288 <= tcca) && (tcca <= 65533)) {
-                  alm = -fontSize * 0.01;
-                  if ((tdc === "う") || (tdc === "く") || (tdc === "し") || (tdc === "ち")) {
-                    alm += fontSize * 0.2;
-                  }
-                }
-                tcca = null;
-              }
-              tar._list[tar._list.length] = x;
-              tar._list[tar._list.length] = y;
-              tar._list[tar._list.length] = fontSize - alm;
-              if (isYokogaki) {
-                x += fontSize;
-                x -= alm;
-              } else {
-                y += fontSize;
-              }
-              ++n;
-            }
-          } else if ((ti.localName === "tspan") && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
-            /*現在のテキスト位置(x,y)の分だけ、tspan要素をずらしておく。
-             *さらに、現在のテキスト位置を更新する
-             */
-            for (var j=0, ttls=ti._list.length;j<ttls;++j) {
-              ti._list[j] += x;
-              ++j;
-              ti._list[j] += y;
-              ++j;
-            }
-            x = ti._list[ti._list.length-3];
-            y = ti._list[ti._list.length-2];
-            tar._list = tar._list.concat(ti._list);
-            n += ti.getNumberOfChars();
-          }
-          ti = ti.nextSibling;
-        }
-        tar._isYokogaki = isYokogaki //getEndPositionOfCharメソッドなどで使う
-        tar = evt.currentTarget;
-        style = null;
-      }
       evt = tar = null;
     }
   }, false);
@@ -3605,7 +3614,8 @@
       for (var i=0, j=0, tli=tar.getNumberOfChars();i<tli;++i) {
         if (ti) {
           if (!!ti._tars) {
-            var sty = ti._tars[i-j].style, p = tar.getStartPositionOfChar(i);
+            var ij = (i > j) ? i - j : j - i
+            var sty = ti._tars[ij].style, p = tar.getStartPositionOfChar(i);
             sty.position = "absolute";
             if (tar._isYokogaki) {
               if (anchor === "middle") {
@@ -3626,7 +3636,7 @@
             sty.height = "0px";
             sty.marginTop = tar._isYokogaki ? -n+ "px" : "0px";
             sty.lineHeight = n+ "px";
-            tar._tar.appendChild(ti._tars[i]);
+            tar._tar.appendChild(ti._tars[ij]);
             sty = p = null;
           }
           if (!!ti.data) {
@@ -3637,7 +3647,6 @@
           } else if (!!ti.getNumberOfChars) {
               if ((ti.getNumberOfChars()+j) <= i+1) {
                 j = j + i + 1;
-                i += j;
                 ti = ti.nextSibling;
               }
           }




Sie-announce メーリングリストの案内
Back to archive index