OSDN Git Service

0.92 build
authordhrname <dhrname@users.sourceforge.jp>
Wed, 11 Jan 2012 12:34:25 +0000 (21:34 +0900)
committerdhrname <dhrname@users.sourceforge.jp>
Wed, 11 Jan 2012 12:34:25 +0000 (21:34 +0900)
sie.js

diff --git a/sie.js b/sie.js
index 6018550..a7ae1f3 100644 (file)
--- a/sie.js
+++ b/sie.js
@@ -2312,12 +2312,12 @@ module smil
  */
 function ElementTimeControl(ele) {
   this._tar = ele;
-  /*_beginと_endプロパティはミリ秒数を収納する。リピート時に書き換えられることがある。
-   *_beginはアニメ開始時の秒数。_endはアニメ終了時の秒数
+  /*_startと_endプロパティはミリ秒数を収納する。
+   *_startはアニメ開始時の秒数のリスト。_finishはアニメ終了時の秒数のリスト
    *なお、文書読み込み終了時(アニメ開始時刻)の秒数を0とする。
    */
-  this._begin = 0;
-  this._end = null;
+  this._start = [];
+  this._finish = null;
   return this;
 };
 ElementTimeControl.prototype = {
@@ -2332,12 +2332,28 @@ ElementTimeControl.prototype = {
     this.dispatchEvent(evt);
   },
   /*void*/  beginElementAt : function(/*float*/ offset) {
-    var ntc = this.ownerDocument.documentElement.getCurrentTime();
-    this._begin = offset + ntc;
+    var ntc = this.ownerDocument.documentElement.getCurrentTime(),
+        start = this._start || [];
+    for (var i=0,sli=start.length;i<sli;++i) {
+      if (start[i] === (offset+ntc)) {
+        ntc = start = offset = void 0;
+        return;
+      }
+    }
+    start.push(offset + ntc);
+    this._start = start;
   },
   /*void*/  endElementAt : function(/*float*/ offset) {
-    var ntc = this.ownerDocument.documentElement.getCurrentTime();
-    this._end = offset + ntc;
+    var ntc = this.ownerDocument.documentElement.getCurrentTime(),
+        fin = this._finish || [];
+    for (var i=0,fli=fin.length;i<fli;++i) {
+      if (fin[i] === (offset+ntc)) {
+        ntc = fin = offset = void 0;
+        return;
+      }
+    }
+    fin.push(offset + ntc);
+    this._finish = fin;
   }
 };
 
