From 325e4703d45051307a50d39ff5e194e2083337dc Mon Sep 17 00:00:00 2001 From: Josh Tynjala Date: Fri, 14 Apr 2017 09:43:45 -0700 Subject: [PATCH] Text Renderers/Editors: if they make a texture snapshot, it only happens in render() to avoid multiple texture uploads in the same frame (which should slightly improve performance when text is changing frequently, such as scrolling a list) --- .../controls/text/StageTextTextEditor.as | 47 ++++++++--- .../controls/text/TextBlockTextRenderer.as | 40 ++++----- .../controls/text/TextFieldTextEditor.as | 57 +++++++------ .../controls/text/TextFieldTextRenderer.as | 81 ++++++++++--------- 4 files changed, 130 insertions(+), 95 deletions(-) diff --git a/source/feathers/controls/text/StageTextTextEditor.as b/source/feathers/controls/text/StageTextTextEditor.as index 3839c0b8ab..b2b84a9579 100644 --- a/source/feathers/controls/text/StageTextTextEditor.as +++ b/source/feathers/controls/text/StageTextTextEditor.as @@ -316,6 +316,11 @@ package feathers.controls.text */ protected var _needsNewTexture:Boolean = false; + /** + * @private + */ + protected var _needsTextureUpdate:Boolean = false; + /** * @private */ @@ -1225,7 +1230,7 @@ package feathers.controls.text { painter.excludeFromCache(this); } - if(this.textSnapshot && this._updateSnapshotOnScaleChange) + if(this.textSnapshot !== null && this._updateSnapshotOnScaleChange) { var matrix:Matrix = Pool.getMatrix(); this.getTransformationMatrix(this.stage, matrix); @@ -1239,10 +1244,32 @@ package feathers.controls.text } Pool.putMatrix(matrix); } + if(this._needsTextureUpdate) + { + this._needsTextureUpdate = false; + var hasText:Boolean = this._text.length > 0; + if(hasText) + { + this.refreshSnapshot(); + } + if(this.textSnapshot) + { + this.textSnapshot.visible = !this._stageTextHasFocus; + this.textSnapshot.alpha = hasText ? 1 : 0; + } + if(!this._stageTextHasFocus) + { + //hide the StageText after the snapshot is created + //native controls don't necessarily render at the same time + //as starling, and we don't want to see the text disappear + //for a moment + this.stageText.visible = false; + } + } //we'll skip this if the text field isn't visible to avoid running //that code every frame. - if(this.stageText && this.stageText.visible) + if(this.stageText !== null && this.stageText.visible) { this.refreshViewPortAndFontSize(); } @@ -1612,17 +1639,11 @@ package feathers.controls.text if(!this._stageTextHasFocus && (stateInvalid || stylesInvalid || dataInvalid || sizeInvalid || this._needsNewTexture)) { - var hasText:Boolean = this._text.length > 0; - if(hasText) - { - this.refreshSnapshot(); - } - if(this.textSnapshot) - { - this.textSnapshot.visible = !this._stageTextHasFocus; - this.textSnapshot.alpha = hasText ? 1 : 0; - } - this.stageText.visible = false; + //we're going to update the texture in render() because + //there's a chance that it will be updated more than once per + //frame if we do it here. + this._needsTextureUpdate = true; + this.setRequiresRedraw(); } this.doPendingActions(); diff --git a/source/feathers/controls/text/TextBlockTextRenderer.as b/source/feathers/controls/text/TextBlockTextRenderer.as index e30854ff95..95b02aa14c 100644 --- a/source/feathers/controls/text/TextBlockTextRenderer.as +++ b/source/feathers/controls/text/TextBlockTextRenderer.as @@ -313,7 +313,7 @@ package feathers.controls.text /** * @private */ - protected var _needsUpdateSnapshot:Boolean = false; + protected var _needsTextureUpdate:Boolean = false; /** * @private @@ -1356,9 +1356,25 @@ package feathers.controls.text */ override public function render(painter:Painter):void { - if(this._needsUpdateSnapshot) + var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; + if(this.textSnapshot !== null && this._updateSnapshotOnScaleChange) + { + this.getTransformationMatrix(this.stage, HELPER_MATRIX); + var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX); + var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX); + if(globalScaleX != this._lastGlobalScaleX || + globalScaleY != this._lastGlobalScaleY || + starling.contentScaleFactor != this._lastGlobalContentScaleFactor) + { + //the snapshot needs to be updated because the scale has + //changed since the last snapshot was taken. + this.invalidate(INVALIDATION_FLAG_SIZE); + this.validate(); + } + } + if(this._needsTextureUpdate) { - this._needsUpdateSnapshot = false; + this._needsTextureUpdate = false; if(this._content !== null) { this.refreshSnapshot(); @@ -1366,22 +1382,6 @@ package feathers.controls.text } if(this.textSnapshot !== null) { - var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; - if(this._updateSnapshotOnScaleChange) - { - this.getTransformationMatrix(this.stage, HELPER_MATRIX); - var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX); - var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX); - if(globalScaleX != this._lastGlobalScaleX || - globalScaleY != this._lastGlobalScaleY || - starling.contentScaleFactor != this._lastGlobalContentScaleFactor) - { - //the snapshot needs to be updated because the scale has - //changed since the last snapshot was taken. - this.invalidate(INVALIDATION_FLAG_SIZE); - this.validate(); - } - } var scaleFactor:Number = starling.contentScaleFactor; if(!this._nativeFilters || this._nativeFilters.length === 0) { @@ -1729,7 +1729,7 @@ package feathers.controls.text //we're going to update the texture in render() because //there's a chance that it will be updated more than once per //frame if we do it here. - this._needsUpdateSnapshot = true; + this._needsTextureUpdate = true; this.setRequiresRedraw(); } } diff --git a/source/feathers/controls/text/TextFieldTextEditor.as b/source/feathers/controls/text/TextFieldTextEditor.as index 0f6f777d5e..abcac8988f 100644 --- a/source/feathers/controls/text/TextFieldTextEditor.as +++ b/source/feathers/controls/text/TextFieldTextEditor.as @@ -332,6 +332,11 @@ package feathers.controls.text */ protected var _lastGlobalScaleY:Number = 0; + /** + * @private + */ + protected var _needsTextureUpdate:Boolean = false; + /** * @private */ @@ -1403,21 +1408,32 @@ package feathers.controls.text */ override public function render(painter:Painter):void { - if(this.textSnapshot) + if(this.textSnapshot !== null && this._updateSnapshotOnScaleChange) { - if(this._updateSnapshotOnScaleChange) + var matrix:Matrix = Pool.getMatrix(); + this.getTransformationMatrix(this.stage, matrix); + if(matrixToScaleX(matrix) !== this._lastGlobalScaleX || + matrixToScaleY(matrix) !== this._lastGlobalScaleY) { - var matrix:Matrix = Pool.getMatrix(); - this.getTransformationMatrix(this.stage, matrix); - if(matrixToScaleX(matrix) !== this._lastGlobalScaleX || - matrixToScaleY(matrix) !== this._lastGlobalScaleY) - { - //the snapshot needs to be updated because the scale has - //changed since the last snapshot was taken. - this.invalidate(INVALIDATION_FLAG_SIZE); - this.validate(); - } - Pool.putMatrix(matrix); + //the snapshot needs to be updated because the scale has + //changed since the last snapshot was taken. + this.invalidate(INVALIDATION_FLAG_SIZE); + this.validate(); + } + Pool.putMatrix(matrix); + } + if(this._needsTextureUpdate) + { + this._needsTextureUpdate = false; + if(this._useSnapshotDelayWorkaround) + { + //sometimes, we need to wait a frame for flash.text.TextField + //to render properly when drawing to BitmapData. + this.addEventListener(Event.ENTER_FRAME, refreshSnapshot_enterFrameHandler); + } + else + { + this.refreshSnapshot(); } this.positionSnapshot(); } @@ -2078,16 +2094,11 @@ package feathers.controls.text if(!this._textFieldHasFocus && (sizeInvalid || stylesInvalid || dataInvalid || stateInvalid || this._needsNewTexture)) { - if(this._useSnapshotDelayWorkaround) - { - //sometimes, we need to wait a frame for flash.text.TextField - //to render properly when drawing to BitmapData. - this.addEventListener(Event.ENTER_FRAME, refreshSnapshot_enterFrameHandler); - } - else - { - this.refreshSnapshot(); - } + //we're going to update the texture in render() because + //there's a chance that it will be updated more than once per + //frame if we do it here. + this._needsTextureUpdate = true; + this.setRequiresRedraw(); } this.doPendingActions(); } diff --git a/source/feathers/controls/text/TextFieldTextRenderer.as b/source/feathers/controls/text/TextFieldTextRenderer.as index 9245898bf3..93189827a2 100644 --- a/source/feathers/controls/text/TextFieldTextRenderer.as +++ b/source/feathers/controls/text/TextFieldTextRenderer.as @@ -170,6 +170,11 @@ package feathers.controls.text */ protected var _snapshotVisibleHeight:int = 0; + /** + * @private + */ + protected var _needsTextureUpdate:Boolean = false; + /** * @private */ @@ -1229,24 +1234,41 @@ package feathers.controls.text */ override public function render(painter:Painter):void { - if(this.textSnapshot !== null) + var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; + if(this.textSnapshot !== null && this._updateSnapshotOnScaleChange) { - var starling:Starling = this.stage !== null ? this.stage.starling : Starling.current; - if(this._updateSnapshotOnScaleChange) + this.getTransformationMatrix(this.stage, HELPER_MATRIX); + var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX); + var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX); + if(globalScaleX != this._lastGlobalScaleX || + globalScaleY != this._lastGlobalScaleY || + starling.contentScaleFactor != this._lastContentScaleFactor) { - this.getTransformationMatrix(this.stage, HELPER_MATRIX); - var globalScaleX:Number = matrixToScaleX(HELPER_MATRIX); - var globalScaleY:Number = matrixToScaleY(HELPER_MATRIX); - if(globalScaleX != this._lastGlobalScaleX || - globalScaleY != this._lastGlobalScaleY || - starling.contentScaleFactor != this._lastContentScaleFactor) + //the snapshot needs to be updated because the scale has + //changed since the last snapshot was taken. + this.invalidate(INVALIDATION_FLAG_SIZE); + this.validate(); + } + } + if(this._needsTextureUpdate) + { + this._needsTextureUpdate = false; + if(this._text.length > 0) + { + if(this._useSnapshotDelayWorkaround) { - //the snapshot needs to be updated because the scale has - //changed since the last snapshot was taken. - this.invalidate(INVALIDATION_FLAG_SIZE); - this.validate(); + //we need to wait a frame for the TextField to render + //properly. sometimes two, and this is a known issue. + this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); + } + else + { + this.refreshSnapshot(); } } + } + if(this.textSnapshot !== null) + { var scaleFactor:Number = starling.contentScaleFactor; if(!this._nativeFilters || this._nativeFilters.length === 0) { @@ -1282,11 +1304,13 @@ package feathers.controls.text if(snapshotIndex < 0) { var snapshot:Image = this.textSnapshot; + snapshot.visible = this._text.length > 0 && this._snapshotWidth > 0 && this._snapshotHeight > 0; } else { snapshot = this.textSnapshots[snapshotIndex]; } + snapshot.pixelSnapping = this._pixelSnapping; snapshot.x = xPosition / scaleFactor; snapshot.y = yPosition / scaleFactor; snapshotIndex++; @@ -1629,32 +1653,11 @@ package feathers.controls.text { this._previousActualWidth = this.actualWidth; this._previousActualHeight = this.actualHeight; - var hasText:Boolean = this._text.length > 0; - if(hasText) - { - if(this._useSnapshotDelayWorkaround) - { - //we need to wait a frame for the TextField to render - //properly. sometimes two, and this is a known issue. - this.addEventListener(Event.ENTER_FRAME, enterFrameHandler); - } - else - { - this.refreshSnapshot(); - } - } - if(this.textSnapshot) - { - this.textSnapshot.visible = hasText && this._snapshotWidth > 0 && this._snapshotHeight > 0; - this.textSnapshot.pixelSnapping = this._pixelSnapping; - } - if(this.textSnapshots) - { - for each(var snapshot:Image in this.textSnapshots) - { - snapshot.pixelSnapping = this._pixelSnapping; - } - } + //we're going to update the texture in render() because + //there's a chance that it will be updated more than once per + //frame if we do it here. + this._needsTextureUpdate = true; + this.setRequiresRedraw(); } }