import { LinearGradientObject } from '../graphic/LinearGradient'; 
 | 
import { RadialGradientObject } from '../graphic/RadialGradient'; 
 | 
import { GradientObject } from '../graphic/Gradient'; 
 | 
import { RectLike } from '../core/BoundingRect'; 
 | 
import Path from '../graphic/Path'; 
 | 
  
 | 
function isSafeNum(num: number) { 
 | 
    // NaN、Infinity、undefined、'xx' 
 | 
    return isFinite(num); 
 | 
} 
 | 
  
 | 
export function createLinearGradient( 
 | 
    this: void, 
 | 
    ctx: CanvasRenderingContext2D, 
 | 
    obj: LinearGradientObject, 
 | 
    rect: RectLike 
 | 
) { 
 | 
    let x = obj.x == null ? 0 : obj.x; 
 | 
    let x2 = obj.x2 == null ? 1 : obj.x2; 
 | 
    let y = obj.y == null ? 0 : obj.y; 
 | 
    let y2 = obj.y2 == null ? 0 : obj.y2; 
 | 
  
 | 
    if (!obj.global) { 
 | 
        x = x * rect.width + rect.x; 
 | 
        x2 = x2 * rect.width + rect.x; 
 | 
        y = y * rect.height + rect.y; 
 | 
        y2 = y2 * rect.height + rect.y; 
 | 
    } 
 | 
  
 | 
    // Fix NaN when rect is Infinity 
 | 
    x = isSafeNum(x) ? x : 0; 
 | 
    x2 = isSafeNum(x2) ? x2 : 1; 
 | 
    y = isSafeNum(y) ? y : 0; 
 | 
    y2 = isSafeNum(y2) ? y2 : 0; 
 | 
  
 | 
    const canvasGradient = ctx.createLinearGradient(x, y, x2, y2); 
 | 
  
 | 
    return canvasGradient; 
 | 
} 
 | 
  
 | 
export function createRadialGradient( 
 | 
    this: void, 
 | 
    ctx: CanvasRenderingContext2D, 
 | 
    obj: RadialGradientObject, 
 | 
    rect: RectLike 
 | 
) { 
 | 
    const width = rect.width; 
 | 
    const height = rect.height; 
 | 
    const min = Math.min(width, height); 
 | 
  
 | 
    let x = obj.x == null ? 0.5 : obj.x; 
 | 
    let y = obj.y == null ? 0.5 : obj.y; 
 | 
    let r = obj.r == null ? 0.5 : obj.r; 
 | 
  
 | 
    if (!obj.global) { 
 | 
        x = x * width + rect.x; 
 | 
        y = y * height + rect.y; 
 | 
        r = r * min; 
 | 
    } 
 | 
  
 | 
    x = isSafeNum(x) ? x : 0.5; 
 | 
    y = isSafeNum(y) ? y : 0.5; 
 | 
    r = r >= 0 && isSafeNum(r) ? r : 0.5; 
 | 
  
 | 
    const canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r); 
 | 
  
 | 
    return canvasGradient; 
 | 
} 
 | 
  
 | 
export function getCanvasGradient(this: void, ctx: CanvasRenderingContext2D, obj: GradientObject, rect: RectLike) { 
 | 
    // TODO Cache? 
 | 
    const canvasGradient = obj.type === 'radial' 
 | 
        ? createRadialGradient(ctx, obj as RadialGradientObject, rect) 
 | 
        : createLinearGradient(ctx, obj as LinearGradientObject, rect); 
 | 
  
 | 
    const colorStops = obj.colorStops; 
 | 
    for (let i = 0; i < colorStops.length; i++) { 
 | 
        canvasGradient.addColorStop( 
 | 
            colorStops[i].offset, colorStops[i].color 
 | 
        ); 
 | 
    } 
 | 
    return canvasGradient; 
 | 
} 
 | 
  
 | 
export function isClipPathChanged(clipPaths: Path[], prevClipPaths: Path[]): boolean { 
 | 
    // displayable.__clipPaths can only be `null`/`undefined` or an non-empty array. 
 | 
    if (clipPaths === prevClipPaths || (!clipPaths && !prevClipPaths)) { 
 | 
        return false; 
 | 
    } 
 | 
    if (!clipPaths || !prevClipPaths || (clipPaths.length !== prevClipPaths.length)) { 
 | 
        return true; 
 | 
    } 
 | 
    for (let i = 0; i < clipPaths.length; i++) { 
 | 
        if (clipPaths[i] !== prevClipPaths[i]) { 
 | 
            return true; 
 | 
        } 
 | 
    } 
 | 
    return false; 
 | 
} 
 | 
  
 | 
function parseInt10(val: string) { 
 | 
    return parseInt(val, 10); 
 | 
} 
 | 
export function getSize( 
 | 
    root: HTMLElement, 
 | 
    whIdx: number, 
 | 
    opts: { width?: number | string, height?: number | string} 
 | 
) { 
 | 
  
 | 
    const wh = ['width', 'height'][whIdx] as 'width' | 'height'; 
 | 
    const cwh = ['clientWidth', 'clientHeight'][whIdx] as 'clientWidth' | 'clientHeight'; 
 | 
    const plt = ['paddingLeft', 'paddingTop'][whIdx] as 'paddingLeft' | 'paddingTop'; 
 | 
    const prb = ['paddingRight', 'paddingBottom'][whIdx] as 'paddingRight' | 'paddingBottom'; 
 | 
  
 | 
    if (opts[wh] != null && opts[wh] !== 'auto') { 
 | 
        return parseFloat(opts[wh] as string); 
 | 
    } 
 | 
  
 | 
    // IE8 does not support getComputedStyle, but it use VML. 
 | 
    const stl = document.defaultView.getComputedStyle(root); 
 | 
  
 | 
    return ( 
 | 
        (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) 
 | 
        - (parseInt10(stl[plt]) || 0) 
 | 
        - (parseInt10(stl[prb]) || 0) 
 | 
    ) | 0; 
 | 
} 
 |