| /* |
| * Copyright (C) 2018 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| WI.RecordingState = class RecordingState |
| { |
| constructor(data, {source} = {}) |
| { |
| this._data = data; |
| this._source = source || null; |
| } |
| |
| // Static |
| |
| static fromContext(type, context, options = {}) |
| { |
| if (type !== WI.Recording.Type.Canvas2D) |
| return null; |
| |
| let matrix = context.getTransform(); |
| |
| let data = {}; |
| |
| if (WI.ImageUtilities.supportsCanvasPathDebugging()) { |
| data.currentX = context.currentX; |
| data.currentY = context.currentY; |
| } |
| |
| data.direction = context.direction; |
| data.fillStyle = context.fillStyle; |
| data.font = context.font; |
| data.globalAlpha = context.globalAlpha; |
| data.globalCompositeOperation = context.globalCompositeOperation; |
| data.imageSmoothingEnabled = context.imageSmoothingEnabled; |
| data.imageSmoothingQuality = context.imageSmoothingQuality; |
| data.lineCap = context.lineCap; |
| data.lineDash = context.getLineDash(); |
| data.lineDashOffset = context.lineDashOffset; |
| data.lineJoin = context.lineJoin; |
| data.lineWidth = context.lineWidth; |
| data.miterLimit = context.miterLimit; |
| data.shadowBlur = context.shadowBlur; |
| data.shadowColor = context.shadowColor; |
| data.shadowOffsetX = context.shadowOffsetX; |
| data.shadowOffsetY = context.shadowOffsetY; |
| data.strokeStyle = context.strokeStyle; |
| data.textAlign = context.textAlign; |
| data.textBaseline = context.textBaseline; |
| data.transform = [matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f]; |
| data.webkitImageSmoothingEnabled = context.webkitImageSmoothingEnabled; |
| data.webkitLineDash = context.webkitLineDash; |
| data.webkitLineDashOffset = context.webkitLineDashOffset; |
| |
| if (WI.ImageUtilities.supportsCanvasPathDebugging()) |
| data.setPath = [context.getPath()]; |
| |
| return new WI.RecordingState(data, options); |
| } |
| |
| static async swizzleInitialState(recording, initialState) |
| { |
| if (recording.type === WI.Recording.Type.Canvas2D) { |
| let swizzledState = {}; |
| |
| for (let [name, value] of Object.entries(initialState)) { |
| // COMPATIBILITY (iOS 12.0): Recording.InitialState.states did not exist yet |
| let nameIndex = parseInt(name); |
| if (!isNaN(nameIndex)) |
| name = await recording.swizzle(nameIndex, WI.Recording.Swizzle.String); |
| |
| switch (name) { |
| case "setTransform": |
| value = [await recording.swizzle(value, WI.Recording.Swizzle.DOMMatrix)]; |
| break; |
| |
| case "fillStyle": |
| case "strokeStyle": |
| var [gradient, pattern, string] = await Promise.all([ |
| recording.swizzle(value, WI.Recording.Swizzle.CanvasGradient), |
| recording.swizzle(value, WI.Recording.Swizzle.CanvasPattern), |
| recording.swizzle(value, WI.Recording.Swizzle.String), |
| ]); |
| if (gradient && !pattern) |
| value = gradient; |
| else if (pattern && !gradient) |
| value = pattern; |
| else |
| value = string; |
| break; |
| |
| case "direction": |
| case "font": |
| case "globalCompositeOperation": |
| case "imageSmoothingQuality": |
| case "lineCap": |
| case "lineJoin": |
| case "shadowColor": |
| case "textAlign": |
| case "textBaseline": |
| value = await recording.swizzle(value, WI.Recording.Swizzle.String); |
| break; |
| |
| case "globalAlpha": |
| case "lineWidth": |
| case "miterLimit": |
| case "shadowOffsetX": |
| case "shadowOffsetY": |
| case "shadowBlur": |
| case "lineDashOffset": |
| value = await recording.swizzle(value, WI.Recording.Swizzle.Number); |
| break; |
| |
| case "setPath": |
| value = [await recording.swizzle(value[0], WI.Recording.Swizzle.Path2D)]; |
| break; |
| } |
| |
| if (value === undefined || (Array.isArray(value) && value.includes(undefined))) |
| continue; |
| |
| swizzledState[name] = value; |
| } |
| |
| return new WI.RecordingState(swizzledState); |
| } |
| |
| return null; |
| } |
| |
| // Public |
| |
| get source() { return this._source; } |
| |
| has(name) |
| { |
| return name in this._data; |
| } |
| |
| get(name) |
| { |
| return this._data[name]; |
| } |
| |
| apply(type, context) |
| { |
| for (let [name, value] of this) { |
| if (!(name in context)) |
| continue; |
| |
| // Skip internal state used for path debugging. |
| if (name === "currentX" || name === "currentY") |
| continue; |
| |
| try { |
| if (WI.RecordingAction.isFunctionForType(type, name)) |
| context[name](...value); |
| else |
| context[name] = value; |
| } catch { } |
| } |
| } |
| |
| toJSON() |
| { |
| return this._data; |
| } |
| |
| [Symbol.iterator]() |
| { |
| return Object.entries(this._data)[Symbol.iterator](); |
| } |
| }; |