1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3  Copyright (c) 2008-2010 Ricardo Quesada
  4  Copyright (c) 2011      Zynga Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 cc.RESOLUTION_POLICY = {
 28     // The entire application is visible in the specified area without trying to preserve the original aspect ratio.
 29     // Distortion can occur, and the application may appear stretched or compressed.
 30     EXACT_FIT: 0,
 31     // The entire application fills the specified area, without distortion but possibly with some cropping,
 32     // while maintaining the original aspect ratio of the application.
 33     NO_BORDER: 1,
 34     // The entire application is visible in the specified area without distortion while maintaining the original
 35     // aspect ratio of the application. Borders can appear on two sides of the application.
 36     SHOW_ALL: 2,
 37     // The application takes the height of the design resolution size and modifies the width of the internal
 38     // canvas so that it fits the aspect ratio of the device
 39     // no distortion will occur however you must make sure your application works on different
 40     // aspect ratios
 41     FIXED_HEIGHT: 3,
 42     // The application takes the width of the design resolution size and modifies the height of the internal
 43     // canvas so that it fits the aspect ratio of the device
 44     // no distortion will occur however you must make sure your application works on different
 45     // aspect ratios
 46     FIXED_WIDTH: 4,
 47 
 48     UNKNOWN: 5
 49 };
 50 
 51 cc.Touches = [];
 52 cc.TouchesIntergerDict = {};
 53 
 54 /**
 55  * @class
 56  * @extends cc.Class
 57  */
 58 cc.EGLView = cc.Class.extend(/** @lends cc.EGLView# */{
 59     _delegate: null,
 60     // Size of parent node that contains cc.container and cc.canvas
 61     _frameSize: null,
 62     // resolution size, it is the size appropriate for the app resources.
 63     _designResolutionSize: null,
 64     _originalDesignResolutionSize: null,
 65     // Viewport is the container's rect related to content's coordinates in pixel
 66     _viewPortRect: null,
 67     // The visible rect in content's coordinate in point
 68     _visibleRect: null,
 69     // The device's pixel ratio (for retina displays)
 70     _devicePixelRatio: 1,
 71     // the view name
 72     _viewName: "",
 73     // Custom callback for resize event
 74     _resizeCallback: null,
 75     _scaleX: 1,
 76     _originalScaleX: 1,
 77     _scaleY: 1,
 78     _originalScaleY: 1,
 79     _indexBitsUsed: 0,
 80     _maxTouches: 5,
 81     _resolutionPolicy: null,
 82     _rpExactFit: null,
 83     _rpShowAll: null,
 84     _rpNoBorder: null,
 85     _rpFixedHeight: null,
 86     _rpFixedWidth: null,
 87     _initialized: false,
 88 
 89     _captured: false,
 90     _wnd: null,
 91     _hDC: null,
 92     _hRC: null,
 93     _accelerometerKeyHook: null,
 94     _supportTouch: false,
 95     _contentTranslateLeftTop: null,
 96 
 97     _menu: null,
 98     // Parent node that contains cc.container and cc.canvas
 99     _frame: null,
100     _frameZoomFactor: 1.0,
101     __resizeWithBrowserSize: false,
102     _isAdjustViewPort: true,
103 
104     ctor: function () {
105         this._frame = (cc.container.parentNode === document.body) ? document.documentElement : cc.container.parentNode;
106         this._frameSize = cc.size(0, 0);
107         this._initFrameSize();
108 
109         var w = cc.canvas.width, h = cc.canvas.height;
110         this._designResolutionSize = cc.size(w, h);
111         this._originalDesignResolutionSize = cc.size(w, h);
112         this._viewPortRect = cc.rect(0, 0, w, h);
113         this._visibleRect = cc.rect(0, 0, w, h);
114         this._delegate = cc.Director.getInstance().getTouchDispatcher();
115         this._contentTranslateLeftTop = {left: 0, top: 0};
116         this._viewName = "Cocos2dHTML5";
117 
118         cc.VisibleRect.init(this._designResolutionSize);
119 
120         // Setup system default resolution policies
121         this._rpExactFit = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.EXACT_FIT);
122         this._rpShowAll = new cc.ResolutionPolicy(cc.ContainerStrategy.PROPORTION_TO_FRAME, cc.ContentStrategy.SHOW_ALL);
123         this._rpNoBorder = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.NO_BORDER);
124         this._rpFixedHeight = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.FIXED_HEIGHT);
125         this._rpFixedWidth = new cc.ResolutionPolicy(cc.ContainerStrategy.EQUAL_TO_FRAME, cc.ContentStrategy.FIXED_WIDTH);
126 
127         this._hDC = cc.canvas;
128         this._hRC = cc.renderContext;
129     },
130 
131     // Resize helper functions
132     _resizeEvent: function () {
133         var width = this._originalDesignResolutionSize.width;
134         var height = this._originalDesignResolutionSize.height;
135         if (this._resizeCallback) {
136             this._initFrameSize();
137             this._resizeCallback.call();
138         }
139         if (width > 0)
140             this.setDesignResolutionSize(width, height, this._resolutionPolicy);
141     },
142 
143     resizeWithBrowserSize: function (enabled) {
144         var adjustSize;
145         if (enabled) {
146             //enable
147             if (!this.__resizeWithBrowserSize) {
148                 this.__resizeWithBrowserSize = true;
149                 adjustSize = this._resizeEvent.bind(this);
150                 window.addEventListener('resize', adjustSize, false);
151             }
152         } else {
153             //disable
154             if (this.__resizeWithBrowserSize) {
155                 this.__resizeWithBrowserSize = true;
156                 adjustSize = this._resizeEvent.bind(this);
157                 window.removeEventListener('resize', adjustSize, false);
158             }
159         }
160     },
161 
162     setResizeCallback: function (callback) {
163         if (typeof callback == "function" || callback == null) {
164             this._resizeCallback = callback;
165         }
166     },
167 
168     _initFrameSize: function () {
169         var locFrameSize = this._frameSize;
170         locFrameSize.width = this._frame.clientWidth;
171         locFrameSize.height = this._frame.clientHeight;
172     },
173 
174     // hack
175     _adjustSizeKeepCanvasSize: function (width, height) {
176         var designWidth = this._originalDesignResolutionSize.width;
177         var designHeight = this._originalDesignResolutionSize.height;
178         if (designWidth > 0)
179             this.setDesignResolutionSize(designWidth, designHeight, this._resolutionPolicy);
180     },
181 
182     _setViewPortMeta: function (width, height) {
183         if (this._isAdjustViewPort) {
184 	        var viewportMetas = {"user-scalable": "no", "maximum-scale": "1.0", "initial-scale": "1.0"}, elems = document.getElementsByName("viewport"), vp, content;
185             if (elems.length == 0) {
186                 vp = document.createElement("meta");
187                 vp.name = "viewport";
188                 vp.content = "";
189                 document.head.appendChild(vp);
190             }
191             else vp = elems[0];
192 
193 	        // For avoiding Android Firefox issue, to remove once firefox fixes its issue.
194 	        if (cc.Browser.isMobile && cc.Browser.type == "firefox") {
195 		        vp.content = "initial-scale:1";
196 		        return;
197 	        }
198 
199             content = vp.content;
200             for (var key in viewportMetas) {
201                 var pattern = new RegExp(key);
202                 if (!pattern.test(content)) {
203                     content += (content == "" ? "" : ",") + key + "=" + viewportMetas[key];
204                 }
205             }
206             /*
207             if(width<=320){
208                 width = 321;
209             }
210             if(height)
211                 content ="height="+height+","+content;
212             if(width)
213                 content ="width="+width+","+content;
214             */
215             vp.content = content;
216         }
217     },
218 
219     // RenderTexture hacker
220     _setScaleXYForRenderTexture: function () {
221         //hack for RenderTexture on canvas mode when adapting multiple resolution resources
222         var scaleFactor = cc.CONTENT_SCALE_FACTOR();
223         this._scaleX = scaleFactor;
224         this._scaleY = scaleFactor;
225     },
226 
227     // Other helper functions
228     _resetScale: function () {
229         this._scaleX = this._originalScaleX;
230         this._scaleY = this._originalScaleY;
231     },
232 
233     _getUnUsedIndex: function () {
234         var i;
235         var temp = this._indexBitsUsed;
236 
237         for (i = 0; i < this._maxTouches; i++) {
238             if (!(temp & 0x00000001)) {
239                 this._indexBitsUsed |= (1 << i);
240                 return i;
241             }
242 
243             temp >>= 1;
244         }
245 
246         // all bits are used
247         return -1;
248     },
249 
250     _removeUsedIndexBit: function (index) {
251         if (index < 0 || index >= this._maxTouches) {
252             return;
253         }
254 
255         var temp = 1 << index;
256         temp = ~temp;
257         this._indexBitsUsed &= temp;
258     },
259 
260     // Useless, just make sure the compatibility temporarily, should be removed
261     _adjustSizeToBrowser: function () {
262     },
263 
264     /**
265      * init
266      */
267     initialize: function () {
268         this._initialized = true;
269     },
270 
271     adjustViewPort: function (enabled) {
272         this._isAdjustViewPort = enabled;
273     },
274 
275     /**
276      * Force destroying EGL view, subclass must implement this method.
277      */
278     end: function () {
279     },
280 
281     /**
282      * Get whether render system is ready(no matter opengl or canvas),
283      * this name is for the compatibility with cocos2d-x, subclass must implement this method.
284      * @return {Boolean}
285      */
286     isOpenGLReady: function () {
287         return (this._hDC != null && this._hRC != null);
288     },
289 
290     /*
291      * Set zoom factor for frame. This method is for debugging big resolution (e.g.new ipad) app on desktop.
292      * @param {Number} zoomFactor
293      */
294     setFrameZoomFactor: function (zoomFactor) {
295         this._frameZoomFactor = zoomFactor;
296         this.centerWindow();
297         cc.Director.getInstance().setProjection(cc.Director.getInstance().getProjection());
298     },
299 
300     /**
301      * Exchanges the front and back buffers, subclass must implement this method.
302      */
303     swapBuffers: function () {
304     },
305 
306     /**
307      * Open or close IME keyboard , subclass must implement this method.
308      */
309     setIMEKeyboardState: function (isOpen) {
310         if (isOpen) {
311             // [EAGLView sharedEGLView] becomeFirstResponder
312         } else {
313             //  [EAGLView sharedEGLView] resignFirstResponder
314         }
315     },
316 
317     /**
318      * <p>
319      *   The resolution translate on EGLView
320      * </p>
321      * @param {Number} offsetLeft
322      * @param {Number} offsetTop
323      */
324     setContentTranslateLeftTop: function (offsetLeft, offsetTop) {
325         this._contentTranslateLeftTop = {left: offsetLeft, top: offsetTop};
326     },
327 
328     /**
329      * <p>
330      *   get the resolution translate on EGLView
331      * </p>
332      * @return {cc.Size|Object}
333      */
334     getContentTranslateLeftTop: function () {
335         return this._contentTranslateLeftTop;
336     },
337 
338     /**
339      * Get the frame size of EGL view.
340      * In general, it returns the screen size since the EGL view is a fullscreen view.
341      * @return {cc.Size}
342      */
343     getFrameSize: function () {
344         return cc.size(this._frameSize.width, this._frameSize.height);
345     },
346 
347     /**
348      * Set the frame size of EGL view.
349      * @param {Number} width
350      * @param {Number} height
351      */
352     setFrameSize: function (width, height) {
353         this._frameSize.width = width;
354         this._frameSize.height = height;
355         this._frame.style.width = width + "px";
356         this._frame.style.height = height + "px";
357         //this.centerWindow();
358         this._resizeEvent();
359         cc.Director.getInstance().setProjection(cc.Director.getInstance().getProjection());
360     },
361 
362     centerWindow: function () {
363     },
364 
365     setAccelerometerKeyHook: function (accelerometerKeyHook) {
366         this._accelerometerKeyHook = accelerometerKeyHook;
367     },
368 
369     /**
370      * Get the visible area size of opengl viewport.
371      * @return {cc.Size}
372      */
373     getVisibleSize: function () {
374         return this._visibleRect._size;
375     },
376 
377     /**
378      * Get the visible origin povar of opengl viewport.
379      * @return {cc.Point}
380      */
381     getVisibleOrigin: function () {
382         return this._visibleRect._origin;
383     },
384 
385     canSetContentScaleFactor: function () {
386         return true;
387     },
388 
389     /**
390      * Get the current resolution policy
391      * @return {cc.ResolutionPolicy}
392      */
393     getResolutionPolicy: function () {
394         return this._resolutionPolicy;
395     },
396 
397     /**
398      * Set the current resolution policy
399      * @param {cc.ResolutionPolicy|Number} resolutionPolicy
400      */
401     setResolutionPolicy: function (resolutionPolicy) {
402         if (resolutionPolicy instanceof cc.ResolutionPolicy) {
403             this._resolutionPolicy = resolutionPolicy;
404         }
405         // Ensure compatibility with JSB
406         else {
407             switch (resolutionPolicy) {
408                 case cc.RESOLUTION_POLICY.EXACT_FIT:
409                     this._resolutionPolicy = this._rpExactFit;
410                     break;
411                 case cc.RESOLUTION_POLICY.SHOW_ALL:
412                     this._resolutionPolicy = this._rpShowAll;
413                     break;
414                 case cc.RESOLUTION_POLICY.NO_BORDER:
415                     this._resolutionPolicy = this._rpNoBorder;
416                     break;
417                 case cc.RESOLUTION_POLICY.FIXED_HEIGHT:
418                     this._resolutionPolicy = this._rpFixedHeight;
419                     break;
420                 case cc.RESOLUTION_POLICY.FIXED_WIDTH:
421                     this._resolutionPolicy = this._rpFixedWidth;
422                     break;
423             }
424         }
425     },
426 
427     /**
428      * Set the design resolution size.
429      * @param {Number} width Design resolution width.
430      * @param {Number} height Design resolution height.
431      * @param {cc.ResolutionPolicy|Number} resolutionPolicy The resolution policy desired, you may choose:
432      * [1] ResolutionExactFit       Fill screen by stretch-to-fit: if the design resolution ratio of width to height is different from the screen resolution ratio, your game view will be stretched.
433      * [2] ResolutionNoBorder       Full screen without black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two areas of your game view will be cut.
434      * [3] ResolutionShowAll        Full screen with black border: if the design resolution ratio of width to height is different from the screen resolution ratio, two black borders will be shown.
435      * [4] ResolutionFixedHeight    Scale the content's height to screen's height and proportionally scale its width
436      * [5] ResolutionFixedWidth     Scale the content's width to screen's width and proportionally scale its height
437      * [cc.ResolutionPolicy]        Custom resolution policy, constructed by cc.ResolutionPolicy
438      */
439     setDesignResolutionSize: function (width, height, resolutionPolicy) {
440         // Defensive code
441         if (isNaN(width) || width == 0 || isNaN(height) || height == 0) {
442             cc.log("Resolution not valid");
443             return;
444         }
445         this.setResolutionPolicy(resolutionPolicy);
446         var policy = this._resolutionPolicy;
447         if (policy)
448             policy.preApply(this);
449         else {
450             cc.log("should set resolutionPolicy");
451             return;
452         }
453 
454         // Reinit frame size
455         var frameW = this._frameSize.width, frameH = this._frameSize.height;
456         if (cc.Browser.isMobile)
457             this._setViewPortMeta(this._frameSize.width, this._frameSize.height);
458         this._initFrameSize();
459         // No change
460         if (resolutionPolicy == this._resolutionPolicy
461             && width == this._originalDesignResolutionSize.width && height == this._originalDesignResolutionSize.height
462             && frameW == this._frameSize.width && frameH == this._frameSize.height)
463             return;
464         this._designResolutionSize = cc.size(width, height);
465         this._originalDesignResolutionSize = cc.size(width, height);
466 
467         var result = policy.apply(this, this._designResolutionSize);
468         if (result.scale && result.scale.length == 2) {
469             this._scaleX = result.scale[0];
470             this._scaleY = result.scale[1];
471         }
472         if (result.viewport instanceof cc.Rect) {
473             var vp = this._viewPortRect = result.viewport, visible = this._visibleRect;
474             visible._size.width = cc.canvas.width / this._scaleX;
475             visible._size.height = cc.canvas.height / this._scaleY;
476             visible._origin.x = -vp.x / this._scaleX;
477             visible._origin.y = -vp.y / this._scaleY;
478         }
479 
480         // reset director's member variables to fit visible rect
481         var director = cc.Director.getInstance();
482         director._winSizeInPoints = this.getDesignResolutionSize();
483 
484         policy.postApply(this);
485 
486         if (cc.renderContextType == cc.WEBGL) {
487             // reset director's member variables to fit visible rect
488             director._createStatsLabel();
489             director.setGLDefaultValues();
490         }
491 
492         this._originalScaleX = this._scaleX;
493         this._originalScaleY = this._scaleY;
494         // For editbox
495         if (cc.DOM) {
496             cc.DOM._resetEGLViewDiv();
497         }
498 
499         cc.VisibleRect.init(this.getVisibleSize());
500     },
501 
502     /**
503      * Get design resolution size.
504      * Default resolution size is the same as 'getFrameSize'.
505      * @return {cc.Size}
506      */
507     getDesignResolutionSize: function () {
508         return cc.size(this._designResolutionSize.width, this._designResolutionSize.height);
509     },
510 
511     /**
512      * set touch delegate
513      * @param {cc.TouchDispatcher} delegate
514      */
515     setTouchDelegate: function (delegate) {
516         this._delegate = delegate;
517     },
518 
519     /**
520      * Set opengl view port rectangle with points.
521      * @param {Number} x
522      * @param {Number} y
523      * @param {Number} w width
524      * @param {Number} h height
525      */
526     setViewPortInPoints: function (x, y, w, h) {
527         var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY;
528         cc.renderContext.viewport((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor),
529             (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor),
530             (w * locScaleX * locFrameZoomFactor),
531             (h * locScaleY * locFrameZoomFactor));
532     },
533 
534     /**
535      * Set Scissor rectangle with points.
536      * @param {Number} x
537      * @param {Number} y
538      * @param {Number} w
539      * @param {Number} h
540      */
541     setScissorInPoints: function (x, y, w, h) {
542         var locFrameZoomFactor = this._frameZoomFactor, locScaleX = this._scaleX, locScaleY = this._scaleY;
543         cc.renderContext.scissor((x * locScaleX * locFrameZoomFactor + this._viewPortRect.x * locFrameZoomFactor),
544             (y * locScaleY * locFrameZoomFactor + this._viewPortRect.y * locFrameZoomFactor),
545             (w * locScaleX * locFrameZoomFactor),
546             (h * locScaleY * locFrameZoomFactor));
547     },
548 
549     /**
550      * Get whether GL_SCISSOR_TEST is enable
551      */
552     isScissorEnabled: function () {
553         var gl = cc.renderContext;
554         return gl.isEnabled(gl.SCISSOR_TEST);
555     },
556 
557     /**
558      * Get the current scissor rectangle
559      * @return {cc.Rect}
560      */
561     getScissorRect: function () {
562         var gl = cc.renderContext, scaleX = this._scaleX, scaleY = this._scaleY;
563         var boxArr = gl.getParameter(gl.SCISSOR_BOX);
564         return cc.rect((boxArr[0] - this._viewPortRect.x) / scaleX, (boxArr[1] - this._viewPortRect.y) / scaleY,
565             boxArr[2] / scaleX, boxArr[3] / scaleY);
566     },
567 
568     /**
569      * @param {String} viewName
570      */
571     setViewName: function (viewName) {
572         if (viewName != null && viewName.length > 0) {
573             this._viewName = viewName;
574         }
575     },
576 
577     /**
578      * get view name
579      * @return {String}
580      */
581     getViewName: function () {
582         return this._viewName;
583     },
584 
585     /**
586      * Get the opengl view port rectangle.
587      */
588     getViewPortRect: function () {
589         return this._viewPortRect;
590     },
591 
592     /**
593      * Get scale factor of the horizontal direction.
594      */
595     getScaleX: function () {
596         return this._scaleX;
597     },
598 
599     /**
600      * Get scale factor of the vertical direction.
601      */
602     getScaleY: function () {
603         return this._scaleY;
604     },
605 
606     /**
607      * Get device pixel ratio for retina display.
608      */
609     getDevicePixelRatio: function() {
610         return this._devicePixelRatio;
611     },
612 
613     /**
614      * Get the real location in view
615      */
616     convertToLocationInView: function (tx, ty, relatedPos) {
617         return {x: this._devicePixelRatio * (tx - relatedPos.left), y: this._devicePixelRatio * (relatedPos.top + relatedPos.height - ty)};
618     },
619 
620     /**
621      * Touch events are handled by default; if you want to customize your handlers, please override these functions:
622      * @param {Number} num
623      * @param {Array} ids
624      * @param {Array} xs
625      * @param {Array} ys
626      */
627     handleTouchesBegin: function (num, ids, xs, ys) {
628         var arr = [], locViewPortRect = this._viewPortRect, locScaleX = this._scaleX, locScaleY = this._scaleY;
629         for (var i = 0; i < num; ++i) {
630             var id = ids[i];
631             var x = xs[i];
632             var y = ys[i];
633 
634             var index = cc.TouchesIntergerDict[id];
635             var unusedIndex = 0;
636 
637             // it is a new touch
638             if (index == null) {
639                 unusedIndex = this._getUnUsedIndex();
640 
641                 // The touches is more than MAX_TOUCHES ?
642                 if (unusedIndex == -1) {
643                     cc.log("The touches is more than MAX_TOUCHES, nUnusedIndex = " + unusedIndex);
644                     continue;
645                 }
646 
647                 var touch = cc.Touches[unusedIndex] = new cc.Touch();
648                 touch.setTouchInfo(unusedIndex, (x - locViewPortRect.x) / locScaleX,
649                     (y - locViewPortRect.y) / locScaleY);
650 
651                 cc.TouchesIntergerDict[id] = 0 | unusedIndex;
652                 arr.push(touch);
653             }
654         }
655 
656         if (arr.length !== 0)
657             this._delegate.touchesBegan(arr, null);
658     },
659 
660     /**
661      * @param {Number} num
662      * @param {Number} ids
663      * @param {Number} xs
664      * @param {Number} ys
665      */
666     handleTouchesMove: function (num, ids, xs, ys) {
667         var arr = [];
668         var locScaleX = this._scaleX, locScaleY = this._scaleY, locViewPortX = this._viewPortRect.x, locViewPortY = this._viewPortRect.y;
669         for (var i = 0; i < num; ++i) {
670             var id = ids[i];
671             var x = xs[i];
672             var y = ys[i];
673 
674             var index = cc.TouchesIntergerDict[id];
675             if (index == null) {
676                 //cc.log("if the index doesn't exist, it is an error");
677                 continue;
678             }
679 
680             var touch = cc.Touches[index];
681             if (touch) {
682                 touch.setTouchInfo(index, (x - locViewPortX) / locScaleX,
683                     (y - locViewPortY) / locScaleY);
684                 arr.push(touch);
685             }
686             else {
687                 // It is error, should return.
688                 //cc.log("Moving touches with id: " + id + " error");
689                 return;
690             }
691         }
692 
693         if (arr.length == 0) {
694             //cc.log("touchesMoved: count = 0");
695             return;
696         }
697 
698         this._delegate.touchesMoved(arr, null);
699     },
700 
701     /**
702      * @param {Number} num
703      * @param {Number} ids
704      * @param {Number} xs
705      * @param {Number} ys
706      */
707     handleTouchesEnd: function (num, ids, xs, ys) {
708         var arr = [];
709         this.getSetOfTouchesEndOrCancel(arr, num, ids, xs, ys);
710         this._delegate.touchesEnded(arr, null);
711     },
712 
713     /**
714      * @param {Number} num
715      * @param {Number} ids
716      * @param {Number} xs
717      * @param {Number} ys
718      */
719     handleTouchesCancel: function (num, ids, xs, ys) {
720         var arr = [];
721         this.getSetOfTouchesEndOrCancel(arr, num, ids, xs, ys);
722         this._delegate.touchesCancelled(arr, null);
723     },
724 
725     /**
726      * @param {Array} arr
727      * @param {Number} num
728      * @param {Number} ids
729      * @param {Number} xs
730      * @param {Number} ys
731      */
732     getSetOfTouchesEndOrCancel: function (arr, num, ids, xs, ys) {
733         var locScaleX = this._scaleX, locScaleY = this._scaleY, locViewPortRect = this._viewPortRect;
734         for (var i = 0; i < num; ++i) {
735             var id = ids[i];
736             var x = xs[i];
737             var y = ys[i];
738 
739             var index = cc.TouchesIntergerDict[id];
740             if (index == null) {
741                 //cc.log("if the index doesn't exist, it is an error");
742                 continue;
743             }
744             /* Add to the set to send to the director */
745             var touch = cc.Touches[index];
746             if (touch) {
747                 //cc.log("Ending touches with id: " + id + ", x=" + x + ", y=" + y);
748                 touch.setTouchInfo(index, (x - locViewPortRect.x) / locScaleX,
749                     (y - locViewPortRect.y) / locScaleY);
750 
751                 arr.push(touch);
752 
753                 // release the object
754                 cc.Touches[index] = null;
755                 this._removeUsedIndexBit(index);
756 
757                 delete cc.TouchesIntergerDict[id];
758             } else {
759                 //cc.log("Ending touches with id: " + id + " error");
760                 return;
761             }
762         }
763     },
764 
765     // Pass the touches to the superview
766     touchesBegan: function (touches, event) {
767         var ids = [];
768         var xs = [];
769         var ys = [];
770 
771         var i = 0;
772         var touch;
773         for (var j = 0; j < touches.length; j++) {
774             touch = touches[j];
775             ids[i] = touch.getId() || j;
776             xs[i] = touch.getLocation().x;
777             ys[i] = touch.getLocation().y;
778             ++i;
779         }
780         this.handleTouchesBegin(i, ids, xs, ys);
781     },
782 
783     touchesMoved: function (touches, event) {
784         var ids = [];
785         var xs = [];
786         var ys = [];
787 
788         var i = 0;
789         var touch;
790         for (var j = 0; j < touches.length; j++) {
791             touch = touches[j];
792             ids[i] = touch.getId() || j;
793             xs[i] = touch.getLocation().x;
794             ys[i] = touch.getLocation().y;
795             ++i;
796         }
797         this.handleTouchesMove(i, ids, xs, ys);
798     },
799 
800     touchesEnded: function (touches, event) {
801         var ids = [];
802         var xs = [];
803         var ys = [];
804 
805         var i = 0;
806         var touch;
807         for (var j = 0; j < touches.length; j++) {
808             touch = touches[j];
809             ids[i] = touch.getId() || j;
810             xs[i] = touch.getLocation().x;
811             ys[i] = touch.getLocation().y;
812             ++i;
813         }
814         this.handleTouchesEnd(i, ids, xs, ys);
815     },
816 
817     touchesCancelled: function (touches, event) {
818         var ids = [];
819         var xs = [];
820         var ys = [];
821 
822         var i = 0;
823         var touch;
824         for (var j = 0; j < touches.length; j++) {
825             touch = touches[j];
826             ids[i] = touch.getId() || j;
827             xs[i] = touch.getLocation().x;
828             ys[i] = touch.getLocation().y;
829             ++i;
830         }
831         this.handleTouchesCancel(i, ids, xs, ys);
832     }
833 });
834 
835 
836 cc.EGLView.getInstance = function () {
837     if (!this._instance) {
838 	    // First init director
839 	    cc.Director.getInstance();
840 
841         this._instance = this._instance || new cc.EGLView();
842         this._instance.initialize();
843     }
844     return this._instance;
845 };
846 
847 
848 /**
849  * <p>cc.ContainerStrategy class is the root strategy class of container's scale strategy,
850  * it controls the behavior of how to scale the cc.container and cc.canvas object</p>
851  *
852  * @class
853  * @extends cc.Class
854  */
855 
856 cc.ContainerStrategy = cc.Class.extend({
857     // Adjust canvas's size for retina display
858     _adjustRetina: false,
859 
860     /**
861      * Manipulation before appling the strategy
862      * @param {cc.EGLView} The target view
863      */
864     preApply: function (view) {
865 	    if(sys.os == "iOS" || sys.os == "OS X")
866 		    this._adjustRetina = true;
867     },
868 
869     /**
870      * Function to apply this strategy
871      * @param {cc.EGLView} view
872      * @param {cc.Size} designedResolution
873      */
874     apply: function (view, designedResolution) {
875     },
876 
877     /**
878      * Manipulation after appling the strategy
879      * @param {cc.EGLView} The target view
880      */
881     postApply: function (view) {
882 
883     },
884 
885     _setupContainer: function (view, w, h) {
886         var frame = view._frame;
887         if (cc.Browser.isMobile && frame == document.documentElement) {
888             // Automatically full screen when user touches on mobile version
889             cc.Screen.getInstance().autoFullScreen(frame);
890         }
891 
892         var locCanvasElement = cc.canvas, locContainer = cc.container;
893         // Setup container
894         locContainer.style.width = locCanvasElement.style.width = w + "px";
895         locContainer.style.height = locCanvasElement.style.height = h + "px";
896         // Setup pixel ratio for retina display
897         var devicePixelRatio = view._devicePixelRatio = 1;
898         if (this._adjustRetina)
899             devicePixelRatio = view._devicePixelRatio = window.devicePixelRatio || 1;
900         // Setup canvas
901         locCanvasElement.width = w * devicePixelRatio;
902         locCanvasElement.height = h * devicePixelRatio;
903 
904         var body = document.body, style;
905         if (body && (style = body.style)) {
906             style.paddingTop = style.paddingTop || "0px";
907             style.paddingRight = style.paddingRight || "0px";
908             style.paddingBottom = style.paddingBottom || "0px";
909             style.paddingLeft = style.paddingLeft || "0px";
910             style.borderTop = style.borderTop || "0px";
911             style.borderRight = style.borderRight || "0px";
912             style.borderBottom = style.borderBottom || "0px";
913             style.borderLeft = style.borderLeft || "0px";
914             style.marginTop = style.marginTop || "0px";
915             style.marginRight = style.marginRight || "0px";
916             style.marginBottom = style.marginBottom || "0px";
917             style.marginLeft = style.marginLeft || "0px";
918         }
919     },
920 
921     _fixContainer: function () {
922         // Add container to document body
923         document.body.insertBefore(cc.container, document.body.firstChild);
924         // Set body's width height to window's size, and forbid overflow, so that game will be centered
925         var bs = document.body.style;
926         bs.width = window.innerWidth + "px";
927         bs.height = window.innerHeight + "px";
928         bs.overflow = "hidden";
929         // Body size solution doesn't work on all mobile browser so this is the aleternative: fixed container
930         var contStyle = cc.container.style;
931         contStyle.position = "fixed";
932         contStyle.left = contStyle.top = "0px";
933         // Reposition body
934         document.body.scrollTop = 0;
935     }
936 });
937 
938 /**
939  * <p>cc.ContentStrategy class is the root strategy class of content's scale strategy,
940  * it controls the behavior of how to scale the scene and setup the viewport for the game</p>
941  *
942  * @class
943  * @extends cc.Class
944  */
945 
946 cc.ContentStrategy = cc.Class.extend({
947 
948     _result: {
949         scale: [1, 1],
950         viewport: null
951     },
952 
953     _buildResult: function (containerW, containerH, contentW, contentH, scaleX, scaleY) {
954 	    // Makes content fit better the canvas
955 	    Math.abs(containerW - contentW) < 2 && (contentW = containerW);
956 	    Math.abs(containerH - contentH) < 2 && (contentH = containerH);
957 
958         var viewport = cc.rect(Math.round((containerW - contentW) / 2),
959                                Math.round((containerH - contentH) / 2),
960                                contentW, contentH);
961 
962         // Translate the content
963         if (cc.renderContextType == cc.CANVAS)
964             cc.renderContext.translate(viewport.x, viewport.y + contentH);
965 
966         this._result.scale = [scaleX, scaleY];
967         this._result.viewport = viewport;
968         return this._result;
969     },
970 
971     /**
972      * Manipulation before appling the strategy
973      * @param {cc.EGLView} The target view
974      */
975     preApply: function (view) {
976     },
977 
978     /**
979      * Function to apply this strategy
980      * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}},
981      * The target view can then apply these value to itself, it's prefered not to modify directly its private variables
982      * @param {cc.EGLView} view
983      * @param {cc.Size} designedResolution
984      * @return {object} scaleAndViewportRect
985      */
986     apply: function (view, designedResolution) {
987         return {"scale": [1, 1]};
988     },
989 
990     /**
991      * Manipulation after appling the strategy
992      * @param {cc.EGLView} The target view
993      */
994     postApply: function (view) {
995     }
996 });
997 
998 (function () {
999 
1000 // Container scale strategys
1001     var EqualToFrame = cc.ContainerStrategy.extend({
1002         apply: function (view) {
1003             this._setupContainer(view, view._frameSize.width, view._frameSize.height);
1004         }
1005     });
1006 
1007     var ProportionalToFrame = cc.ContainerStrategy.extend({
1008         apply: function (view, designedResolution) {
1009             var frameW = view._frameSize.width, frameH = view._frameSize.height, containerStyle = cc.container.style,
1010                 designW = designedResolution.width, designH = designedResolution.height,
1011                 scaleX = frameW / designW, scaleY = frameH / designH,
1012                 containerW, containerH;
1013 
1014             scaleX < scaleY ? (containerW = frameW, containerH = designH * scaleX) : (containerW = designW * scaleY, containerH = frameH);
1015 
1016             // Adjust container size with integer value
1017             var offx = Math.round((frameW - containerW) / 2);
1018             var offy = Math.round((frameH - containerH) / 2);
1019             containerW = frameW - 2 * offx;
1020             containerH = frameH - 2 * offy;
1021 
1022             this._setupContainer(view, containerW, containerH);
1023             // Setup container's margin
1024             containerStyle.marginLeft = offx + "px";
1025             containerStyle.marginRight = offx + "px";
1026             containerStyle.marginTop = offy + "px";
1027             containerStyle.marginBottom = offy + "px";
1028         }
1029     });
1030 
1031     var EqualToWindow = EqualToFrame.extend({
1032         preApply: function (view) {
1033 	        this._super(view);
1034             view._frame = document.documentElement;
1035         },
1036 
1037         apply: function (view) {
1038             this._super(view);
1039             this._fixContainer();
1040         }
1041     });
1042 
1043     var ProportionalToWindow = ProportionalToFrame.extend({
1044         preApply: function (view) {
1045 	        this._super(view);
1046             view._frame = document.documentElement;
1047         },
1048 
1049         apply: function (view, designedResolution) {
1050             this._super(view, designedResolution);
1051             this._fixContainer();
1052         }
1053     });
1054 
1055     var OriginalContainer = cc.ContainerStrategy.extend({
1056         apply: function (view) {
1057             this._setupContainer(view, cc.canvas.width, cc.canvas.height);
1058         }
1059     });
1060 
1061 // #NOT STABLE on Android# Alias: Strategy that makes the container's size equals to the window's size
1062 //    cc.ContainerStrategy.EQUAL_TO_WINDOW = new EqualToWindow();
1063 // #NOT STABLE on Android# Alias: Strategy that scale proportionally the container's size to window's size
1064 //    cc.ContainerStrategy.PROPORTION_TO_WINDOW = new ProportionalToWindow();
1065 // Alias: Strategy that makes the container's size equals to the frame's size
1066     cc.ContainerStrategy.EQUAL_TO_FRAME = new EqualToFrame();
1067 // Alias: Strategy that scale proportionally the container's size to frame's size
1068     cc.ContainerStrategy.PROPORTION_TO_FRAME = new ProportionalToFrame();
1069 // Alias: Strategy that keeps the original container's size
1070     cc.ContainerStrategy.ORIGINAL_CONTAINER = new OriginalContainer();
1071 
1072 // Content scale strategys
1073     var ExactFit = cc.ContentStrategy.extend({
1074         apply: function (view, designedResolution) {
1075             var containerW = cc.canvas.width, containerH = cc.canvas.height,
1076                 scaleX = containerW / designedResolution.width, scaleY = containerH / designedResolution.height;
1077 
1078             return this._buildResult(containerW, containerH, containerW, containerH, scaleX, scaleY);
1079         }
1080     });
1081 
1082     var ShowAll = cc.ContentStrategy.extend({
1083         apply: function (view, designedResolution) {
1084             var containerW = cc.canvas.width, containerH = cc.canvas.height,
1085                 designW = designedResolution.width, designH = designedResolution.height,
1086                 scaleX = containerW / designW, scaleY = containerH / designH, scale = 0,
1087                 contentW, contentH;
1088 
1089 	        scaleX < scaleY ? (scale = scaleX, contentW = containerW, contentH = designH * scale)
1090                 : (scale = scaleY, contentW = designW * scale, contentH = containerH);
1091 
1092             return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
1093         }
1094     });
1095 
1096     var NoBorder = cc.ContentStrategy.extend({
1097         apply: function (view, designedResolution) {
1098             var containerW = cc.canvas.width, containerH = cc.canvas.height,
1099                 designW = designedResolution.width, designH = designedResolution.height,
1100                 scaleX = containerW / designW, scaleY = containerH / designH, scale,
1101                 contentW, contentH;
1102 
1103             scaleX < scaleY ? (scale = scaleY, contentW = designW * scale, contentH = containerH)
1104                 : (scale = scaleX, contentW = containerW, contentH = designH * scale);
1105 
1106             return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
1107         }
1108     });
1109 
1110     var FixedHeight = cc.ContentStrategy.extend({
1111         apply: function (view, designedResolution) {
1112             var containerW = cc.canvas.width, containerH = cc.canvas.height,
1113                 designH = designedResolution.height, scale = containerH / designH,
1114                 contentW = containerW, contentH = containerH;
1115 
1116             return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
1117         },
1118 
1119         postApply: function (view) {
1120             cc.Director.getInstance()._winSizeInPoints = view.getVisibleSize();
1121         }
1122     });
1123 
1124     var FixedWidth = cc.ContentStrategy.extend({
1125         apply: function (view, designedResolution) {
1126             var containerW = cc.canvas.width, containerH = cc.canvas.height,
1127                 designW = designedResolution.width, scale = containerW / designW,
1128                 contentW = containerW, contentH = containerH;
1129 
1130             return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
1131         },
1132 
1133         postApply: function (view) {
1134             cc.Director.getInstance()._winSizeInPoints = view.getVisibleSize();
1135         }
1136     });
1137 
1138 // Alias: Strategy to scale the content's size to container's size, non proportional
1139     cc.ContentStrategy.EXACT_FIT = new ExactFit();
1140 // Alias: Strategy to scale the content's size proportionally to maximum size and keeps the whole content area to be visible
1141     cc.ContentStrategy.SHOW_ALL = new ShowAll();
1142 // Alias: Strategy to scale the content's size proportionally to fill the whole container area
1143     cc.ContentStrategy.NO_BORDER = new NoBorder();
1144 // Alias: Strategy to scale the content's height to container's height and proportionally scale its width
1145     cc.ContentStrategy.FIXED_HEIGHT = new FixedHeight();
1146 // Alias: Strategy to scale the content's width to container's width and proportionally scale its height
1147     cc.ContentStrategy.FIXED_WIDTH = new FixedWidth();
1148 
1149 })();
1150 
1151 /**
1152  * <p>cc.ResolutionPolicy class is the root strategy class of scale strategy,
1153  * its main task is to maintain the compatibility with Cocos2d-x</p>
1154  *
1155  * @class
1156  * @extends cc.Class
1157  */
1158 cc.ResolutionPolicy = cc.Class.extend({
1159     _containerStrategy: null,
1160     _contentStrategy: null,
1161 
1162     ctor: function (containerStg, contentStg) {
1163         this.setContainerStrategy(containerStg);
1164         this.setContentStrategy(contentStg);
1165     },
1166 
1167     /**
1168      * Manipulation before appling the resolution policy
1169      * @param {cc.EGLView} The target view
1170      */
1171     preApply: function (view) {
1172         this._containerStrategy.preApply(view);
1173         this._contentStrategy.preApply(view);
1174     },
1175 
1176     /**
1177      * Function to apply this resolution policy
1178      * The return value is {scale: [scaleX, scaleY], viewport: {cc.Rect}},
1179      * The target view can then apply these value to itself, it's prefered not to modify directly its private variables
1180      * @param {cc.EGLView} The target view
1181      * @param {cc.Size} The user defined design resolution
1182      * @return {object} An object contains the scale X/Y values and the viewport rect
1183      */
1184     apply: function (view, designedResolution) {
1185         this._containerStrategy.apply(view, designedResolution);
1186         return this._contentStrategy.apply(view, designedResolution);
1187     },
1188 
1189     /**
1190      * Manipulation after appling the strategy
1191      * @param {cc.EGLView} The target view
1192      */
1193     postApply: function (view) {
1194         this._containerStrategy.postApply(view);
1195         this._contentStrategy.postApply(view);
1196     },
1197 
1198     /**
1199      * Setup the container's scale strategy
1200      * @param {cc.ContainerStrategy} containerStg
1201      */
1202     setContainerStrategy: function (containerStg) {
1203         if (containerStg instanceof cc.ContainerStrategy)
1204             this._containerStrategy = containerStg;
1205     },
1206 
1207     /**
1208      * Setup the content's scale strategy
1209      * @param {cc.ContentStrategy} contentStg
1210      */
1211     setContentStrategy: function (contentStg) {
1212         if (contentStg instanceof cc.ContentStrategy)
1213             this._contentStrategy = contentStg;
1214     }
1215 });