1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies 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 /**
 28  * <p>cc.LabelTTF is a subclass of cc.TextureNode that knows how to render text labels with system font or a ttf font file<br/>
 29  * All features from cc.Sprite are valid in cc.LabelTTF<br/>
 30  * cc.LabelTTF objects are slow for js-binding on mobile devices.<br/>
 31  * Consider using cc.LabelAtlas or cc.LabelBMFont instead.<br/>
 32  * You can create a cc.LabelTTF from a font name, alignment, dimension and font size or a cc.FontDefinition object.</p>
 33  * @class
 34  * @extends cc.Sprite
 35  *
 36  * @param {String} text
 37  * @param {String|cc.FontDefinition} [fontName="Arial"]
 38  * @param {Number} [fontSize=16]
 39  * @param {cc.Size} [dimensions=cc.size(0,0)]
 40  * @param {Number} [hAlignment=cc.TEXT_ALIGNMENT_LEFT]
 41  * @param {Number} [vAlignment=cc.VERTICAL_TEXT_ALIGNMENT_TOP]
 42  * @example
 43  * var myLabel = new cc.LabelTTF('label text',  'Times New Roman', 32, cc.size(320,32), cc.TEXT_ALIGNMENT_LEFT);
 44  *
 45  * var fontDef = new cc.FontDefinition();
 46  * fontDef.fontName = "Arial";
 47  * fontDef.fontSize = "32";
 48  * var myLabel = new cc.LabelTTF('label text',  fontDef);
 49  *
 50  * @property {String}       string          - Content string of label
 51  * @property {Number}       textAlign       - Horizontal Alignment of label: cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT
 52  * @property {Number}       verticalAlign   - Vertical Alignment of label: cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM
 53  * @property {Number}       fontSize        - Font size of label
 54  * @property {String}       fontName        - Font name of label
 55  * @property {String}       font            - The label font with a style string: e.g. "18px Verdana"
 56  * @property {Number}       boundingWidth   - Width of the bounding box of label, the real content width is limited by boundingWidth
 57  * @property {Number}       boundingHeight  - Height of the bounding box of label, the real content height is limited by boundingHeight
 58  * @property {cc.Color}     fillStyle       - The fill color
 59  * @property {cc.Color}     strokeStyle     - The stroke color
 60  * @property {Number}       lineWidth       - The line width for stroke
 61  * @property {Number}       shadowOffsetX   - The x axis offset of shadow
 62  * @property {Number}       shadowOffsetY   - The y axis offset of shadow
 63  * @property {Number}       shadowOpacity   - The opacity of shadow
 64  * @property {Number}       shadowBlur      - The blur size of shadow
 65  */
 66 cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{
 67     _dimensions: null,
 68     _hAlignment: cc.TEXT_ALIGNMENT_CENTER,
 69     _vAlignment: cc.VERTICAL_TEXT_ALIGNMENT_TOP,
 70     _fontName: null,
 71     _fontSize: 0.0,
 72     _string: "",
 73     _originalText: null,
 74     _onCacheCanvasMode: true,
 75 
 76     // font shadow
 77     _shadowEnabled: false,
 78     _shadowOffset: null,
 79     _shadowOpacity: 0,
 80     _shadowBlur: 0,
 81     _shadowColor: null,
 82 
 83     // font stroke
 84     _strokeEnabled: false,
 85     _strokeColor: null,
 86     _strokeSize: 0,
 87 
 88     // font tint
 89     _textFillColor: null,
 90 
 91     _strokeShadowOffsetX: 0,
 92     _strokeShadowOffsetY: 0,
 93     _needUpdateTexture: false,
 94 
 95     _lineWidths: null,
 96     _className: "LabelTTF",
 97 
 98     //for web
 99     _fontStyle: "normal",
100     _fontWeight: "normal",
101     _lineHeight: "normal",
102 
103     /**
104      * Initializes the cc.LabelTTF with a font name, alignment, dimension and font size, do not call it by yourself,
105      * you should pass the correct arguments in constructor to initialize the label.
106      * @param {String} label string
107      * @param {String} fontName
108      * @param {Number} fontSize
109      * @param {cc.Size} [dimensions=]
110      * @param {Number} [hAlignment=]
111      * @param {Number} [vAlignment=]
112      * @return {Boolean} return false on error
113      */
114     initWithString: function (label, fontName, fontSize, dimensions, hAlignment, vAlignment) {
115         var strInfo;
116         if (label)
117             strInfo = label + "";
118         else
119             strInfo = "";
120 
121         fontSize = fontSize || 16;
122         dimensions = dimensions || cc.size(0, 0/*fontSize*/);
123         hAlignment = hAlignment || cc.TEXT_ALIGNMENT_LEFT;
124         vAlignment = vAlignment || cc.VERTICAL_TEXT_ALIGNMENT_TOP;
125 
126         this._opacityModifyRGB = false;
127         this._dimensions = cc.size(dimensions.width, dimensions.height);
128         this._fontName = fontName || "Arial";
129         this._hAlignment = hAlignment;
130         this._vAlignment = vAlignment;
131 
132         this._fontSize = fontSize;
133         this._renderCmd._setFontStyle(this._fontName, fontSize, this._fontStyle, this._fontWeight);
134         this.string = strInfo;
135         this._renderCmd._setColorsString();
136         this._renderCmd._updateTexture();
137         this._setUpdateTextureDirty();
138 
139         // Needed for high dpi text.
140         // In order to render it crisp, we request devicePixelRatio times the
141         // font size and scale it down 1/devicePixelRatio.
142         this._scaleX = this._scaleY = 1 / cc.view.getDevicePixelRatio();
143         return true;
144     },
145 
146     _setUpdateTextureDirty: function () {
147         this._needUpdateTexture = true;
148         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.textDirty);
149     },
150 
151     ctor: function (text, fontName, fontSize, dimensions, hAlignment, vAlignment) {
152         cc.Sprite.prototype.ctor.call(this);
153 
154         this._dimensions = cc.size(0, 0);
155         this._hAlignment = cc.TEXT_ALIGNMENT_LEFT;
156         this._vAlignment = cc.VERTICAL_TEXT_ALIGNMENT_TOP;
157         this._opacityModifyRGB = false;
158         this._fontName = "Arial";
159 
160         this._shadowEnabled = false;
161         this._shadowOffset = cc.p(0, 0);
162         this._shadowOpacity = 0;
163         this._shadowBlur = 0;
164 
165         this._strokeEnabled = false;
166         this._strokeColor = cc.color(255, 255, 255, 255);
167         this._strokeSize = 0;
168 
169         this._textFillColor = cc.color(255, 255, 255, 255);
170         this._strokeShadowOffsetX = 0;
171         this._strokeShadowOffsetY = 0;
172         this._needUpdateTexture = false;
173 
174         this._lineWidths = [];
175         this._renderCmd._setColorsString();
176         this._textureLoaded = true;
177 
178         if (fontName && fontName instanceof cc.FontDefinition) {
179             this.initWithStringAndTextDefinition(text, fontName);
180         } else {
181             cc.LabelTTF.prototype.initWithString.call(this, text, fontName, fontSize, dimensions, hAlignment, vAlignment);
182         }
183     },
184 
185     init: function () {
186         return this.initWithString(" ", this._fontName, this._fontSize);
187     },
188 
189     description: function () {
190         return "<cc.LabelTTF | FontName =" + this._fontName + " FontSize = " + this._fontSize.toFixed(1) + ">";
191     },
192 
193     getLineHeight: function () {
194         return !this._lineHeight || this._lineHeight.charAt ?
195             this._renderCmd._getFontClientHeight() :
196             this._lineHeight || this._renderCmd._getFontClientHeight();
197     },
198 
199     setLineHeight: function (lineHeight) {
200         this._lineHeight = lineHeight;
201     },
202 
203     /**
204      * Returns the text of the label
205      * @return {String}
206      */
207     getString: function () {
208         return this._string;
209     },
210 
211     /**
212      * Returns Horizontal Alignment of cc.LabelTTF
213      * @return {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT}
214      */
215     getHorizontalAlignment: function () {
216         return this._hAlignment;
217     },
218 
219     /**
220      * Returns Vertical Alignment of cc.LabelTTF
221      * @return {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM}
222      */
223     getVerticalAlignment: function () {
224         return this._vAlignment;
225     },
226 
227     /**
228      * Returns the dimensions of cc.LabelTTF, the dimension is the maximum size of the label, set it so that label will automatically change lines when necessary.
229      * @see cc.LabelTTF#setDimensions, cc.LabelTTF#boundingWidth and cc.LabelTTF#boundingHeight
230      * @return {cc.Size}
231      */
232     getDimensions: function () {
233         return cc.size(this._dimensions);
234     },
235 
236     /**
237      * Returns font size of cc.LabelTTF
238      * @return {Number}
239      */
240     getFontSize: function () {
241         return this._fontSize;
242     },
243 
244     /**
245      * Returns font name of cc.LabelTTF
246      * @return {String}
247      */
248     getFontName: function () {
249         return this._fontName;
250     },
251 
252     /**
253      * Initializes the CCLabelTTF with a font name, alignment, dimension and font size, do not call it by yourself, you should pass the correct arguments in constructor to initialize the label.
254      * @param {String} text
255      * @param {cc.FontDefinition} textDefinition
256      * @return {Boolean}
257      */
258     initWithStringAndTextDefinition: function (text, textDefinition) {
259         // prepare everything needed to render the label
260         this._updateWithTextDefinition(textDefinition, false);
261         // set the string
262         this.string = text;
263         return true;
264     },
265 
266     /**
267      * Sets the text definition used by this label
268      * @param {cc.FontDefinition} theDefinition
269      */
270     setTextDefinition: function (theDefinition) {
271         if (theDefinition)
272             this._updateWithTextDefinition(theDefinition, true);
273     },
274 
275     /**
276      * Extract the text definition used by this label
277      * @return {cc.FontDefinition}
278      */
279     getTextDefinition: function () {
280         return this._prepareTextDefinition(false);
281     },
282 
283     /**
284      * Enable or disable shadow for the label
285      * @param {cc.Color | Number} a Color or The x axis offset of the shadow
286      * @param {cc.Size | Number} b Size or The y axis offset of the shadow
287      * @param {Number} c The blur size of the shadow or The opacity of the shadow (0 to 1)
288      * @param {null | Number} d Null or The blur size of the shadow
289      * @example
290      *   old:
291      *     labelttf.enableShadow(shadowOffsetX, shadowOffsetY, shadowOpacity, shadowBlur);
292      *   new:
293      *     labelttf.enableShadow(shadowColor, offset, blurRadius);
294      */
295     enableShadow: function (a, b, c, d) {
296         if (a.r != null && a.g != null && a.b != null && a.a != null) {
297             this._enableShadow(a, b, c);
298         } else {
299             this._enableShadowNoneColor(a, b, c, d);
300         }
301     },
302 
303     _enableShadowNoneColor: function (shadowOffsetX, shadowOffsetY, shadowOpacity, shadowBlur) {
304         shadowOpacity = shadowOpacity || 0.5;
305         if (false === this._shadowEnabled)
306             this._shadowEnabled = true;
307 
308         var locShadowOffset = this._shadowOffset;
309         if (locShadowOffset && (locShadowOffset.x !== shadowOffsetX) || (locShadowOffset._y !== shadowOffsetY)) {
310             locShadowOffset.x = shadowOffsetX;
311             locShadowOffset.y = shadowOffsetY;
312         }
313 
314         if (this._shadowOpacity !== shadowOpacity) {
315             this._shadowOpacity = shadowOpacity;
316         }
317         this._renderCmd._setColorsString();
318 
319         if (this._shadowBlur !== shadowBlur)
320             this._shadowBlur = shadowBlur;
321         this._setUpdateTextureDirty();
322     },
323 
324     _enableShadow: function (shadowColor, offset, blurRadius) {
325         if (!this._shadowColor) {
326             this._shadowColor = cc.color(255, 255, 255, 128);
327         }
328         this._shadowColor.r = shadowColor.r;
329         this._shadowColor.g = shadowColor.g;
330         this._shadowColor.b = shadowColor.b;
331 
332         var x, y, a, b;
333         x = offset.width || offset.x || 0;
334         y = offset.height || offset.y || 0;
335         a = (shadowColor.a != null) ? (shadowColor.a / 255) : 0.5;
336         b = blurRadius;
337 
338         this._enableShadowNoneColor(x, y, a, b);
339     },
340 
341     _getShadowOffsetX: function () {
342         return this._shadowOffset.x;
343     },
344     _setShadowOffsetX: function (x) {
345         if (false === this._shadowEnabled)
346             this._shadowEnabled = true;
347 
348         if (this._shadowOffset.x !== x) {
349             this._shadowOffset.x = x;
350             this._setUpdateTextureDirty();
351         }
352     },
353 
354     _getShadowOffsetY: function () {
355         return this._shadowOffset._y;
356     },
357     _setShadowOffsetY: function (y) {
358         if (false === this._shadowEnabled)
359             this._shadowEnabled = true;
360 
361         if (this._shadowOffset._y !== y) {
362             this._shadowOffset._y = y;
363             this._setUpdateTextureDirty();
364         }
365     },
366 
367     _getShadowOffset: function () {
368         return cc.p(this._shadowOffset.x, this._shadowOffset.y);
369     },
370     _setShadowOffset: function (offset) {
371         if (false === this._shadowEnabled)
372             this._shadowEnabled = true;
373 
374         if (this._shadowOffset.x !== offset.x || this._shadowOffset.y !== offset.y) {
375             this._shadowOffset.x = offset.x;
376             this._shadowOffset.y = offset.y;
377             this._setUpdateTextureDirty();
378         }
379     },
380 
381     _getShadowOpacity: function () {
382         return this._shadowOpacity;
383     },
384     _setShadowOpacity: function (shadowOpacity) {
385         if (false === this._shadowEnabled)
386             this._shadowEnabled = true;
387 
388         if (this._shadowOpacity !== shadowOpacity) {
389             this._shadowOpacity = shadowOpacity;
390             this._renderCmd._setColorsString();
391             this._setUpdateTextureDirty();
392         }
393     },
394 
395     _getShadowBlur: function () {
396         return this._shadowBlur;
397     },
398     _setShadowBlur: function (shadowBlur) {
399         if (false === this._shadowEnabled)
400             this._shadowEnabled = true;
401 
402         if (this._shadowBlur !== shadowBlur) {
403             this._shadowBlur = shadowBlur;
404             this._setUpdateTextureDirty();
405         }
406     },
407 
408     /**
409      * Disable shadow rendering
410      */
411     disableShadow: function () {
412         if (this._shadowEnabled) {
413             this._shadowEnabled = false;
414             this._setUpdateTextureDirty();
415         }
416     },
417 
418     /**
419      * Enable label stroke with stroke parameters
420      * @param {cc.Color} strokeColor The color of stroke
421      * @param {Number} strokeSize The size of stroke
422      */
423     enableStroke: function (strokeColor, strokeSize) {
424         if (this._strokeEnabled === false)
425             this._strokeEnabled = true;
426 
427         var locStrokeColor = this._strokeColor;
428         if ((locStrokeColor.r !== strokeColor.r) || (locStrokeColor.g !== strokeColor.g) || (locStrokeColor.b !== strokeColor.b)) {
429             locStrokeColor.r = strokeColor.r;
430             locStrokeColor.g = strokeColor.g;
431             locStrokeColor.b = strokeColor.b;
432             this._renderCmd._setColorsString();
433         }
434 
435         if (this._strokeSize !== strokeSize)
436             this._strokeSize = strokeSize || 0;
437         this._setUpdateTextureDirty();
438     },
439 
440     _getStrokeStyle: function () {
441         return this._strokeColor;
442     },
443     _setStrokeStyle: function (strokeStyle) {
444         if (this._strokeEnabled === false)
445             this._strokeEnabled = true;
446 
447         var locStrokeColor = this._strokeColor;
448         if ((locStrokeColor.r !== strokeStyle.r) || (locStrokeColor.g !== strokeStyle.g) || (locStrokeColor.b !== strokeStyle.b)) {
449             locStrokeColor.r = strokeStyle.r;
450             locStrokeColor.g = strokeStyle.g;
451             locStrokeColor.b = strokeStyle.b;
452             this._renderCmd._setColorsString();
453             this._setUpdateTextureDirty();
454         }
455     },
456 
457     _getLineWidth: function () {
458         return this._strokeSize;
459     },
460     _setLineWidth: function (lineWidth) {
461         if (this._strokeEnabled === false)
462             this._strokeEnabled = true;
463         if (this._strokeSize !== lineWidth) {
464             this._strokeSize = lineWidth || 0;
465             this._setUpdateTextureDirty();
466         }
467     },
468 
469     /**
470      * Disable label stroke
471      */
472     disableStroke: function () {
473         if (this._strokeEnabled) {
474             this._strokeEnabled = false;
475             this._setUpdateTextureDirty();
476         }
477     },
478 
479     /**
480      * Sets the text fill color
481      * @function
482      * @param {cc.Color} fillColor The fill color of the label
483      */
484     setFontFillColor: function (fillColor) {
485         var locTextFillColor = this._textFillColor;
486         if (locTextFillColor.r !== fillColor.r || locTextFillColor.g !== fillColor.g || locTextFillColor.b !== fillColor.b) {
487             locTextFillColor.r = fillColor.r;
488             locTextFillColor.g = fillColor.g;
489             locTextFillColor.b = fillColor.b;
490             this._renderCmd._setColorsString();
491             this._needUpdateTexture = true;
492         }
493     },
494 
495     _getFillStyle: function () {
496         return this._textFillColor;
497     },
498 
499     //set the text definition for this label
500     _updateWithTextDefinition: function (textDefinition, mustUpdateTexture) {
501         if (textDefinition.fontDimensions) {
502             this._dimensions.width = textDefinition.boundingWidth;
503             this._dimensions.height = textDefinition.boundingHeight;
504         } else {
505             this._dimensions.width = 0;
506             this._dimensions.height = 0;
507         }
508 
509         this._hAlignment = textDefinition.textAlign;
510         this._vAlignment = textDefinition.verticalAlign;
511 
512         this._fontName = textDefinition.fontName;
513         this._fontSize = textDefinition.fontSize || 12;
514 
515         if(textDefinition.lineHeight)
516             this._lineHeight = textDefinition.lineHeight
517         else
518             this._lineHeight = this._fontSize;
519 
520         this._renderCmd._setFontStyle(textDefinition);
521 
522 
523         // shadow
524         if (textDefinition.shadowEnabled)
525             this.enableShadow(textDefinition.shadowOffsetX,
526                 textDefinition.shadowOffsetY,
527                 textDefinition.shadowOpacity,
528                 textDefinition.shadowBlur);
529 
530         // stroke
531         if (textDefinition.strokeEnabled)
532             this.enableStroke(textDefinition.strokeStyle, textDefinition.lineWidth);
533 
534         // fill color
535         this.setFontFillColor(textDefinition.fillStyle);
536 
537         if (mustUpdateTexture)
538             this._renderCmd._updateTexture();
539         var flags = cc.Node._dirtyFlags;
540         this._renderCmd.setDirtyFlag(flags.colorDirty|flags.opacityDirty|flags.textDirty);
541     },
542 
543     _prepareTextDefinition: function (adjustForResolution) {
544         var texDef = new cc.FontDefinition();
545 
546         if (adjustForResolution) {
547             texDef.fontSize = this._fontSize;
548             texDef.boundingWidth = cc.contentScaleFactor() * this._dimensions.width;
549             texDef.boundingHeight = cc.contentScaleFactor() * this._dimensions.height;
550         } else {
551             texDef.fontSize = this._fontSize;
552             texDef.boundingWidth = this._dimensions.width;
553             texDef.boundingHeight = this._dimensions.height;
554         }
555 
556         texDef.fontName = this._fontName;
557         texDef.textAlign = this._hAlignment;
558         texDef.verticalAlign = this._vAlignment;
559 
560         // stroke
561         if (this._strokeEnabled) {
562             texDef.strokeEnabled = true;
563             var locStrokeColor = this._strokeColor;
564             texDef.strokeStyle = cc.color(locStrokeColor.r, locStrokeColor.g, locStrokeColor.b);
565             texDef.lineWidth = this._strokeSize;
566         } else
567             texDef.strokeEnabled = false;
568 
569         // shadow
570         if (this._shadowEnabled) {
571             texDef.shadowEnabled = true;
572             texDef.shadowBlur = this._shadowBlur;
573             texDef.shadowOpacity = this._shadowOpacity;
574 
575             texDef.shadowOffsetX = (adjustForResolution ? cc.contentScaleFactor() : 1) * this._shadowOffset.x;
576             texDef.shadowOffsetY = (adjustForResolution ? cc.contentScaleFactor() : 1) * this._shadowOffset.y;
577         } else
578             texDef._shadowEnabled = false;
579 
580         // text tint
581         var locTextFillColor = this._textFillColor;
582         texDef.fillStyle = cc.color(locTextFillColor.r, locTextFillColor.g, locTextFillColor.b);
583         return texDef;
584     },
585 
586     /*
587      * BEGIN SCALE METHODS
588      *
589      * In order to make the value of scaleX and scaleY consistent across
590      * screens, we provide patched versions that return the same values as if
591      * the screen was not HiDPI.
592      */
593 
594     /**
595      * Returns the scale factor of the node.
596      * @warning: Assertion will fail when _scaleX != _scaleY.
597      * @function
598      * @return {Number} The scale factor
599      */
600     getScale: function () {
601         if (this._scaleX !== this._scaleY)
602             cc.log(cc._LogInfos.Node_getScale);
603         return this._scaleX * cc.view.getDevicePixelRatio();
604     },
605 
606     /**
607      * Sets the scale factor of the node. 1.0 is the default scale factor. This function can modify the X and Y scale at the same time.
608      * @function
609      * @param {Number} scale or scaleX value
610      * @param {Number} [scaleY=]
611      */
612     setScale: function (scale, scaleY) {
613         this._scaleX = scale / cc.view.getDevicePixelRatio();
614         this._scaleY = ((scaleY || scaleY === 0) ? scaleY : scale) /
615             cc.view.getDevicePixelRatio();
616         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
617     },
618 
619     /**
620      * Returns the scale factor on X axis of this node
621      * @function
622      * @return {Number} The scale factor on X axis.
623      */
624     getScaleX: function () {
625         return this._scaleX * cc.view.getDevicePixelRatio();
626     },
627 
628     /**
629      * <p>
630      *     Changes the scale factor on X axis of this node                                   <br/>
631      *     The default value is 1.0 if you haven't changed it before
632      * </p>
633      * @function
634      * @param {Number} newScaleX The scale factor on X axis.
635      */
636     setScaleX: function (newScaleX) {
637         this._scaleX = newScaleX / cc.view.getDevicePixelRatio();
638         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
639     },
640 
641     /**
642      * Returns the scale factor on Y axis of this node
643      * @function
644      * @return {Number} The scale factor on Y axis.
645      */
646     getScaleY: function () {
647         return this._scaleY * cc.view.getDevicePixelRatio();
648     },
649 
650     /**
651      * <p>
652      *     Changes the scale factor on Y axis of this node                                            <br/>
653      *     The Default value is 1.0 if you haven't changed it before.
654      * </p>
655      * @function
656      * @param {Number} newScaleY The scale factor on Y axis.
657      */
658     setScaleY: function (newScaleY) {
659         this._scaleY = newScaleY / cc.view.getDevicePixelRatio();
660         this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
661     },
662 
663     /*
664      * END SCALE METHODS
665      */
666 
667     /**
668      * Changes the text content of the label
669      * @warning Changing the string is as expensive as creating a new cc.LabelTTF. To obtain better performance use cc.LabelAtlas
670      * @param {String} text Text content for the label
671      */
672     setString: function (text) {
673         text = String(text);
674         if (this._originalText !== text) {
675             this._originalText = text + "";
676 
677             this._updateString();
678 
679             // Force update
680             this._setUpdateTextureDirty();
681             this._renderCmd.setDirtyFlag(cc.Node._dirtyFlags.transformDirty);
682         }
683     },
684     _updateString: function () {
685         if ((!this._string || this._string === "") && this._string !== this._originalText)
686             cc.renderer.childrenOrderDirty = true;
687         this._string = this._originalText;
688     },
689 
690     /**
691      * Sets Horizontal Alignment of cc.LabelTTF
692      * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment Horizontal Alignment
693      */
694     setHorizontalAlignment: function (alignment) {
695         if (alignment !== this._hAlignment) {
696             this._hAlignment = alignment;
697             // Force update
698             this._setUpdateTextureDirty();
699         }
700     },
701 
702     /**
703      * Sets Vertical Alignment of cc.LabelTTF
704      * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} verticalAlignment
705      */
706     setVerticalAlignment: function (verticalAlignment) {
707         if (verticalAlignment !== this._vAlignment) {
708             this._vAlignment = verticalAlignment;
709 
710             // Force update
711             this._setUpdateTextureDirty();
712         }
713     },
714 
715     /**
716      * Set Dimensions of cc.LabelTTF, the dimension is the maximum size of the label, set it so that label will automatically change lines when necessary.
717      * @param {cc.Size|Number} dim dimensions or width of dimensions
718      * @param {Number} [height] height of dimensions
719      */
720     setDimensions: function (dim, height) {
721         var width;
722         if (height === undefined) {
723             width = dim.width;
724             height = dim.height;
725         } else
726             width = dim;
727 
728         if (width !== this._dimensions.width || height !== this._dimensions.height) {
729             this._dimensions.width = width;
730             this._dimensions.height = height;
731             this._updateString();
732             // Force update
733             this._setUpdateTextureDirty();
734         }
735     },
736 
737     _getBoundingWidth: function () {
738         return this._dimensions.width;
739     },
740     _setBoundingWidth: function (width) {
741         if (width !== this._dimensions.width) {
742             this._dimensions.width = width;
743             this._updateString();
744             // Force update
745             this._setUpdateTextureDirty();
746         }
747     },
748 
749     _getBoundingHeight: function () {
750         return this._dimensions.height;
751     },
752     _setBoundingHeight: function (height) {
753         if (height !== this._dimensions.height) {
754             this._dimensions.height = height;
755             this._updateString();
756             // Force update
757             this._setUpdateTextureDirty();
758         }
759     },
760 
761     /**
762      * Sets font size of cc.LabelTTF
763      * @param {Number} fontSize
764      */
765     setFontSize: function (fontSize) {
766         if (this._fontSize !== fontSize) {
767             this._fontSize = fontSize;
768             this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight);
769             // Force update
770             this._setUpdateTextureDirty();
771         }
772     },
773 
774     /**
775      * Sets font name of cc.LabelTTF
776      * @param {String} fontName
777      */
778     setFontName: function (fontName) {
779         if (this._fontName && this._fontName !== fontName) {
780             this._fontName = fontName;
781             this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight);
782             // Force update
783             this._setUpdateTextureDirty();
784         }
785     },
786 
787     _getFont: function () {
788         return this._renderCmd._getFontStyle();
789     },
790     _setFont: function (fontStyle) {
791         var res = cc.LabelTTF._fontStyleRE.exec(fontStyle);
792         if (res) {
793             this._fontSize = parseInt(res[1]);
794             this._fontName = res[2];
795             this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight);
796 
797             // Force update
798             this._setUpdateTextureDirty();
799         }
800     },
801 
802     /**
803      * Returns the actual content size of the label, the content size is the real size that the label occupied while dimension is the outer bounding box of the label.
804      * @returns {cc.Size} The content size
805      */
806     getContentSize: function () {
807         if (this._needUpdateTexture)
808             this._renderCmd._updateTTF();
809         return cc.size(this._contentSize);
810     },
811 
812     _getWidth: function () {
813         if (this._needUpdateTexture)
814             this._renderCmd._updateTTF();
815         return this._contentSize.width;
816     },
817     _getHeight: function () {
818         if (this._needUpdateTexture)
819             this._renderCmd._updateTTF();
820         return this._contentSize.height;
821     },
822 
823     setTextureRect: function (rect, rotated, untrimmedSize) {
824         //set needConvert to false
825         cc.Sprite.prototype.setTextureRect.call(this, rect, rotated, untrimmedSize, false);
826     },
827 
828     /**
829      * set Target to draw on
830      * @param boolean onCanvas
831      */
832     setDrawMode: function (onCacheMode) {
833         this._onCacheCanvasMode = onCacheMode;
834     },
835 
836     _createRenderCmd: function () {
837         if (cc._renderType === cc.game.RENDER_TYPE_WEBGL)
838             return new cc.LabelTTF.WebGLRenderCmd(this);
839         else if (this._onCacheCanvasMode)
840             return new cc.LabelTTF.CacheCanvasRenderCmd(this);
841         else
842             return new cc.LabelTTF.CanvasRenderCmd(this);
843     },
844 
845     //For web only
846     _setFontStyle: function(fontStyle){
847         if (this._fontStyle !== fontStyle) {
848             this._fontStyle = fontStyle;
849             this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight);
850             this._setUpdateTextureDirty();
851         }
852     },
853 
854     _getFontStyle: function(){
855         return this._fontStyle;
856     },
857 
858     _setFontWeight: function(fontWeight){
859         if (this._fontWeight !== fontWeight) {
860             this._fontWeight = fontWeight;
861             this._renderCmd._setFontStyle(this._fontName, this._fontSize, this._fontStyle, this._fontWeight);
862             this._setUpdateTextureDirty();
863         }
864     },
865 
866     _getFontWeight: function(){
867         return this._fontWeight;
868     }
869 });
870 
871 cc.assert(cc.isFunction(cc._tmp.PrototypeLabelTTF), cc._LogInfos.MissingFile, "LabelTTFPropertyDefine.js");
872 cc._tmp.PrototypeLabelTTF();
873 delete cc._tmp.PrototypeLabelTTF;
874 
875 // Only support style in this format: "18px Verdana" or "18px 'Helvetica Neue'"
876 cc.LabelTTF._fontStyleRE = /^(\d+)px\s+['"]?([\w\s\d]+)['"]?$/;
877 
878 /**
879  * creates a cc.LabelTTF from a font name, alignment, dimension and font size
880  * @deprecated since v3.0, please use the new construction instead
881  * @see cc.LabelTTF
882  * @static
883  * @param {String} text
884  * @param {String|cc.FontDefinition} [fontName="Arial"]
885  * @param {Number} [fontSize=16]
886  * @param {cc.Size} [dimensions=cc.size(0,0)]
887  * @param {Number} [hAlignment=cc.TEXT_ALIGNMENT_LEFT]
888  * @param {Number} [vAlignment=cc.VERTICAL_TEXT_ALIGNMENT_TOP]
889  * @return {cc.LabelTTF|Null}
890  */
891 cc.LabelTTF.create = function (text, fontName, fontSize, dimensions, hAlignment, vAlignment) {
892     return new cc.LabelTTF(text, fontName, fontSize, dimensions, hAlignment, vAlignment);
893 };
894 
895 /**
896  * @deprecated since v3.0, please use the new construction instead
897  * @function
898  * @static
899  */
900 cc.LabelTTF.createWithFontDefinition = cc.LabelTTF.create;
901 
902 cc.LabelTTF.__labelHeightDiv = document.createElement("div");
903 cc.LabelTTF.__labelHeightDiv.style.fontFamily = "Arial";
904 cc.LabelTTF.__labelHeightDiv.style.position = "absolute";
905 cc.LabelTTF.__labelHeightDiv.style.left = "-100px";
906 cc.LabelTTF.__labelHeightDiv.style.top = "-100px";
907 cc.LabelTTF.__labelHeightDiv.style.lineHeight = "normal";
908 
909 document.body ?
910     document.body.appendChild(cc.LabelTTF.__labelHeightDiv) :
911     window.addEventListener('load', function () {
912         this.removeEventListener('load', arguments.callee, false);
913         document.body.appendChild(cc.LabelTTF.__labelHeightDiv);
914     }, false);
915 
916 /**
917  * Returns the height of text with an specified font family and font size, in
918  * device independent pixels.
919  *
920  * @param {string|cc.FontDefinition} fontName
921  * @param {number} fontSize
922  * @returns {number}
923  * @private
924  */
925 cc.LabelTTF.__getFontHeightByDiv = function (fontName, fontSize) {
926     var clientHeight, labelDiv = cc.LabelTTF.__labelHeightDiv;
927     if(fontName instanceof cc.FontDefinition){
928         /** @type cc.FontDefinition */
929         var fontDef = fontName;
930         clientHeight = cc.LabelTTF.__fontHeightCache[fontDef._getCanvasFontStr()];
931         if (clientHeight > 0) return clientHeight;
932         labelDiv.innerHTML = "ajghl~!";
933         labelDiv.style.fontFamily = fontDef.fontName;
934         labelDiv.style.fontSize = fontDef.fontSize + "px";
935         labelDiv.style.fontStyle = fontDef.fontStyle;
936         labelDiv.style.fontWeight = fontDef.fontWeight;
937 
938         clientHeight = labelDiv.clientHeight;
939         cc.LabelTTF.__fontHeightCache[fontDef._getCanvasFontStr()] = clientHeight;
940         labelDiv.innerHTML = "";
941     }
942     else {
943         //Default
944         clientHeight = cc.LabelTTF.__fontHeightCache[fontName + "." + fontSize];
945         if (clientHeight > 0) return clientHeight;
946         labelDiv.innerHTML = "ajghl~!";
947         labelDiv.style.fontFamily = fontName;
948         labelDiv.style.fontSize = fontSize + "px";
949         clientHeight = labelDiv.clientHeight;
950         cc.LabelTTF.__fontHeightCache[fontName + "." + fontSize] = clientHeight;
951         labelDiv.innerHTML = "";
952     }
953     return clientHeight;
954 
955 };
956 
957 cc.LabelTTF.__fontHeightCache = {};
958