neft
Version:
Universal Platform
203 lines (159 loc) • 5.24 kB
text/coffeescript
'use strict'
utils = require 'src/utils'
implUtils = require '../utils'
log = require 'src/log'
signal = require 'src/signal'
log = log.scope 'Renderer', 'CSS Implementation'
{now} = Date
isTouch = 'ontouchstart' of window
SIGNALS_CURSORS =
pointer:
onClick: 'pointer'
module.exports = (impl) ->
LAYER_MIN_OPERATIONS = 8
LAYER_GC_DELAY = 1000
USE_GPU = impl.utils.transform3dSupported
layers = []
{transformProp, rad2deg} = impl.utils
implUtils = impl.utils
if USE_GPU
setInterval ->
i = 0
n = layers.length
while i < n
layer = layers[i]
layer.operations = (layer.operations * 0.5)|0
if layer.operations < LAYER_MIN_OPERATIONS
layer.operations = 0
if i is n-1
layers.pop()
else
layers[i] = layers.pop()
n--
if layer.isLayer
layer.elem.setAttribute 'class', ''
layer.isLayer = false
updateTransforms layer
layer.operations = 0
console.assert layer.isLayer is false
layer.isInLayers = false
else
i++
return
, LAYER_GC_DELAY
{round} = Math
updateTransforms = (data) ->
transform = ''
if USE_GPU
unless data.isInLayers
layers.push data
data.isInLayers = true
if not data.isLayer and data.operations >= LAYER_MIN_OPERATIONS
data.elem.setAttribute 'class', 'layer'
data.isLayer = true
else
data.operations++
# position
if data.isLayer
transform = "translate3d(#{data.x}px, #{data.y}px, 0) "
else
transform = "translate(#{data.x}px, #{data.y}px) "
# rotation
if data.rotation
transform += "rotate(#{rad2deg(data.rotation)}deg) "
# scale
if data.scale isnt 1
transform += "scale(#{data.scale}) "
data.elemStyle[transformProp] = transform
return
NOP = ->
DATA = utils.merge
bindings: null
anchors: null
elem: null
elemStyle: null
linkElem: null
x: 0
y: 0
rotation: 0
scale: 1
mozFontSubpixel: true
isLayer: false
isInLayers: false
operations: 0
, impl.pointer.DATA
DATA: DATA
createData: impl.utils.createDataCloner DATA
create: (data) ->
data.elem ?= document.createElement 'div'
data.elemStyle = data.elem.style
`//<development>`
data.elem.setAttribute 'neft-debug',
`//</development>`
setItemParent: (val) ->
self = @
{elem} =
elem.parentElement?.removeChild elem
if val
val._impl.elem.appendChild elem
return
insertItemBefore: (val) ->
parent = if val then val._parent else
valElem = if val then val._impl.elem else null
oldParent = .elem.parentElement
newParent = parent._impl.elem
newParent.insertBefore .elem, valElem
return
setItemBackground: (val) ->
if (oldElem = ?._impl.elem)?.parentNode is .elem
.elem.removeChild oldElem
if val
implUtils.prependElement .elem, val._impl.elem
return
setItemVisible: (val) ->
.elemStyle.display = if val then 'inline' else 'none'
return
setItemClip: (val) ->
.elemStyle.overflow = if val then 'hidden' else 'visible'
return
setItemWidth: (val) ->
.elemStyle.width = "#{val}px"
return
setItemHeight: (val) ->
.elemStyle.height = "#{val}px"
return
setItemX: (val) ->
.x = round val
updateTransforms
return
setItemY: (val) ->
.y = round val
updateTransforms
return
setItemScale: (val) ->
.scale = val
updateTransforms
return
setItemRotation: (val) ->
.rotation = val
updateTransforms
return
setItemOpacity: (val) ->
.elemStyle.opacity = val
return
setItemLinkUri: (val) ->
unless .linkElem
elem = .linkElem = document.createElement 'a'
elem.setAttribute 'class', 'link'
.elem.appendChild elem
if .linkElem.getAttribute('href') isnt val
.linkElem.setAttribute 'href', val
.linkElem.style.display = if val isnt '' then 'block' else 'none'
return
attachItemSignal: (ns, signalName) ->
if ns is 'pointer'
impl.pointer.attachItemSignal.call @, signalName
# cursor
if cursor = SIGNALS_CURSORS[ns]?[signalName]
._impl.elemStyle.cursor = cursor
return