@@ -4233,7 +4249,7 @@ function _ca_() {
         NAIBU._buff = setInterval(function(){
           var n = NAIBU._buff_num,
               dbuf = DOMImplementation._buffer_,
-              dbufli = dbuf.length,
+              dbufli = dbuf ? dbuf.length : 0, //極端な負荷がかかると、dbufはnullになる可能性あり
               s, evt;
           if (dbufli === 0) {
             clearInterval(NAIBU._buff);              
@@ -6154,7 +6170,7 @@ t.prototype = new SVGElement();
   t.prototype._list = null;         //文字の位置を格納しておくリストのキャッシュ
   t.prototype._length = 0;          //全文字数
   t.prototype._stx = t.prototype._sty = 0; //初めの文字の位置
-  t.prototype._chars = 0;           //tspan要素が全体の何文字目から始まっているか
+  t.prototype._chars = 0;           //tspan (tref)要素が全体の何文字目から始まっているか
   t.prototype._isYokogaki = true;          //横書きかどうか
 /*long*/     t.prototype.getNumberOfChars = function() {
   return (this._length);
@@ -6226,7 +6242,7 @@ t.prototype = new SVGElement();
       while (ti) {
         if (ti.nodeType === /*Node.TEXT_NODE*/ 3) {
           tt = ti._tars;
-          /*tspan要素のx属性で指定された座標の個数よりも、文字数が多い場合は、祖先(親)のx属性を
+          /*tspan(tref)要素のx属性で指定された座標の個数よりも、文字数が多い場合は、祖先(親)のx属性を
            *使う。また、属性が指定されていないときも同様に祖先や親を使う。
            *もし、仮に祖先や親がx属性を指定されていなければ、現在のテキスト位置(変数xに格納している)を使う。
            *この処理はdx属性やdy、y属性でも同様とする
@@ -6308,8 +6324,9 @@ t.prototype = new SVGElement();
             ti = ti.parentNode;
           }
           ti = ti.nextSibling;
-        } else if ((ti.localName === "tspan") && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
-          /*現在のテキスト位置(x,y)の分だけ、tspan要素をずらしておく。
+        } else if (((ti.localName === "tspan") || (ti.localName === "tref"))
+            && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
+          /*現在のテキスト位置(x,y)の分だけ、tspan (tref)要素をずらしておく。
            *さらに、現在のテキスト位置を更新する
            */
           ti._stx = x;
@@ -6384,7 +6401,7 @@ function SVGTextPositioningElement(_doc) {
   /*readonly SVGAnimatedLengthList*/ this.y = new sl();
   /*readonly SVGAnimatedLengthList*/ this.dx = new sl();
   /*readonly SVGAnimatedLengthList*/ this.dy = new sl();
-  _doc = sl = void 0;
+  sl = void 0;
   /*readonly SVGAnimatedNumberList*/ this.rotate = new SVGAnimatedNumberList();
   this.addEventListener("DOMAttrModified", function(evt){
     var tar = evt.target,
@@ -6449,14 +6466,10 @@ function SVGTextPositioningElement(_doc) {
       evt = tar = void 0;
     }
   }, false);
-  return this;
-};
-SVGTextPositioningElement.constructor = SVGTextContentElement;
-SVGTextPositioningElement.prototype = new SVGTextContentElement();
-
-function SVGTextElement(_doc) {
-  SVGTextPositioningElement.apply(this, arguments);
-  this._tar = _doc.createElement("v:group");
+  if (_doc) {
+    this._tar = _doc.createElement("v:group");
+    this._doc = _doc; //_docプロパティは_texto関数内で使われる
+  }
   this.addEventListener("DOMNodeInserted", function(evt){
     if (evt.eventPhase === /*Event.BUBBLING_PHASE*/ 3) {
       return; //強制終了させる
@@ -6485,159 +6498,167 @@ function SVGTextElement(_doc) {
       tpart.appendChild(tar._tar);      
     }
     tnext = tpart = isLast = void 0;
-    tar.addEventListener("DOMNodeInsertedIntoDocument", function(evt) {
-      var tar = evt.target,
-          ti = tar.firstChild,
-          ttp = tar._tar,
-          style = tar.ownerDocument.defaultView.getComputedStyle(tar, null),
-          n = parseFloat(style.getPropertyValue("font-size")) * Math.sqrt(Math.abs(tar.getScreenCTM()._determinant())),
-          tod = tar.ownerDocument.documentElement,
-          ttpc = ttp, //ttpcはttpのキャッシュ
-          tlen = tar.getComputedTextLength(),
-          anchor = style.getPropertyValue("text-anchor"),
-          tedeco = style.getPropertyValue("text-decoration"), //text-decorationは継承しないので、個々に設定する
-          ttps = ttp.style,
-          ae = [];
-      ttps.fontSize = n + "px";
-      ttps.fontFamily = style.getPropertyValue("font-family");
-      ttps.fontStyle = style.getPropertyValue("font-style");
-      ttps.fontWeight = style.getPropertyValue("font-weight");
-      /*ここでの変数jは前回ノードまでの総文字数*/
-      for (var i=0, j=0, tli=tar.getNumberOfChars();i<tli;++i) {
-        if (ti) {
-          if (!!ti._tars && (ti._tars.length !== 0)) {
-            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") {
-                p.x -= tlen / 2;
-              } else if (anchor === "end") {
-                p.x -= tlen;
-              }
-            } else {
-              if (anchor === "middle") {
-                p.y -= tlen / 2;
-              } else if (anchor === "end") {
-                p.y -= tlen;
-              }
-            }
-            sty.left = p.x + "px";
-            sty.top = p.y + "px";
-            sty.width = "0px";
-            sty.height = "0px";
-            sty.marginTop = tar._isYokogaki ? -n-5+ "px" : "-5px";
-            sty.lineHeight = n+10+ "px";
-            sty.textDecoration = tedeco;
-            sty.display = "none"
-            ttp.appendChild(ti._tars[ij]);
-            sty = p = void 0;
+    tar.addEventListener("DOMNodeInsertedIntoDocument", tar._texto, false);
+    evt = tar = void 0;
+  },false);
+  return this;
+};
+SVGTextPositioningElement.constructor = SVGTextContentElement;
+SVGTextPositioningElement.prototype = new SVGTextContentElement();
+SVGTextPositioningElement.prototype._texto = function(evt) {
+  var tar = evt.target,
+      ti = tar.firstChild,
+      ttp = tar._tar,
+      style = tar.ownerDocument.defaultView.getComputedStyle(tar, null),
+      n = parseFloat(style.getPropertyValue("font-size")) * Math.sqrt(Math.abs(tar.getScreenCTM()._determinant())),
+      tod = tar.ownerDocument.documentElement,
+      ttpc = ttp, //ttpcはttpのキャッシュ
+      tlen = tar.getComputedTextLength(),
+      anchor = style.getPropertyValue("text-anchor"),
+      tedeco = style.getPropertyValue("text-decoration"), //text-decorationは継承しないので、個々に設定する
+      ttps = ttp.style,
+      ae = [];
+  ttps.fontSize = n + "px";
+  ttps.fontFamily = style.getPropertyValue("font-family");
+  ttps.fontStyle = style.getPropertyValue("font-style");
+  ttps.fontWeight = style.getPropertyValue("font-weight");
+  /*ここでの変数jは前回ノードまでの総文字数*/
+  for (var i=0, j=0, tli=tar.getNumberOfChars();i<tli;++i) {
+    if (ti) {
+      if (!!ti._tars && (ti._tars.length !== 0)) {
+        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") {
+            p.x -= tlen / 2;
+          } else if (anchor === "end") {
+            p.x -= tlen;
           }
-          if (ti.nodeName === "#text") {
-            if ((ti.data.length+j) <= i+1) { //テキストノード内の文字をすべて処理し終えれば
-              j = j + ti.data.length;
-              if (ti.parentNode.localName === "a") {
-                ti =  ti.parentNode;
-                ttp = ttpc;
-              }
-              ti = ti.nextSibling;
-            }
-          } else if (!!ti.getNumberOfChars) {
-              if ((ti.getNumberOfChars()+j) <= i+1) {
-                j = j + ti.getNumberOfChars();
-                ti = ti.nextSibling;
-              }
-          } else if ((ti.localName === "a") && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
-            ttp = ti._tar;
-            ti = ti.firstChild;
-            ae[ae.length] = ti;
-            i-=2;
+        } else {
+          if (anchor === "middle") {
+            p.y -= tlen / 2;
+          } else if (anchor === "end") {
+            p.y -= tlen;
           }
         }
-      }
-      var color = style.getPropertyValue("fill"),
-          cursor = style.getPropertyCSSValue("cursor"),
-          vis = style.getPropertyCSSValue("visibility"),
-          disp = style.getPropertyCSSValue("display"),
-          tts = tar._tar.style,
-          tft = tar.firstChild._tars, //空白のテキストノードの場合、tftがundefinedになる恐れがある
-          ttt = tft[0] ? tft[0].innerText.charAt(0) : [""], //あらかじめ初期化しておく
-          tfti;
-      if (color === "none"){
-        tts.color = "transparent";
-      } else if (color.indexOf("url") === -1) {
-        tts.color = color;
-      } else {
-        tts.color = "black";
-      }
-      if (cursor && !cursor._isDefault) { //初期値でないならば
-        var tc = cursor.cssText;
-        tts.cursor = tc.split(":")[1];
-        tc = void 0;
-      }
-      if ((tar.x.baseVal.numberOfItems === 1) && (tar.y.baseVal.numberOfItems === 1)
-          && tar._isYokogaki && (tar.firstChild.nodeName === "#text")) {
-        /*xとy属性が一つの値しか取らないとき、字詰めの処理をすべてブラウザに任せておく。
-         *以下では、他のdiv要素のテキストをすべて、最初のdiv要素にまとめている
-         */
-        for (var i=1, tli=tft.length;i<tli;++i) {
-          tfti = tft[i];
-          ttt += tfti.innerText;
-          tfti.parentNode.removeChild(tfti);
-        }
-        //以下でinnerTextやinnerHTMLを使うのは、IE6でエラーとなる可能性がある
-        if (tft[0] && tft[0].replaceChild) {
-          tft[0].replaceChild(_doc.createTextNode(ttt), tft[0].firstChild);
-        }
-        ttt = void 0;
-      }
-      var isRect = true,
-          di = "block";
-      if (ttp.lastChild) {
-        if (ttp.lastChild.nodeName !== "rect") {
-          isRect = false;
-        }
-      } else {
-        isRect = false;
-      }
-      if (!isRect) {
-        var backr = _doc.createElement("v:rect"),
-            backrs = backr.style; //ずれを修正するためのもの
-        backrs.width = backrs.height = "1px";
-        backrs.left = backrs.top = "0px";
-        backr.stroked = backr.filled = "false";
-        ttp.appendChild(backr);
-      }
-      if (vis && !vis._isDefault) {
-        tts.visibility = vis.cssText.split(":")[1];
-      }
-      /*dipslayプロパティだけはdiv要素の個々に設定しておく必要がある
-       *なぜかといえば、div要素をdisplay:none;であらかじめ設定しているため。
-       */
-      if (disp && !disp._isDefault && (disp.cssText.indexOf("none") > -1)) {
-        di = "none";
-            } else if (disp && !disp._isDefault) {
-        di = "block";
-      }
-      var jt = tar._tar.firstChild,
-          j = 0;
-      while (jt) {
-        jt.style.display = di;
-        jt = jt.nextSibling;
-      }
-      while (ae[j]) { //要素内部にあるa要素の処理
-        for (var l=0, tli=ae[j]._tars.length;l<tli;++l) {
-          ae[j]._tars[l].style.display = di;
+        sty.left = p.x + "px";
+        sty.top = p.y + "px";
+        sty.width = "0px";
+        sty.height = "0px";
+        sty.marginTop = tar._isYokogaki ? -n-5+ "px" : "-5px";
+        sty.lineHeight = n+10+ "px";
+        sty.textDecoration = tedeco;
+        sty.display = "none"
+        ttp.appendChild(ti._tars[ij]);
+        sty = p = void 0;
+      }
+      if (ti.nodeName === "#text") {
+        if ((ti.data.length+j) <= i+1) { //テキストノード内の文字をすべて処理し終えれば
+          j = j + ti.data.length;
+          if (ti.parentNode.localName === "a") {
+            ti =  ti.parentNode;
+            ttp = ttpc;
+          }
+          ti = ti.nextSibling;
         }
-        l = void 0;
-        ++j;
+      } else if (!!ti.getNumberOfChars) {
+          if ((ti.getNumberOfChars()+j) <= i+1) {
+            j = j + ti.getNumberOfChars();
+            ti = ti.nextSibling;
+          }
+      } else if ((ti.localName === "a") && (ti.namespaceURI === "http://www.w3.org/2000/svg") && ti.firstChild) {
+        ttp = ti._tar;
+        ti = ti.firstChild;
+        ae[ae.length] = ti;
+        i-=2;
       }
-      delete tar._cacheMatrix;
-      ae = isRect = evt = tar = style = tedeco = tpp = ttpc = style = color = cursor = disp = vis = ttps = backr = backrs = di = tft = jt = void 0;
-    }, false);
-    evt = tar = void 0;
-  },false);
+    }
+  }
+  var color = style.getPropertyValue("fill"),
+      cursor = style.getPropertyCSSValue("cursor"),
+      vis = style.getPropertyCSSValue("visibility"),
+      disp = style.getPropertyCSSValue("display"),
+      tts = tar._tar.style,
+      tft = tar.firstChild._tars, //空白のテキストノードの場合、tftがundefinedになる恐れがある
+      ttt = tft[0] ? tft[0].innerText.charAt(0) : [""], //あらかじめ初期化しておく
+      tfti;
+  if (color === "none"){
+    tts.color = "transparent";
+  } else if (color.indexOf("url") === -1) {
+    tts.color = color;
+  } else {
+    tts.color = "black";
+  }
+  if (cursor && !cursor._isDefault) { //初期値でないならば
+    var tc = cursor.cssText;
+    tts.cursor = tc.split(":")[1];
+    tc = void 0;
+  }
+  if ((tar.x.baseVal.numberOfItems === 1) && (tar.y.baseVal.numberOfItems === 1)
+      && tar._isYokogaki && (tar.firstChild.nodeName === "#text")) {
+    /*xとy属性が一つの値しか取らないとき、字詰めの処理をすべてブラウザに任せておく。
+     *以下では、他のdiv要素のテキストをすべて、最初のdiv要素にまとめている
+     */
+    for (var i=1, tli=tft.length;i<tli;++i) {
+      tfti = tft[i];
+      ttt += tfti.innerText;
+      tfti.parentNode.removeChild(tfti);
+    }
+    //以下でinnerTextやinnerHTMLを使うのは、IE6でエラーとなる可能性がある
+    if (tft[0] && tft[0].replaceChild) {
+      tft[0].replaceChild(tar._doc.createTextNode(ttt), tft[0].firstChild);
+    }
+    ttt = void 0;
+  }
+  var isRect = true,
+      di = "block";
+  if (ttp.lastChild) {
+    if (ttp.lastChild.nodeName !== "rect") {
+      isRect = false;
+    }
+  } else {
+    isRect = false;
+  }
+  if (!isRect) {
+    var backr = tar._doc.createElement("v:rect"),
+        backrs = backr.style; //ずれを修正するためのもの
+    backrs.width = backrs.height = "1px";
+    backrs.left = backrs.top = "0px";
+    backr.stroked = backr.filled = "false";
+    ttp.appendChild(backr);
+  }
+  if (vis && !vis._isDefault) {
+    tts.visibility = vis.cssText.split(":")[1];
+  }
+  /*dipslayプロパティだけはdiv要素の個々に設定しておく必要がある
+   *なぜかといえば、div要素をdisplay:none;であらかじめ設定しているため。
+   */
+  if (disp && !disp._isDefault && (disp.cssText.indexOf("none") > -1)) {
+    di = "none";
+        } else if (disp && !disp._isDefault) {
+    di = "block";
+  }
+  var jt = tar._tar.firstChild,
+      j = 0;
+  while (jt) {
+    jt.style.display = di;
+    jt = jt.nextSibling;
+  }
+  while (ae[j]) { //要素内部にあるa要素の処理
+    for (var l=0, tli=ae[j]._tars.length;l<tli;++l) {
+      ae[j]._tars[l].style.display = di;
+    }
+    l = void 0;
+    ++j;
+  }
+  delete tar._cacheMatrix;
+  ae = isRect = evt = tar = style = tedeco = tpp = ttpc = style = color = cursor = disp = vis = ttps = backr = backrs = di = tft = jt = void 0;
+};
+
+function SVGTextElement(_doc) {
+  SVGTextPositioningElement.apply(this, arguments);
   return this;
 };
 SVGTextElement.constructor = SVGTextPositioningElement;
@@ -6652,6 +6673,24 @@ SVGTSpanElement.prototype = new SVGTextPositioningElement();
 
 function SVGTRefElement(_doc) {
   SVGTextPositioningElement.apply(this, arguments);
+  this.addEventListener("DOMNodeInserted", function(evt){
+    if (evt.eventPhase === /*Event.BUBBLING_PHASE*/ 3) {
+      return; //強制終了させる
+    }
+    evt.target.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:show", "embed");
+  }, false);
+  this.addEventListener("S_Load", function(evt){
+    var tar = evt.target,
+        tic = tar._instance.firstChild;
+    /*textノードのデータだけを処理*/
+    while (tic && (tic.nodeName !== "#text")) {
+      tic = tic.nextSibling;
+    }
+    tic && tar.parentNode.insertBefore(tar.ownerDocument.importNode(tic, false), tar);
+    evt.target = tar.parentNode;
+    tar.parentNode._texto(evt);
+    tar = tic = evtt = void 0;
+  }, false);
   SVGURIReference.apply(this, arguments);
   return this;
 };
@@ -7360,76 +7399,132 @@ function SVGAnimationElement(es) {
   this.style.setProperty = function(){};
   this._tar = null;
   /*readonly SVGElement*/ this.targetElement;
-  this._beginValue = "0ms";
-  this._endValue = null;
+  /*それぞれのプロパティは、_を除いた属性に対応している*/
+  this._begin = this._end = this._repeatCount = this._repeatDur = null;
+  this._dur = "indefinite";
   this._currentFrame = 0;
-  this._currentCount = 0;
-  /*_maxCountはrepeatCount属性で指定された数値
-   *_maxDurはrepeatDur属性で指定された数値
-   */
-  this._maxCount = 0;
-  this._maxDur = 0;
+  /*_isRepeatと_numRepeatは繰り返し再生のときに使う。なお、後者は現在のリピート回数*/
   this._isRepeat = false;
-  /*_simpleDurationプロパティは
-   *dur属性の数値を収納しておく。属性がなければnullのまま
-   */
-  this._simpleDuration = null;
-  /*_beginと_endプロパティはミリ秒数を収納する。リピート時に書き換えられることがある。
-   *_beginはアニメ開始時の秒数。_endはアニメ終了時の秒数。
+  this._numRepeat = 0;
+  /*_startと_finishプロパティはミリ秒数のリストを収納する。
+   *_startはアニメ開始時の秒数リスト。_finishはアニメ終了時の秒数のリスト。
    *なお、文書読み込み終了時(アニメ開始時刻)の秒数を0とする。
+   *_startingプロパティは現在アニメーションでの開始時刻。getSartTimeメソッドで使う
    */
-  this._begin = null;
-  this._end = null;
+  this._start = this._finish = this._starting = null;
+  /*_activeDurプロパティは現時点でのアニメーションの活動期間*/
+  this._activeDur = 0; 
   this._from = this._to = this._values = this._by = null;
   this._keyTimes = null;
   this.addEventListener("beginEvent", function(evt) {
-    var tar = evt.target;
-    if (!tar.isRepeat) {
-      tar.endElementAt(tar.getSimpleDuration());
-    } else {
-      tar.beginElementAt(tar.getSimpleDuration());
-      if (tar.getCurrentTime() !== 0) {
-        var ttd = tar.ownerDocument, evt = ttd.createEvent("TimeEvents");
-        tar._currentCount++;
-        evt.initTimeEvent("repeatEvent", ttd.defaultView, tar._currentCount);
-        tar.dispatchEvent(evt);
+    try {
+      var tar = evt.target,
+      begin = tar.getStartTime(),
+      dur = tar.getSimpleDuration(),
+      durv = tar._dur,
+      end = tar._finish,
+      endv= tar._end,
+      td = tar._repeatDur,
+      tc = tar._repeatCount,
+      ac = 0;
+      if (end) {
+        end.sort(function(a, b) {
+          return a - b;
+        });
+        for (var i=0, eli=end.length;i<eli;++i) {
+          /*endの配列をソートした後で、beginに最も近い数値を選ぶ*/
+          if (eli[i] >= begin) {
+            end = end[i];
+          }
+          break;
+        }
       }
+      /*Activate Duration (活性持続時間と呼ぶことにする)を計算
+       *計算方法は以下を参照のこと
+       *http://www.w3.org/TR/smil-animation/#ComputingActiveDur
+       *3.3.4. Computing the active duration
+       */
+      if ((td === "indefinte") || (tc === "indefinte")) {
+        if (endv) {
+          ac = end - begin;
+        } else {
+          /*活性持続時間が不定(indefinte)なので、強制的にアニメを終了させる*/
+          ac = null;
+        }
+      } else if (durv === "indefinte") {
+        if (!tc && !endv) {
+          /*活性持続時間が不定(indefinte)なので、強制的にアニメを終了させる*/
+          ac = null;
+        } else if (tc && !endv) {
+          ac = tar._getOffset(td);
+        } else if (!tc && endv) {
+          ac = end - begin;
+        } else {
+          ac = (tar._getOffset(td) > (end - begin)) ? tar._getOffset(td) : (end - begin);
+        }
+      } else if (durv && !td && !tc && !endv) {
+        ac = dur;
+      } else if (durv && !td && tc && !endv) {
+        ac = dur * (+tc);
+      } else if (durv && td && !tc && !endv) {
+        ac = tar._getOffset(td);
+      } else if (durv && !td && !tc && endv) {
+        ac = (dur > (end - begin)) ? dur : (end - begin);
+      } else if (durv && td && tc && !endv) {
+        ac = (+tc*dur > tar._getOffset(td)) ? +tc*dur : tar._getOffset(td);
+      } else if (durv && td && tc && endv) {
+        ac = (+tc*dur > Math.min(+td, (end-begin))) ? +tc*dur : Math.min(tar._getOffset(td), (end - begin));
+      } else if (durv && td && !tc && endv) {
+        ac = (tar._getOffset(td) > (end - begin)) ? tar._getOffset(td) : (end - begin);
+      } else if (durv && !td && tc && endv) {
+        ac = (+tc*dur > (end - begin)) ? +tc*dur : (end - begin)
+      }
+    } catch (e) {
+      tar.endElementAt(1);
+      throw new DOMException(DOMException.INVALID_STATE_ERR);
     }
+    if (isFinite(ac)) {
+      tar.endElementAt(ac);
+      tar._activeDur = ac;
+    }
+    tar = begin = dur = durv = end = endv= td = tc = ac = void 0;
   }, false);
   this.addEventListener("DOMAttrModified", function(evt){
     if (evt.eventPhase === /*Event.BUBBLING_PHASE*/ 3) {
       return;
     }
-    var tar = evt.target, name = evt.attrName;
+    var tar = evt.target,
+        name = evt.attrName,
+        evtv = evt.newValue;
     if (name === "begin") {
-      tar._beginValue = evt.newValue;
+      tar._begin = evtv.replace(/\s+/g, "").split(";"); //空白は取り除く
     } else if (name === "end") {
-      tar._endValue = evt.newValue;
+      tar._end = evtv.replace(/\s+/g, "").split(";");
     } else if (name === "dur") {
-      tar._simpleDuration = tar._getOffset(evt.newValue);
+      tar._dur = evtv;
     } else if (name === "repeatCount") {
-      tar._maxCount = parseFloat(evt.newValue);
+      tar._repeatCount = evtv;
       tar._isRepeat = true;
     } else if (name === "repeatDur") {
-      tar._maxDur = parseFloat(evt.newValue);
+      tar._repeatCount = evtv;
       tar._isRepeat = true;
     } else if (name === "from") {
-      tar._from = evt.newValue;
+      tar._from = evtv;
     } else if (name === "to") {
-      tar._to = evt.newValue;
+      tar._to = evtv;
     } else if (name === "values") {
-      tar._values = evt.newValue.split(";");
+      tar._values = evtv.split(";");
     } else if (name === "by") {
-      tar._by = evt.newValue;
+      tar._by = evtv;
     } else if (name === "keyTimes") {
-      var s = evt.newValue.split(";");
+      var s = evtv.split(";");
       tar._keyTimes = []; //_keyTimesプロパティを初期化
       for (var i=0;i<s.length;++i) {
         tar._keyTimes[i] = parseFloat(s[i]);
       }
       s = void 0;
     }
-    evt = void 0;
+    evt = evtv = void 0;
   }, false);
   this.addEventListener("DOMNodeInserted", function(evt){
     if (evt.eventPhase === /*Event.BUBBLING_PHASE*/ 3) {
@@ -7461,43 +7556,100 @@ function SVGAnimationElement(es) {
          */
         return this;
       }
+      /*begin属性とend属性を処理する*/
+      var that = tar,
+          timing = function(val, name, offset) {
+        /*timing関数は時間のタイミングをidとeventと、clock-value(offset)に分割して処理していく
+         *まず、idを検出するためのsearcIdローカル関数を作る
+         */
+        var searchId = function () {
+              var n = val.indexOf(".");
+              if ((n > 0) && (/[a-z]/i).test(val.charAt(n+1))) { //. (dot)の後がアルファベットならば
+                return (val.slice(0, n));
+              }
+              n = nn = void 0;
+              return "";
+            },
+            id;
+        /*
+         *W3CのSMIl AnimationのTimingモデルは7パターンがあるので、場合分けする
+         */
+        if (isFinite(parseFloat(val))) { //1) offset-valueの場合
+          that[name](offset);
+        } else if (val.indexOf("repeat(") > -1) { //2) repeat-valueの場合
+          var inte = parseFloat(val.slice(7)),
+              ds = (function(that, name, offset) {
+                return function (evt) {
+                   if (inte === evt.target._numRepeat) {
+                     that[name](offset);
+                   }
+                };
+              })(that, name, offset),
+              id = searchId();
+              if (id) {
+                that.ownerDocument.getElementById(id).addEventListener("repeatEvent", ds);
+              } else {
+                that.addEventListener("repeatEvent", ds);
+              }
+        } else if (/\.(begin|end)/.test(val)) { //3) syncbase-valueの場合
+          id = searchId();
+          if (id) {
+            var ds = (function(that, name, offset) {
+                  return function (evt) {
+                    that[name](offset);
+                  };
+                })(that, name, offset),
+                ev = "";
+            /\.(begin|end)/.test(val); //RegExp.$1のために、もう一度する必要がある
+           if (RegExp.$1 === "begin") {
+              ev = "beginEvent";
+            } else if (RegExp.$1 === "end") {
+              ev = "endEvent";
+            }
+            that.ownerDocument.getElementById(id).addEventListener(ev, ds);
+          }
+        } else if (val.indexOf("wallclock(") === 0) { //4) wallclock-valueの場合
+          
+        } else if (val === "indefinte") { //5) indefinteの場合
+        } else if (val.indexOf("accesskey(") > -1) { //6) accesskey-valueの場合
+          
+        } else { //7) event-valueの場合
+          id = searchId();
+          var ds = (function(that, name, offset) {
+                return function (evt) {
+                   that[name](offset);
+                };
+              })(that, name, offset);
+          if (id && val.match(/\.([a-z]+)/i)) {
+            that.ownerDocument.getElementById(id).addEventListener(RegExp.$1, ds);
+          } else if (val){
+            that.targetElement.addEventListener(val.match(/^[a-z]+/i)[0], ds)
+          }
+        }
+        val = searchId = id = void 0;
+      };
+      if (tar._begin) {
+        for (var i=0,tli=tar._begin.length;i<tli;++i) {
+          timing(tar._begin[i], "beginElementAt", tar._getOffset(tar._begin[i]));
+        }
+      } else {
+        tar.beginElementAt(0);
+      }
+      if (tar._end) {
+        for (var i=0,tli=tar._end.length;i<tli;++i) {
+          timing(tar._end[i], "endElementAt", tar._getOffset(tar._end[i]));
+        }
+      }
+      that = void 0;
       if (tar.hasAttributeNS("http://www.w3.org/1999/xlink", "xlink:href")) {
         tar.targetElement = tar.ownerDocument.getElementById(tar.getAttributeNS("http://www.w3.org/1999/xlink", "xlink:href").substring(1))
       } else {
         tar.targetElement = tar.parentNode;
       }
-      tar._eventSync(tar._beginValue,
-          (function(te, offse, ta, t) {
-            ta.addEventListener( t.match(te._eventRegExp)[0],
-              function(){
-                if (offse !== 0) {
-                  te.beginElementAt(offse);
-                } else {
-                  te._begin = NAIBU.Time.currentFrame;
-                  te.beginElement();
-                  te._currentFrame++;
-                }
-              }, false);
-           }), "beginElementAt");
-      if (tar._endValue) {
-        tar._eventSync(tar._endValue,
-            (function(te, offse, ta, t) {
-              ta.addEventListener( t.match(te._eventRegExp)[0],
-                  function(){
-                    te.endElementAt(offse);
-                  }, false );
-              }), "endElementAt");
-      }
       evt = tar = void 0;
     }, false);
     evt = tar = void 0;
   }, false);
-  this.addEventListener("repeatEvent", function(evt) {
-    var tar = evt.target;
-    if ((tar._currentCount >= tar._maxCount) || (tar.getCurrentTime() >= (tar._maxDur+tar.getStartTime()))) {
-      tar._isRepeat = false;
-    }
-  }, false);
   return this;
 };
 SVGAnimationElement.constructor = SVGElement;
@@ -7506,25 +7658,65 @@ SVGAnimationElement.prototype = new SVGElement();
  *別モジュールであるsmil::ElementTimeControl(smil.js)を参照のこと
  */
 /*void*/ SVGAnimationElement.prototype.beginElement = function() {
-  var ttd = this.ownerDocument, evt = ttd.createEvent("TimeEvents");
+  var ttd = this.ownerDocument,
+      evt = ttd.createEvent("TimeEvents");
+  this._starting = ttd.documentElement.getCurrentTime(); //getStartTimeメソッドで使う開始時刻
+  if (this.getCurrentTime() > 0) {
+    /*アニメーションの最中で、beginEventが起きるときは、endEventが前もって起こされる。SVG1.1の仕様を参照
+     * 
+     * 19.4.2 Interface TimeEvent
+     * Note that if an element is restarted while it is currently playing, the element will raise an end event and another begin event, as the element restarts. 
+     * 
+     * http://www.w3.org/TR/SVG/animate.html#InterfaceTimeEvent
+     * 
+     */
+    this.endElement();
+    this._currentFrame = 0;
+  }
   evt.initTimeEvent("beginEvent", ttd.defaultView, 0);
   this.dispatchEvent(evt);
+  /*新しくリストの頭を更新して、別の値も実行させるようにする*/
+  this._start.shift();
 };
 /*void*/ SVGAnimationElement.prototype.endElement = function() {
-  var ttd = this.ownerDocument, evt = ttd.createEvent("TimeEvents");
+  var ttd = this.ownerDocument,
+      evt = ttd.createEvent("TimeEvents");
   evt.initTimeEvent("endEvent", ttd.defaultView, 0);
   this.dispatchEvent(evt);
+  this._finish.shift();
 };
 /*void*/ SVGAnimationElement.prototype.beginElementAt = function(/*float*/ offset) {
-  var ntc = this.ownerDocument.documentElement.getCurrentTime();
-  this._begin = offset + ntc;
+  var ntc = this.ownerDocument.documentElement.getCurrentTime(),
+  start = this._start || [];
+  for (var i=0,sli=start.length;i<sli;++i) {
+    if (start[i] === (offset+ntc)) {
+      ntc = start = offset = void 0;
+      return;
+    }
+  }
+  start.push(offset + ntc);
+  start.sort(function(a, b) {
+    return a - b;
+  });
+  this._start = start;
 };
 /*void*/ SVGAnimationElement.prototype.endElementAt = function(/*float*/ offset) {
-  var ntc = this.ownerDocument.documentElement.getCurrentTime();
-  this._end = offset + ntc;
+  var ntc = this.ownerDocument.documentElement.getCurrentTime(),
+  fin = this._finish || [];
+  for (var i=0,fli=fin.length;i<fli;++i) {
+    if (fin[i] === (offset+ntc)) {
+      ntc = fin = offset = void 0;
+      return;
+    }
+  }
+  fin.push(offset + ntc);
+  fin.sort(function(a, b) {
+    return a - b;
+  });
+  this._finish = fin;
 };
 SVGAnimationElement.prototype._eventRegExp = /(mouse|activ|clic|begi|en)[a-z]+/;
-SVGAnimationElement.prototype._timeRegExp = /[\-\d\.]+(h|min|s|ms)?/;
+SVGAnimationElement.prototype._timeRegExp = /[\-\d\.]+(h|min|s|ms)?$/;
 SVGAnimationElement.prototype._unit = {
     "h"   : 2880000,
     "min" : 48000,
@@ -7540,43 +7732,20 @@ SVGAnimationElement.prototype._unit = {
  ** Note that when the simple duration is "indefinite", some simple use cases can yield surprising results. See the related example #4 in Appendix B.
  */
 SVGAnimationElement.prototype._getOffset = function(/*string*/ t) {
-  var n = parseFloat(t.match(this._timeRegExp));
-  if (!isNaN(n) && RegExp.$1) {
+  var n = parseFloat((t.match(this._timeRegExp) || "0")),
+      offset = 0;
+  if (isFinite(n) && RegExp.$1) {
     var offset = n * this._unit[RegExp.$1]
-  } else if (!isNaN(n)) {
-    var offset = n;
-  } else {
-    var offset = 0;
+  } else if (isFinite(n)) {
+    offset = n;
   }
   n = t = void 0;
   return offset;
 };
-/*_eventSyncメソッド
- *イベントがある場合とない場合とで、別々の処理に分けるメソッド
- */
-SVGAnimationElement.prototype._eventSync = function(/*string*/ t, /*function*/ f, /*string*/ methodName) {
-  var offset = this._getOffset(t);
-  this._begin = NAIBU.Time.Max;
-  if ( /(mouse|activ|click|begin|end)/.test(t) ) { //イベントがある場合
-    var tar;
-    if ( /([^;]+)\.\D/.test(t) ) {
-      tar = this.ownerDocument.getElementById(RegExp.$1);
-    } else {
-      tar = this.targetElement;
-    }
-    if (!offset && offset !== 0) {
-      offset = NAIBU.Time.Max;
-    }
-    f(this, offset, tar, t);
-  } else if (!offset && (t !== "undefined") && (offset !== 0)) {
-    this._begin = 0;
-  } else {
-    this[methodName](offset);
-  }
-};
+
 /*float*/ SVGAnimationElement.prototype.getStartTime = function(){
-  if (!!this._begin || (this._begin === 0)) {
-    return (this._begin);
+  if (this._starting || (this._starting === 0)) {
+    return (this._starting);
   } else {
     throw new DOMException(DOMException.INVALID_STATE_ERR);
   }
@@ -7589,14 +7758,11 @@ SVGAnimationElement.prototype._eventSync = function(/*string*/ t, /*function*/ f
   return (this._currentFrame * 125 * 0.8);
 };
 /*float*/ SVGAnimationElement.prototype.getSimpleDuration = function(){
-  if (!!!this._simpleDuration && !!!this._end && (this._simpleDuration !== 0)) {
+  if (!this._dur && !this._finish && (this._dur === "indefinte")) {
     throw new DOMException(DOMException.NOT_SUPPORTED_ERR);
-  } else if (!!this._simpleDuration && !!this._end) {
-    var s = (this._simpleDuration > this._end - this._begin) ? this._end - this._begin : this._simpleDuration;
   } else {
-    var s = !!this._end ? this._end - this._begin : this._simpleDuration;
+    return (this._getOffset(this._dur));
   }
- return s;
 };
                     //raises( DOMException );
 NAIBU.Time = {
@@ -7611,34 +7777,48 @@ NAIBU.Time = {
     }
     NAIBU.stop = setInterval( (function() {
 /*      try{*/
-        var ntc = NAIBU.Time.currentFrame++;
-        var nc = NAIBU.Clip;
-        var s = ntc * 100; //フレーム数ntcをミリ秒数sに変換
+        var ntc = NAIBU.Time.currentFrame,
+            nc = NAIBU.Clip,
+            s = ntc * 100; //フレーム数ntcをミリ秒数sに変換 (100 = 125 * 0.8)
         if (ntc > NAIBU.Time.Max) {
           clearInterval(NAIBU.stop);
         }
+        nc[0] && nc[0].ownerDocument.documentElement.setCurrentTime(s);
         for (var i=0,ncli=nc.length;i<ncli;++i) {
-          var nci = nc[i];
-          nci.ownerDocument.documentElement.setCurrentTime(s);
-          if ("_begin" in nci) {
-            if (nci.getStartTime() <= s) {
-              if (nci.getCurrentTime() === 0) {
+          var nci = nc[i]
+              s2 = s + 100,
+              s1 = s - 100;
+          if (nci._start) {
+              var sti = nci._start[0];
+              if ((sti || (sti === 0)) && s1 <= sti && sti < s) {
                 nci.beginElement();
               }
-              nci._currentFrame++;
+              sti = void 0;
             }
-            if (nci._end && (nci._end <= s) && (nci.getCurrentTime() !== 0)) {
-              nci.endElement();
-              nci._frame && nci._frame();
-              nci._currentFrame = 0;
-              delete nci._begin;
-              nci._end = null;
-            } else if (!!nci._frame) {
-              nci._frame();
+          if (nci._isRepeat && (nci.getCurrentTime() !== 0) && ((nci.getSimpleDuration() % s) === 0)) {
+            var ttd = nci.ownerDocument,
+                evt = ttd.createEvent("TimeEvents");
+            ++nci._numRepeat;
+            evt.initTimeEvent("repeatEvent", ttd.defaultView, nci._numRepeat);
+            nci.dispatchEvent(evt);
+            ttd = evt = void 0;
+          }
+          if (nci._finish && (nci.getCurrentTime() !== 0)) {
+
+              var fti = nci._finish[0];
+              if ((fti || (fti === 0)) && s < fti && fti <= s2) {
+                nci.endElement();
+                nci._currentFrame = 0;
+              }
+              fti = void 0;
             }
+          if (nci._frame) {
+            nci._currentFrame++;
+            nci._frame();
           }
-          nci = void 0;
         }
+        ++NAIBU.Time.currentFrame;
+        nci = s1 = s2 = void 0;
 /*      } catch (e) {
         stlog.add(e, 4157);
       }*/
@@ -7741,11 +7921,18 @@ function SVGAnimateElement(){
     }, false);
   }, false);
   this.addEventListener("beginEvent", function(evt) {
-    var tar = evt.target;
-    var attrName = tar.getAttributeNS(null, "attributeName"), newAttr = tar.targetElement.attributes.getNamedItemNS(null, attrName);
-    var ttr = tar.targetElement, tta = ttr[attrName];
-    tar._frame = function() {
-      var d = tar.getSimpleDuration() * 0.8, n = tar._valueList.length-1, tg = tar.getCurrentTime();
+    var _tar = evt.target,
+        attrName = _tar.getAttributeNS(null, "attributeName"),
+        newAttr = _tar.targetElement.attributes.getNamedItemNS(null, attrName),
+        ttr = _tar.targetElement,
+        tta = ttr[attrName];
+    _tar._frame = function() {
+      var tar = _tar,
+          d = tar._isRepeat ? tar.getSimpleDuration() : tar._activeDur,
+          n = tar._valueList.length-1,
+          tg = tar.getCurrentTime();
+      tar._activeDur || (d = 0);
+      d *= 0.8;
       if ((n !== -1) && (d !== 0) && (tg <= d)) {
         if (tar._isDiscrete) {
           ++n; //discreteモードは他のモードに比べて、分割数が多いことに注意
@@ -7815,18 +8002,21 @@ function SVGAnimateElement(){
         ttr.animatedNormalizedPathSegList = ttr.normalizedPathSegList;
         ttr.normalizedPathSegList = base;
       }
-     evt = v1 = v2 = v = d = n = ii = tg = void 0;
+     evt = tar = v1 = v2 = v = d = n = ii = tg = void 0;
     };
     evt = vir = void 0;
   }, false);
   this.addEventListener("endEvent", function(evt) {
-    var tar = evt.target, fill = tar.getAttributeNS(null, "fill");
+    var tar = evt.target,
+        fill = tar.getAttributeNS(null, "fill");
     if (!fill || (fill === "remove")) {
       var evt = tar.ownerDocument.createEvent("MutationEvents");
       evt.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
       tar.targetElement.dispatchEvent(evt);
       evt = void 0;
+      tar._frame && tar._frame();
     }
+    delete tar._frame;
   }, false);
   this.addEventListener("repeatEvent", function(evt) {
     var tar = evt.target;
@@ -7881,6 +8071,7 @@ function SVGSetElement(){
         tta.baseVal = base;
       }
     }
+    ++tar._currentFrame; //これがないと、NAIBU.stopの内部の処理の都合上、endEventが発動しない。
     evt = tar = attrName = void 0;
   }, false);
   this.addEventListener("endEvent", function(evt) {
@@ -7954,10 +8145,11 @@ function SVGAnimateMotionElement(){
     tar._frame = function() {
       var _tar = tar,
           tpn = _tar._path,
-          tgsd = _tar.getSimpleDuration(),
+          tgsd = _tar._isRepeat ? _tar.getSimpleDuration() : _tar._activeDur,
           d = tgsd * 0.8,
           tg = _tar.getCurrentTime(),
           ii;
+      _tar._activeDur || (d = 0);
       if (tgsd === 0) {
          tgsd = void 0;
          return;
@@ -8021,8 +8213,10 @@ function SVGAnimateMotionElement(){
       var evtt = tar.ownerDocument.createEvent("MutationEvents");
       evtt.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
       tar.targetElement.dispatchEvent(evtt);
+      tar._frame && tar._frame();
     }
-    tar._frame = evt = evtt = void 0;
+    delete tar._frame;
+    evt = evtt = trans = fill = tar = void 0;
   }, false);
   this.addEventListener("repeatEvent", function(evt) {
     var tar = evt.target;
@@ -8092,10 +8286,12 @@ function SVGAnimateColorElement() {
        * 3.4.2 Specifying the simple animation function f(t)
        *http://www.w3.org/TR/2005/REC-SMIL2-20050107/animation.html#animationNS-SpecifyingAnimationFunction
        */
-      var d = _tar.getSimpleDuration() * 0.8,
+      var d = _tar._isRepeat ? _tar.getSimpleDuration() : _tar._activeDur,
           n = _tar._valueList.length - 1,
           tg = _tar.getCurrentTime(),
           ii, di, ti;
+      _tar._activeDur || (d = 0);
+      d *= 0.8;
       if ((n !== -1) && (d !== 0) && (tg <= d)) {
         ii = Math.floor((tg*n) / d);
         if (ii === n) { //iiが境い目のときは、n-2を適用
@@ -8127,13 +8323,16 @@ function SVGAnimateColorElement() {
     tar._frame();
   }, false);
   this.addEventListener("endEvent", function(evt) {
-    var tar = evt.target;
+    var tar = evt.target,
+        fill = tar.getAttributeNS(null, "fill");
     if (!fill || (fill === "remove")) {
       var evtt = tar.ownerDocument.createEvent("MutationEvents");
       evtt.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
       tar.targetElement.dispatchEvent(evtt);
+      tar._frame && tar._frame();
     }
-    tar._frame = evt = evtt = void 0;
+    delete tar._frame;
+    evt = evtt = tar = fill = void 0;
   }, false);
   this.addEventListener("repeatEvent", function(evt) {
     var tar = evt.target;
@@ -8158,7 +8357,16 @@ function SVGAnimateTransformElement() {
     trans.animVal.appendItem(tar.ownerDocument.documentElement.createSVGTransform());
   }, false);
   this.addEventListener("endEvent", function(evt) {
-    var tar = evt.target;
+    var tar = evt.target,
+        fill = tar.getAttributeNS(null, "fill");
+    if (!fill || (fill === "remove")) {
+      var evtt = tar.ownerDocument.createEvent("MutationEvents");
+      evtt.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
+      tar.targetElement.dispatchEvent(evtt);
+      tar._frame && tar._frame();
+    }
+    delete tar._frame;
+    evt = evtt = tar = fill = void 0;
   }, false);
   this.addEventListener("repeatEvent", function(evt) {
     var tar = evt.target;