OSDN Git Service

Add an end property to the . object
[sie/sie.git] / org / w3c / dom / smil.js
index 4c17f3e..98a3e81 100644 (file)
@@ -105,13 +105,16 @@ base("$frame").mix ( {
   }\r
 } ).mix( function($frame) {\r
   $frame.up("$list").mix( {\r
-    /*開始時刻リスト (後述のupdateStateメソッドで使う)*/\r
+    /*終了時刻(単位フレーム数)のキャッシュとして使う*/\r
+    end: 0,\r
+    \r
+    /*開始時刻(単位フレーム数)リスト (後述のupdateStateメソッドで使う)*/\r
     beginList: { \r
       next: null,\r
       value: Number.MAX_VALUE\r
     },\r
     \r
-    /*終了時刻リスト (後述のupdateStateメソッドで使う)*/\r
+    /*終了時刻(単位フレーム数)リスト (後述のupdateStateメソッドで使う)*/\r
     endList: {\r
        next: null,\r
        value: Number.MAX_VALUE\r
@@ -165,6 +168,13 @@ base("$frame").mix ( {
     /*終了処理をした後の待機状態を示す定数*/\r
     POSTWAITING: 4,\r
     \r
+    /*初期化用メソッド*/\r
+    init: function() {\r
+      this.state = this.WAITING;\r
+      this.begin = 0;\r
+      return this;\r
+    },\r
+    \r
     /*引数で指定されたフレーム数に応じて、stateプロパティを更新するメソッド*/\r
     updateState: function( /*number*/ f) {\r
       if (f === void 0) {\r
@@ -189,16 +199,25 @@ base("$frame").mix ( {
           this.state = begin;\r
           /*beginプロパティに開始時刻をキャッシュ用に保存*/\r
           this.begin = startTime;\r
-        } else if (!f && !startTime) {\r
+        } else if (!startTime) {\r
           /*開始時刻が0ならば、アニメーションを開始*/\r
           this.state = begin;\r
         }\r
       } else if (state === begin) {\r
-        this.state = play;\r
+        if (endTime >= cacheBegin) {\r
+          /*終了時刻にもう到達したときは、直接BEGINNING状態からENDING状態へ移行*/\r
+          this.state = end;\r
+          /*現時点を終了時刻とみなす*/\r
+          this.end = f;\r
+        } else {\r
+          this.state = play;\r
+        }\r
       } else if (state === play) {\r
         if ( (endTime >= cacheBegin) || (startTime > cacheBegin) ) {\r
           /*終了時刻に到達したか、再び開始イベントが発火されたとき*/\r
           this.state = end;\r
+          /*現時点を終了時刻とみなす*/\r
+          this.end = f;\r
         }\r
       } else if (state === end) {\r
         if (endTime >= cacheBegin) {\r
@@ -226,7 +245,12 @@ base("$frame").mix ( {
     \r
     /*開始と再生と終了時に発火されるイベントリスナーを登録するメソッド*/\r
     addEvent: function ( /*string*/ eventName, /*fnction*/ listener) {\r
-      this["_" +eventName+ "ListenerList"].push(listener);\r
+      var evtName = "_" +eventName+ "ListenerList";\r
+      /*プロトタイプ継承していた場合は新しく配列を作成*/\r
+      if (!this.hasOwnProperty(evtName)) {\r
+        this[evtName] = [];\r
+      }\r
+      this[evtName].push(listener);\r
     },\r
     \r
     /*入力されたフレーム数fの場面に切り替えるメソッド*/\r
@@ -245,8 +269,10 @@ base("$frame").mix ( {
         for (var i=0;i<list.length;++i) {\r
           list[i](this);\r
         }\r
-        this.updateState(f);\r
-      } else if (state === /*this.ENDING*/ 3) {\r
+        /*開始時刻と終了時刻が一致した場合はstateはENDING状態*/\r
+        state = this.updateState(f).state;\r
+      }\r
+      if (state === /*this.ENDING*/ 3) {\r
         list = this._endListenerList;\r
         for (var i=0;i<list.length;++i) {\r
           list[i](this);\r
@@ -262,12 +288,6 @@ base("$frame").mix ( {
     /*後述の$beginや$endで使うメソッド*/\r
     this.addList = this.addBeginList;\r
   } );\r
-  \r
-  /*$endFrame オブジェクト\r
-   * 終了時の処理をするためのフレームを集める*/\r
-  $frame.up("$endFrame").mix( {\r
-    timelines: []\r
-  } );\r
    \r
   /*$begin オブジェクト\r
    * 開始のタイミングを計算する*/\r
@@ -364,11 +384,6 @@ base("$frame").mix ( {
           ele,\r
           /*endListのvalueプロパティには、活動継続フレーム数と開始フレーム数を足したものが入る*/\r
           endList = this.$list.addEndList(Number.MAX_VALUE);\r
-      if (this.$end) {\r
-        /*$endオブジェクトを継承していた場合、\r
-         *活動継続フレーム数関連のリストは無効とする*/\r
-        endList = { value: 0};\r
-      }\r
       if (str === "indefinite") {\r
         this.begin = Number.MAX_VALUE;\r
       } else if (plusminus > 0) {\r
@@ -402,8 +417,8 @@ base("$frame").mix ( {
             objList = this.$list.addList(Number.MAX_VALUE),\r
         /*イベントのリスナーとして使う*/\r
             listener = function(evt) {\r
-              objList.value = this.begin = eventOffset + this.$frame.currentFrame;\r
-              endList.value = this.$list.begin + this.activeTime;\r
+              objList.value = this.begin = eventOffset + base("$frame").currentFrame;\r
+              endList.value = this.begin + this.activeTime;\r
               this.isResolved = true;\r
             };\r
         this.eventOffset = eventOffset;\r
@@ -437,10 +452,6 @@ base("$frame").mix ( {
       /*初期値を設定*/\r
       this.begin = 0;\r
       this.isResolved = false;\r
-      /*beginとend属性を考慮に入れないで、活動継続時間を求める*/\r
-      var s = ( this.$activate = this.$activate.up() );\r
-      this.activeTime = s.call() || Number.MAX_VALUE;\r
-      this.simpleDuration = s.simpleDur;\r
       var str = this.trim(this.string);\r
       if (str.indexOf(";") > -1){\r
         /*;で区切られたリストを一つずつ解析*/\r
@@ -455,11 +466,15 @@ base("$frame").mix ( {
       return this;\r
     },\r
     \r
-    /*$listã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\82\92æ\9b´æ\96°ã\81\99るメソッド*/\r
+    /*$listã\81¨$activateã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\82\92æ\9b´æ\96°ã\81\97ã\81¦ã\80\81æ´»å\8b\95ç¶\99ç¶\9aæ\99\82é\96\93ã\82\92æ±\82ã\82\81るメソッド*/\r
     updateList: function() {\r
       this.$list = this.$list.up();\r
+      /*beginとend属性を考慮に入れないで、活動継続時間を求める*/\r
+      var s = ( this.$activate = this.$activate.up() );\r
       /*$endオブジェクトに付属している$listプロパティを更新したものと一致させておく*/\r
-      this.$activate.end && (this.$activate.end.$list = this.$list);\r
+      s.end && (s.end.$list = this.$list);\r
+      this.activeTime = s.call() || Number.MAX_VALUE;\r
+      this.simpleDuration = s.simpleDur;\r
       return this;\r
     }\r
     \r
@@ -571,9 +586,10 @@ base("$frame").mix ( {
       if (!this.string) {\r
         return null;\r
       }\r
-      /*addListメソッドには、addBeginList関数が入っているはずなので、それを変更する*/\r
+      /*addListメソッドには、addBeginList関数が入っているはずなので、それを一時的に変更する*/\r
       this.$list.addList = this.$list.addEndList;\r
       this.parse(this.string);\r
+      this.$list.addList = this.$list.addBeginList;\r
       return this.isResolved ? this.begin\r
                              : "indefinite";\r
     }\r
@@ -1024,6 +1040,32 @@ base("$calcMode").up("$attribute").mix( {
     }\r
     return s;\r
   },\r
+  \r
+  /*repeatイベントの発火時刻リスト\r
+   * setSmilEventメソッドを見よ*/\r
+  _repeatList: [],\r
+  \r
+  /*SMILイベント関連を発火させるためのメソッド\r
+   * もっぱら、push メソッドで使われる*/\r
+   setSmilEvent: function($list) {\r
+    var detail = 0;\r
+    $list.addEvent("begin", function($list) {\r
+        var target = this._ele;\r
+        /*IE11のために、MouseEventsでSMILEventsの代用をする*/\r
+        var evt = target.ownerDocument.createEvent("MouseEvents");\r
+        evt.initMouseEvent("beginEvent" ,true, true, window, detail, 0, 0, 0, 0, false, false, false, false, 0, target);\r
+        target.dispatchEvent(evt);\r
+        /*repeatイベントのために、_repeatListプロパティを初期化する*/\r
+        var list = this._repeatList = [],\r
+            simpleDuration = this.timeline.simpleDuration;\r
+      }.bind(this) );\r
+    $list.addEvent("end", function() {\r
+        var target = this._ele;\r
+        var evt = target.ownerDocument.createEvent("MouseEvents");\r
+        evt.initMouseEvent("endEvent" ,true, true, window, detail, 0, 0, 0, 0, false, false, false, false, 0, target);\r
+        target.dispatchEvent(evt);\r
+      }.bind(this) );\r
+   },\r
 \r
   /*引数で指定した要素 ele の属性を解析して、フレームに追加する*/\r
   push: function(/*Element Node*/ ele) {\r
@@ -1101,21 +1143,36 @@ base("$calcMode").up("$attribute").mix( {
                     max: this.getAttr("max", "indefinite")\r
                   } )\r
                 } ).updateList().parse();\r
-    $frame.addLine(frame.$list);\r
+    $frame.addLine(frame.$list.init());\r
+    \r
     /*beginElementメソッドを追加*/\r
-    function eleMethod (obj, eventName) {\r
-      return (obj.string !== "indefinite") ? function(){}\r
+    var objList = frame.$list.addList(Number.MAX_VALUE),\r
+        /*endListのvalueプロパティには、活動継続フレーム数と開始フレーム数を足したものが入る*/\r
+        endList = frame.$list.addEndList(Number.MAX_VALUE);\r
+    ele.beginElement = (frame.string !== "indefinite") ? function(){}\r
                         : function() {\r
+                            objList.value = frame.begin = base("$frame").currentFrame;\r
+                            endList.value = frame.begin + frame.activeTime;\r
+                            frame.isResolved = true;\r
                             var evt = this.ownerDocument.createEvent("MouseEvents");\r
-                            evt.initMouseEvent(eventName + "Event" ,true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, this);\r
+                            evt.initMouseEvent("beginEvent" ,true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, this);\r
                             this.dispatchEvent(evt);\r
                           };\r
-    };\r
-    ele.beginElement = eleMethod(frame, "begin");\r
     /*endElementメソッドを追加*/\r
-    ele.endElement = eleMethod(frame.$activate.end || {}, "end");\r
+    var endFrame = frame.$activate.end || {};\r
+    ele.endElement = (endFrame.string !== "indefinite") ? function(){}\r
+                        : function() {\r
+                            if (frame.isResolved) {\r
+                              endList.value = frame.begin + frame.activeTime;\r
+                              endFrame.isResolved = true;\r
+                              var evt = this.ownerDocument.createEvent("MouseEvents");\r
+                              evt.initMouseEvent("endEvent" ,true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, this);\r
+                              this.dispatchEvent(evt);\r
+                            }\r
+                          };\r
     /*setFrameメソッドを使ったときの、再帰スタックの使いすぎを防ぐため*/\r
     frame.timelines = [];\r
+    this.setSmilEvent(frame.$list);\r
     begin = ele = void 0;\r
     return frame;\r
   },\r
@@ -1343,7 +1400,7 @@ base("$calcMode").up("$attribute").mix( {
   },\r
   \r
   _setFrame: function($list) {\r
-    var currentTime = $list.currentFrame;\r
+    var currentFrame = $list.currentFrame;\r
     /*durationは単純継続時間\r
      *advanceは継続時間内での、進捗率\r
      *  仕様を参照 http://www.w3.org/TR/smil-animation/#AnimFuncValues\r
@@ -1355,13 +1412,13 @@ base("$calcMode").up("$attribute").mix( {
         /*単純継続時間が不定の場合、補間はせずに初期値が採用されるため、advanceは0となる\r
          * 仕様を参照 SMIL Animation 3.2.2. Animation function values のInterpolation and indefinite simple durations\r
          * http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues*/\r
-        advance = duration ? ( (currentTime - line.begin) % duration ) / duration\r
+        advance = duration ? ( (currentFrame - $list.begin) % duration ) / duration\r
                     : 0;\r
     this.setAttribute(this.tocall(advance));\r
     line = duration = advance = void 0;\r
   },\r
   \r
-  /*_setEndFrameメソッドは、終了処理と凍結作業をするときに、falseを返す*/\r
+  /*_setEndFrameメソッドは、終了処理と凍結作業をする*/\r
   _setEndFrame: function($list) {\r
     var frame = $list.currentFrame;\r
     /*上書きされたメソッドを呼び出してアニメーションの凍結作業をする*/\r
@@ -1719,7 +1776,8 @@ base("$calcMode").up("$attribute").mix( {
    /*後の_setFrameメソッドで使うダミー*/\r
    __setAttribute: function(){},\r
    \r
-   _setFrame: function(currentFrame) {\r
+   _setFrame: function($list) {\r
+    var currentFrame = $list.currentFrame;\r
      /*__transformListの中で、自分より後の項目に再生中のものがあれば、\r
       *アニメーションを再生させないで、後に続く項目に任せる*/\r
      var list = this.element.__transformList,\r
@@ -1741,7 +1799,7 @@ base("$calcMode").up("$attribute").mix( {
      this.$animateElement._setFrame.call(this, currentFrame);\r
    },\r
    \r
-   _setEndFrame: function(currentFrame) {\r
+   _setEndFrame: function($list) {\r
      var list = this.element.__transformList;\r
      if ((this.fill !== "remove") || !list) {\r
        return;\r
@@ -2000,7 +2058,7 @@ base("$frame").up("$svgEvent").mix( {
         floor = Math.floor;\r
     while(obj) {\r
       var frame = obj.frame,\r
-          target = obj.target\r
+          target = obj.target,\r
           detail = 0;\r
       if (frame <= num) {\r
         /*IE11ではSVGEventsやDOMEventsを使うと問題が起きるため、MouseEventsで代用する*/\r
@@ -2103,7 +2161,6 @@ if (!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Anim
           frame++;\r
           try {\r
             $f.setFrame(frame);\r
-            $f.$endFrame.setFrame(frame);\r
           } catch(e) {\r
           }\r
           _cancel.handle = requestAnimationFrame(step);\r